Pull RTLA tracing tool updates from Steven Rostedt: "Real Time Analysis Tool updatesfor 5.18: - Support for adjusting tracing_threashold - Add -a (auto) option to make it easier for users to debug in the field - Add -e option to add more events to the trace - Add --trigger option to add triggers to events - Add --filter option to filter events - Add support to save histograms to the file - Add --dma-latency to set /dev/cpu_dma_latency - Other fixes and cleanups" * tag 'trace-rtla-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: rtla: Tools main loop cleanup rtla/timerlat: Add --dma-latency option rtla/osnoise: Fix osnoise hist stop tracing message rtla: Check for trace off also in the trace instance rtla/trace: Save event histogram output to a file rtla: Add --filter support rtla/trace: Add trace event filter helpers rtla: Add --trigger support rtla/trace: Add trace event trigger helpers rtla: Add -e/--event support rtla/trace: Add trace events helpers rtla/timerlat: Add the automatic trace option rtla/osnoise: Add the automatic trace option rtla/osnoise: Add an option to set the threshold rtla/osnoise: Add support to adjust the tracing_thresh
Unified · Split
| @@ -14,6 +14,25 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | Save the stopped trace to [*file|osnoise_trace.txt*]. |
| 16 | 16 | |
| 17 | +**-e**, **--event** *sys:event* | |
| 18 | + | |
| 19 | + Enable an event in the trace (**-t**) session. The argument can be a specific event, e.g., **-e** *sched:sched_switch*, or all events of a system group, e.g., **-e** *sched*. Multiple **-e** are allowed. It is only active when **-t** or **-a** are set. | |
| 20 | + | |
| 21 | +**--filter** *<filter>* | |
| 22 | + | |
| 23 | + Filter the previous **-e** *sys:event* event with *<filter>*. For further information about event filtering see https://www.kernel.org/doc/html/latest/trace/events.html#event-filtering. | |
| 24 | + | |
| 25 | +**--trigger** *<trigger>* | |
| 26 | + Enable a trace event trigger to the previous **-e** *sys:event*. | |
| 27 | + If the *hist:* trigger is activated, the output histogram will be automatically saved to a file named *system_event_hist.txt*. | |
| 28 | + For example, the command: | |
| 29 | + | |
| 30 | + rtla <command> <mode> -t -e osnoise:irq_noise --trigger="hist:key=desc,duration/1000:sort=desc,duration/1000:vals=hitcount" | |
| 31 | + | |
| 32 | + Will automatically save the content of the histogram associated to *osnoise:irq_noise* event in *osnoise_irq_noise_hist.txt*. | |
| 33 | + | |
| 34 | + For further information about event trigger see https://www.kernel.org/doc/html/latest/trace/events.html#event-triggers. | |
| 35 | + | |
| 17 | 36 | **-P**, **--priority** *o:prio|r:prio|f:prio|d:runtime:period* |
| 18 | 37 | |
| 19 | 38 | Set scheduling parameters to the osnoise tracer threads, the format to set the priority are: |
| @@ -1,3 +1,8 @@ | ||
| 1 | +**-a**, **--auto** *us* | |
| 2 | + | |
| 3 | + Set the automatic trace mode. This mode sets some commonly used options | |
| 4 | + while debugging the system. It is equivalent to use **-s** *us* **-T 1 -t**. | |
| 5 | + | |
| 1 | 6 | **-p**, **--period** *us* |
| 2 | 7 | |
| 3 | 8 | Set the *osnoise* tracer period in microseconds. |
| @@ -15,3 +20,8 @@ · 11 unmodified lines | ||
| 15 | 20 | |
| 16 | 21 | Stop the trace if the total sample is higher than the argument in microseconds. |
| 17 | 22 | If **-T** is set, it will also save the trace to the output. |
| 23 | + | |
| 24 | +**-T**, **--threshold** *us* | |
| 25 | + | |
| 26 | + Specify the minimum delta between two time reads to be considered noise. | |
| 27 | + The default threshold is *5 us*. | |
| @@ -1,3 +1,10 @@ | ||
| 1 | +**-a**, **--auto** *us* | |
| 2 | + | |
| 3 | + Set the automatic trace mode. This mode sets some commonly used options | |
| 4 | + while debugging the system. It is equivalent to use **-T** *us* **-s** *us* | |
| 5 | + **-t**. By default, *timerlat* tracer uses FIFO:95 for *timerlat* threads, | |
| 6 | + thus equilavent to **-P** *f:95*. | |
| 7 | + | |
| 1 | 8 | **-p**, **--period** *us* |
| 2 | 9 | |
| 3 | 10 | Set the *timerlat* tracer period in microseconds. |
| @@ -14,3 +21,8 @@ · 10 unmodified lines | ||
| 14 | 21 | |
| 15 | 22 | Save the stack trace at the *IRQ* if a *Thread* latency is higher than the |
| 16 | 23 | argument in us. |
| 24 | + | |
| 25 | +**--dma-latency** *us* | |
| 26 | + Set the /dev/cpu_dma_latency to *us*, aiming to bound exit from idle latencies. | |
| 27 | + *cyclictest* sets this value to *0* by default, use **--dma-latency** *0* to have | |
| 28 | + similar results. | |
| @@ -655,6 +655,85 @@ void osnoise_put_print_stack(struct osnoise_context *context) · 654 unmodified lines | ||
| 655 | 655 | context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; |
| 656 | 656 | } |
| 657 | 657 | |
| 658 | +/* | |
| 659 | + * osnoise_get_tracing_thresh - read and save the original "tracing_thresh" | |
| 660 | + */ | |
| 661 | +static long long | |
| 662 | +osnoise_get_tracing_thresh(struct osnoise_context *context) | |
| 663 | +{ | |
| 664 | + long long tracing_thresh; | |
| 665 | + | |
| 666 | + if (context->tracing_thresh != OSNOISE_OPTION_INIT_VAL) | |
| 667 | + return context->tracing_thresh; | |
| 668 | + | |
| 669 | + if (context->orig_tracing_thresh != OSNOISE_OPTION_INIT_VAL) | |
| 670 | + return context->orig_tracing_thresh; | |
| 671 | + | |
| 672 | + tracing_thresh = osnoise_read_ll_config("tracing_thresh"); | |
| 673 | + if (tracing_thresh < 0) | |
| 674 | + goto out_err; | |
| 675 | + | |
| 676 | + context->orig_tracing_thresh = tracing_thresh; | |
| 677 | + return tracing_thresh; | |
| 678 | + | |
| 679 | +out_err: | |
| 680 | + return OSNOISE_OPTION_INIT_VAL; | |
| 681 | +} | |
| 682 | + | |
| 683 | +/* | |
| 684 | + * osnoise_set_tracing_thresh - set "tracing_thresh" | |
| 685 | + */ | |
| 686 | +int osnoise_set_tracing_thresh(struct osnoise_context *context, long long tracing_thresh) | |
| 687 | +{ | |
| 688 | + long long curr_tracing_thresh = osnoise_get_tracing_thresh(context); | |
| 689 | + int retval; | |
| 690 | + | |
| 691 | + if (curr_tracing_thresh == OSNOISE_OPTION_INIT_VAL) | |
| 692 | + return -1; | |
| 693 | + | |
| 694 | + retval = osnoise_write_ll_config("tracing_thresh", tracing_thresh); | |
| 695 | + if (retval < 0) | |
| 696 | + return -1; | |
| 697 | + | |
| 698 | + context->tracing_thresh = tracing_thresh; | |
| 699 | + | |
| 700 | + return 0; | |
| 701 | +} | |
| 702 | + | |
| 703 | +/* | |
| 704 | + * osnoise_restore_tracing_thresh - restore the original "tracing_thresh" | |
| 705 | + */ | |
| 706 | +void osnoise_restore_tracing_thresh(struct osnoise_context *context) | |
| 707 | +{ | |
| 708 | + int retval; | |
| 709 | + | |
| 710 | + if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL) | |
| 711 | + return; | |
| 712 | + | |
| 713 | + if (context->orig_tracing_thresh == context->tracing_thresh) | |
| 714 | + goto out_done; | |
| 715 | + | |
| 716 | + retval = osnoise_write_ll_config("tracing_thresh", context->orig_tracing_thresh); | |
| 717 | + if (retval < 0) | |
| 718 | + err_msg("Could not restore original tracing_thresh\n"); | |
| 719 | + | |
| 720 | +out_done: | |
| 721 | + context->tracing_thresh = OSNOISE_OPTION_INIT_VAL; | |
| 722 | +} | |
| 723 | + | |
| 724 | +/* | |
| 725 | + * osnoise_put_tracing_thresh - restore original values and cleanup data | |
| 726 | + */ | |
| 727 | +void osnoise_put_tracing_thresh(struct osnoise_context *context) | |
| 728 | +{ | |
| 729 | + osnoise_restore_tracing_thresh(context); | |
| 730 | + | |
| 731 | + if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL) | |
| 732 | + return; | |
| 733 | + | |
| 734 | + context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL; | |
| 735 | +} | |
| 736 | + | |
| 658 | 737 | /* |
| 659 | 738 | * enable_osnoise - enable osnoise tracer in the trace_instance |
| 660 | 739 | */ |
| @@ -716,6 +795,9 @@ struct osnoise_context *osnoise_context_alloc(void) · 55 unmodified lines | ||
| 716 | 795 | context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; |
| 717 | 796 | context->print_stack = OSNOISE_OPTION_INIT_VAL; |
| 718 | 797 | |
| 798 | + context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL; | |
| 799 | + context->tracing_thresh = OSNOISE_OPTION_INIT_VAL; | |
| 800 | + | |
| 719 | 801 | osnoise_get_context(context); |
| 720 | 802 | |
| 721 | 803 | return context; |
| @@ -741,6 +823,7 @@ void osnoise_put_context(struct osnoise_context *context) · 19 unmodified lines | ||
| 741 | 823 | osnoise_put_stop_total_us(context); |
| 742 | 824 | osnoise_put_timerlat_period_us(context); |
| 743 | 825 | osnoise_put_print_stack(context); |
| 826 | + osnoise_put_tracing_thresh(context); | |
| 744 | 827 | |
| 745 | 828 | free(context); |
| 746 | 829 | } |
| @@ -23,6 +23,10 @@ struct osnoise_context { · 22 unmodified lines | ||
| 23 | 23 | long long orig_timerlat_period_us; |
| 24 | 24 | long long timerlat_period_us; |
| 25 | 25 | |
| 26 | + /* 0 as init value */ | |
| 27 | + long long orig_tracing_thresh; | |
| 28 | + long long tracing_thresh; | |
| 29 | + | |
| 26 | 30 | /* -1 as init value because 0 is disabled */ |
| 27 | 31 | long long orig_stop_us; |
| 28 | 32 | long long stop_us; |
| @@ -67,6 +71,10 @@ int osnoise_set_timerlat_period_us(struct osnoise_context *context, · 38 unmodified lines | ||
| 67 | 71 | long long timerlat_period_us); |
| 68 | 72 | void osnoise_restore_timerlat_period_us(struct osnoise_context *context); |
| 69 | 73 | |
| 74 | +int osnoise_set_tracing_thresh(struct osnoise_context *context, | |
| 75 | + long long tracing_thresh); | |
| 76 | +void osnoise_restore_tracing_thresh(struct osnoise_context *context); | |
| 77 | + | |
| 70 | 78 | void osnoise_restore_print_stack(struct osnoise_context *context); |
| 71 | 79 | int osnoise_set_print_stack(struct osnoise_context *context, |
| 72 | 80 | long long print_stack); |
| @@ -21,6 +21,7 @@ struct osnoise_hist_params { · 20 unmodified lines | ||
| 21 | 21 | char *trace_output; |
| 22 | 22 | unsigned long long runtime; |
| 23 | 23 | unsigned long long period; |
| 24 | + long long threshold; | |
| 24 | 25 | long long stop_us; |
| 25 | 26 | long long stop_total_us; |
| 26 | 27 | int sleep_time; |
| @@ -28,6 +29,7 @@ struct osnoise_hist_params { · 1 unmodified line | ||
| 28 | 29 | int set_sched; |
| 29 | 30 | int output_divisor; |
| 30 | 31 | struct sched_attr sched_param; |
| 32 | + struct trace_events *events; | |
| 31 | 33 | |
| 32 | 34 | char no_header; |
| 33 | 35 | char no_summary; |
| @@ -425,19 +427,25 @@ static void osnoise_hist_usage(char *usage) · 391 unmodified lines | ||
| 425 | 427 | |
| 426 | 428 | static const char * const msg[] = { |
| 427 | 429 | "", |
| 428 | − " usage: rtla osnoise hist [-h] [-D] [-d s] [-p us] [-r us] [-s us] [-S us] [-t[=file]] \\", | |
| 429 | − " [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\", | |
| 430 | − " [--no-index] [--with-zeros]", | |
| 430 | + " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", | |
| 431 | + " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", | |
| 432 | + " [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] [--no-index] \\", | |
| 433 | + " [--with-zeros]", | |
| 431 | 434 | "", |
| 432 | 435 | " -h/--help: print this menu", |
| 436 | + " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", | |
| 433 | 437 | " -p/--period us: osnoise period in us", |
| 434 | 438 | " -r/--runtime us: osnoise runtime in us", |
| 435 | 439 | " -s/--stop us: stop trace if a single sample is higher than the argument in us", |
| 436 | 440 | " -S/--stop-total us: stop trace if the total sample is higher than the argument in us", |
| 441 | + " -T/--threshold us: the minimum delta to be considered a noise", | |
| 437 | 442 | " -c/--cpus cpu-list: list of cpus to run osnoise threads", |
| 438 | 443 | " -d/--duration time[s|m|h|d]: duration of the session", |
| 439 | 444 | " -D/--debug: print debug info", |
| 440 | 445 | " -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]", |
| 446 | + " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", | |
| 447 | + " --filter <filter>: enable a trace event filter to the previous -e event", | |
| 448 | + " --trigger <trigger>: enable a trace event trigger to the previous -e event", | |
| 441 | 449 | " -b/--bucket-size N: set the histogram bucket size (default 1)", |
| 442 | 450 | " -E/--entries N: set the number of entries of the histogram (default 256)", |
| 443 | 451 | " --no-header: do not print header", |
| @@ -471,6 +479,7 @@ static struct osnoise_hist_params · 27 unmodified lines | ||
| 471 | 479 | *osnoise_hist_parse_args(int argc, char *argv[]) |
| 472 | 480 | { |
| 473 | 481 | struct osnoise_hist_params *params; |
| 482 | + struct trace_events *tevent; | |
| 474 | 483 | int retval; |
| 475 | 484 | int c; |
| 476 | 485 | |
| @@ -485,6 +494,7 @@ static struct osnoise_hist_params · 8 unmodified lines | ||
| 485 | 494 | |
| 486 | 495 | while (1) { |
| 487 | 496 | static struct option long_options[] = { |
| 497 | + {"auto", required_argument, 0, 'a'}, | |
| 488 | 498 | {"bucket-size", required_argument, 0, 'b'}, |
| 489 | 499 | {"entries", required_argument, 0, 'E'}, |
| 490 | 500 | {"cpus", required_argument, 0, 'c'}, |
| @@ -497,17 +507,21 @@ static struct osnoise_hist_params · 6 unmodified lines | ||
| 497 | 507 | {"stop", required_argument, 0, 's'}, |
| 498 | 508 | {"stop-total", required_argument, 0, 'S'}, |
| 499 | 509 | {"trace", optional_argument, 0, 't'}, |
| 510 | + {"event", required_argument, 0, 'e'}, | |
| 511 | + {"threshold", required_argument, 0, 'T'}, | |
| 500 | 512 | {"no-header", no_argument, 0, '0'}, |
| 501 | 513 | {"no-summary", no_argument, 0, '1'}, |
| 502 | 514 | {"no-index", no_argument, 0, '2'}, |
| 503 | 515 | {"with-zeros", no_argument, 0, '3'}, |
| 516 | + {"trigger", required_argument, 0, '4'}, | |
| 517 | + {"filter", required_argument, 0, '5'}, | |
| 504 | 518 | {0, 0, 0, 0} |
| 505 | 519 | }; |
| 506 | 520 | |
| 507 | 521 | /* getopt_long stores the option index here. */ |
| 508 | 522 | int option_index = 0; |
| 509 | 523 | |
| 510 | − c = getopt_long(argc, argv, "c:b:d:E:Dhp:P:r:s:S:t::0123", | |
| 524 | + c = getopt_long(argc, argv, "a:c:b:d:e:E:Dhp:P:r:s:S:t::T:01234:5:", | |
| 511 | 525 | long_options, &option_index); |
| 512 | 526 | |
| 513 | 527 | /* detect the end of the options. */ |
| @@ -515,6 +529,17 @@ static struct osnoise_hist_params · 1 unmodified line | ||
| 515 | 529 | break; |
| 516 | 530 | |
| 517 | 531 | switch (c) { |
| 532 | + case 'a': | |
| 533 | + /* set sample stop to auto_thresh */ | |
| 534 | + params->stop_us = get_llong_from_str(optarg); | |
| 535 | + | |
| 536 | + /* set sample threshold to 1 */ | |
| 537 | + params->threshold = 1; | |
| 538 | + | |
| 539 | + /* set trace */ | |
| 540 | + params->trace_output = "osnoise_trace.txt"; | |
| 541 | + | |
| 542 | + break; | |
| 518 | 543 | case 'b': |
| 519 | 544 | params->bucket_size = get_llong_from_str(optarg); |
| 520 | 545 | if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) |
| @@ -534,6 +559,18 @@ static struct osnoise_hist_params · 13 unmodified lines | ||
| 534 | 559 | if (!params->duration) |
| 535 | 560 | osnoise_hist_usage("Invalid -D duration\n"); |
| 536 | 561 | break; |
| 562 | + case 'e': | |
| 563 | + tevent = trace_event_alloc(optarg); | |
| 564 | + if (!tevent) { | |
| 565 | + err_msg("Error alloc trace event"); | |
| 566 | + exit(EXIT_FAILURE); | |
| 567 | + } | |
| 568 | + | |
| 569 | + if (params->events) | |
| 570 | + tevent->next = params->events; | |
| 571 | + | |
| 572 | + params->events = tevent; | |
| 573 | + break; | |
| 537 | 574 | case 'E': |
| 538 | 575 | params->entries = get_llong_from_str(optarg); |
| 539 | 576 | if ((params->entries < 10) || (params->entries > 9999999)) |
| @@ -565,6 +602,9 @@ static struct osnoise_hist_params · 25 unmodified lines | ||
| 565 | 602 | case 'S': |
| 566 | 603 | params->stop_total_us = get_llong_from_str(optarg); |
| 567 | 604 | break; |
| 605 | + case 'T': | |
| 606 | + params->threshold = get_llong_from_str(optarg); | |
| 607 | + break; | |
| 568 | 608 | case 't': |
| 569 | 609 | if (optarg) |
| 570 | 610 | /* skip = */ |
| @@ -584,6 +624,28 @@ static struct osnoise_hist_params · 13 unmodified lines | ||
| 584 | 624 | case '3': /* with zeros */ |
| 585 | 625 | params->with_zeros = 1; |
| 586 | 626 | break; |
| 627 | + case '4': /* trigger */ | |
| 628 | + if (params->events) { | |
| 629 | + retval = trace_event_add_trigger(params->events, optarg); | |
| 630 | + if (retval) { | |
| 631 | + err_msg("Error adding trigger %s\n", optarg); | |
| 632 | + exit(EXIT_FAILURE); | |
| 633 | + } | |
| 634 | + } else { | |
| 635 | + osnoise_hist_usage("--trigger requires a previous -e\n"); | |
| 636 | + } | |
| 637 | + break; | |
| 638 | + case '5': /* filter */ | |
| 639 | + if (params->events) { | |
| 640 | + retval = trace_event_add_filter(params->events, optarg); | |
| 641 | + if (retval) { | |
| 642 | + err_msg("Error adding filter %s\n", optarg); | |
| 643 | + exit(EXIT_FAILURE); | |
| 644 | + } | |
| 645 | + } else { | |
| 646 | + osnoise_hist_usage("--filter requires a previous -e\n"); | |
| 647 | + } | |
| 648 | + break; | |
| 587 | 649 | default: |
| 588 | 650 | osnoise_hist_usage("Invalid option"); |
| 589 | 651 | } |
| @@ -645,6 +707,14 @@ osnoise_hist_apply_config(struct osnoise_tool *tool, struct osnoise_hist_params · 55 unmodified lines | ||
| 645 | 707 | } |
| 646 | 708 | } |
| 647 | 709 | |
| 710 | + if (params->threshold) { | |
| 711 | + retval = osnoise_set_tracing_thresh(tool->context, params->threshold); | |
| 712 | + if (retval) { | |
| 713 | + err_msg("Failed to set tracing_thresh\n"); | |
| 714 | + goto out_err; | |
| 715 | + } | |
| 716 | + } | |
| 717 | + | |
| 648 | 718 | return 0; |
| 649 | 719 | |
| 650 | 720 | out_err: |
| @@ -751,6 +821,13 @@ int osnoise_hist_main(int argc, char *argv[]) · 100 unmodified lines | ||
| 751 | 821 | err_msg("Failed to enable the trace instance\n"); |
| 752 | 822 | goto out_hist; |
| 753 | 823 | } |
| 824 | + | |
| 825 | + if (params->events) { | |
| 826 | + retval = trace_events_enable(&record->trace, params->events); | |
| 827 | + if (retval) | |
| 828 | + goto out_hist; | |
| 829 | + } | |
| 830 | + | |
| 754 | 831 | trace_instance_start(&record->trace); |
| 755 | 832 | } |
| 756 | 833 | |
| @@ -771,9 +848,9 @@ int osnoise_hist_main(int argc, char *argv[]) · 14 unmodified lines | ||
| 771 | 848 | goto out_hist; |
| 772 | 849 | } |
| 773 | 850 | |
| 774 | − if (!tracefs_trace_is_on(trace->inst)) | |
| 851 | + if (trace_is_off(&tool->trace, &record->trace)) | |
| 775 | 852 | break; |
| 776 | − }; | |
| 853 | + } | |
| 777 | 854 | |
| 778 | 855 | osnoise_read_trace_hist(tool); |
| 779 | 856 | |
| @@ -781,8 +858,8 @@ int osnoise_hist_main(int argc, char *argv[]) · 1 unmodified line | ||
| 781 | 858 | |
| 782 | 859 | return_value = 0; |
| 783 | 860 | |
| 784 | − if (!tracefs_trace_is_on(trace->inst)) { | |
| 785 | − printf("rtla timelat hit stop tracing\n"); | |
| 861 | + if (trace_is_off(&tool->trace, &record->trace)) { | |
| 862 | + printf("rtla osnoise hit stop tracing\n"); | |
| 786 | 863 | if (params->trace_output) { |
| 787 | 864 | printf(" Saving trace to %s\n", params->trace_output); |
| 788 | 865 | save_trace_to_file(record->trace.inst, params->trace_output); |
| @@ -790,6 +867,8 @@ int osnoise_hist_main(int argc, char *argv[]) · 1 unmodified line | ||
| 790 | 867 | } |
| 791 | 868 | |
| 792 | 869 | out_hist: |
| 870 | + trace_events_destroy(&record->trace, params->events); | |
| 871 | + params->events = NULL; | |
| 793 | 872 | osnoise_free_histogram(tool->data); |
| 794 | 873 | out_destroy: |
| 795 | 874 | osnoise_destroy_tool(record); |
| @@ -23,6 +23,7 @@ struct osnoise_top_params { · 22 unmodified lines | ||
| 23 | 23 | char *trace_output; |
| 24 | 24 | unsigned long long runtime; |
| 25 | 25 | unsigned long long period; |
| 26 | + long long threshold; | |
| 26 | 27 | long long stop_us; |
| 27 | 28 | long long stop_total_us; |
| 28 | 29 | int sleep_time; |
| @@ -30,6 +31,7 @@ struct osnoise_top_params { · 1 unmodified line | ||
| 30 | 31 | int quiet; |
| 31 | 32 | int set_sched; |
| 32 | 33 | struct sched_attr sched_param; |
| 34 | + struct trace_events *events; | |
| 33 | 35 | }; |
| 34 | 36 | |
| 35 | 37 | struct osnoise_top_cpu { |
| @@ -244,18 +246,24 @@ void osnoise_top_usage(char *usage) · 208 unmodified lines | ||
| 244 | 246 | int i; |
| 245 | 247 | |
| 246 | 248 | static const char * const msg[] = { |
| 247 | − " usage: rtla osnoise [top] [-h] [-q] [-D] [-d s] [-p us] [-r us] [-s us] [-S us] [-t[=file]] \\", | |
| 249 | + " usage: rtla osnoise [top] [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", | |
| 250 | + " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", | |
| 248 | 251 | " [-c cpu-list] [-P priority]", |
| 249 | 252 | "", |
| 250 | 253 | " -h/--help: print this menu", |
| 254 | + " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", | |
| 251 | 255 | " -p/--period us: osnoise period in us", |
| 252 | 256 | " -r/--runtime us: osnoise runtime in us", |
| 253 | 257 | " -s/--stop us: stop trace if a single sample is higher than the argument in us", |
| 254 | 258 | " -S/--stop-total us: stop trace if the total sample is higher than the argument in us", |
| 259 | + " -T/--threshold us: the minimum delta to be considered a noise", | |
| 255 | 260 | " -c/--cpus cpu-list: list of cpus to run osnoise threads", |
| 256 | 261 | " -d/--duration time[s|m|h|d]: duration of the session", |
| 257 | 262 | " -D/--debug: print debug info", |
| 258 | 263 | " -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]", |
| 264 | + " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", | |
| 265 | + " --filter <filter>: enable a trace event filter to the previous -e event", | |
| 266 | + " --trigger <trigger>: enable a trace event trigger to the previous -e event", | |
| 259 | 267 | " -q/--quiet print only a summary at the end", |
| 260 | 268 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", |
| 261 | 269 | " o:prio - use SCHED_OTHER with prio", |
| @@ -283,6 +291,7 @@ void osnoise_top_usage(char *usage) · 21 unmodified lines | ||
| 283 | 291 | struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) |
| 284 | 292 | { |
| 285 | 293 | struct osnoise_top_params *params; |
| 294 | + struct trace_events *tevent; | |
| 286 | 295 | int retval; |
| 287 | 296 | int c; |
| 288 | 297 | |
| @@ -292,9 +301,11 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) · 3 unmodified lines | ||
| 292 | 301 | |
| 293 | 302 | while (1) { |
| 294 | 303 | static struct option long_options[] = { |
| 304 | + {"auto", required_argument, 0, 'a'}, | |
| 295 | 305 | {"cpus", required_argument, 0, 'c'}, |
| 296 | 306 | {"debug", no_argument, 0, 'D'}, |
| 297 | 307 | {"duration", required_argument, 0, 'd'}, |
| 308 | + {"event", required_argument, 0, 'e'}, | |
| 298 | 309 | {"help", no_argument, 0, 'h'}, |
| 299 | 310 | {"period", required_argument, 0, 'p'}, |
| 300 | 311 | {"priority", required_argument, 0, 'P'}, |
| @@ -302,14 +313,17 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) · 1 unmodified line | ||
| 302 | 313 | {"runtime", required_argument, 0, 'r'}, |
| 303 | 314 | {"stop", required_argument, 0, 's'}, |
| 304 | 315 | {"stop-total", required_argument, 0, 'S'}, |
| 316 | + {"threshold", required_argument, 0, 'T'}, | |
| 305 | 317 | {"trace", optional_argument, 0, 't'}, |
| 318 | + {"trigger", required_argument, 0, '0'}, | |
| 319 | + {"filter", required_argument, 0, '1'}, | |
| 306 | 320 | {0, 0, 0, 0} |
| 307 | 321 | }; |
| 308 | 322 | |
| 309 | 323 | /* getopt_long stores the option index here. */ |
| 310 | 324 | int option_index = 0; |
| 311 | 325 | |
| 312 | − c = getopt_long(argc, argv, "c:d:Dhp:P:qr:s:S:t::", | |
| 326 | + c = getopt_long(argc, argv, "a:c:d:De:hp:P:qr:s:S:t::T:0:1:", | |
| 313 | 327 | long_options, &option_index); |
| 314 | 328 | |
| 315 | 329 | /* Detect the end of the options. */ |
| @@ -317,6 +331,17 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) · 1 unmodified line | ||
| 317 | 331 | break; |
| 318 | 332 | |
| 319 | 333 | switch (c) { |
| 334 | + case 'a': | |
| 335 | + /* set sample stop to auto_thresh */ | |
| 336 | + params->stop_us = get_llong_from_str(optarg); | |
| 337 | + | |
| 338 | + /* set sample threshold to 1 */ | |
| 339 | + params->threshold = 1; | |
| 340 | + | |
| 341 | + /* set trace */ | |
| 342 | + params->trace_output = "osnoise_trace.txt"; | |
| 343 | + | |
| 344 | + break; | |
| 320 | 345 | case 'c': |
| 321 | 346 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); |
| 322 | 347 | if (retval) |
| @@ -331,6 +356,18 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) · 8 unmodified lines | ||
| 331 | 356 | if (!params->duration) |
| 332 | 357 | osnoise_top_usage("Invalid -D duration\n"); |
| 333 | 358 | break; |
| 359 | + case 'e': | |
| 360 | + tevent = trace_event_alloc(optarg); | |
| 361 | + if (!tevent) { | |
| 362 | + err_msg("Error alloc trace event"); | |
| 363 | + exit(EXIT_FAILURE); | |
| 364 | + } | |
| 365 | + | |
| 366 | + if (params->events) | |
| 367 | + tevent->next = params->events; | |
| 368 | + params->events = tevent; | |
| 369 | + | |
| 370 | + break; | |
| 334 | 371 | case 'h': |
| 335 | 372 | case '?': |
| 336 | 373 | osnoise_top_usage(NULL); |
| @@ -367,6 +404,31 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) · 30 unmodified lines | ||
| 367 | 404 | else |
| 368 | 405 | params->trace_output = "osnoise_trace.txt"; |
| 369 | 406 | break; |
| 407 | + case 'T': | |
| 408 | + params->threshold = get_llong_from_str(optarg); | |
| 409 | + break; | |
| 410 | + case '0': /* trigger */ | |
| 411 | + if (params->events) { | |
| 412 | + retval = trace_event_add_trigger(params->events, optarg); | |
| 413 | + if (retval) { | |
| 414 | + err_msg("Error adding trigger %s\n", optarg); | |
| 415 | + exit(EXIT_FAILURE); | |
| 416 | + } | |
| 417 | + } else { | |
| 418 | + osnoise_top_usage("--trigger requires a previous -e\n"); | |
| 419 | + } | |
| 420 | + break; | |
| 421 | + case '1': /* filter */ | |
| 422 | + if (params->events) { | |
| 423 | + retval = trace_event_add_filter(params->events, optarg); | |
| 424 | + if (retval) { | |
| 425 | + err_msg("Error adding filter %s\n", optarg); | |
| 426 | + exit(EXIT_FAILURE); | |
| 427 | + } | |
| 428 | + } else { | |
| 429 | + osnoise_top_usage("--filter requires a previous -e\n"); | |
| 430 | + } | |
| 431 | + break; | |
| 370 | 432 | default: |
| 371 | 433 | osnoise_top_usage("Invalid option"); |
| 372 | 434 | } |
| @@ -425,6 +487,14 @@ osnoise_top_apply_config(struct osnoise_tool *tool, struct osnoise_top_params *p · 52 unmodified lines | ||
| 425 | 487 | } |
| 426 | 488 | } |
| 427 | 489 | |
| 490 | + if (params->threshold) { | |
| 491 | + retval = osnoise_set_tracing_thresh(tool->context, params->threshold); | |
| 492 | + if (retval) { | |
| 493 | + err_msg("Failed to set tracing_thresh\n"); | |
| 494 | + goto out_err; | |
| 495 | + } | |
| 496 | + } | |
| 497 | + | |
| 428 | 498 | return 0; |
| 429 | 499 | |
| 430 | 500 | out_err: |
| @@ -529,13 +599,20 @@ int osnoise_top_main(int argc, char **argv) · 98 unmodified lines | ||
| 529 | 599 | err_msg("Failed to enable the trace instance\n"); |
| 530 | 600 | goto out_top; |
| 531 | 601 | } |
| 602 | + | |
| 603 | + if (params->events) { | |
| 604 | + retval = trace_events_enable(&record->trace, params->events); | |
| 605 | + if (retval) | |
| 606 | + goto out_top; | |
| 607 | + } | |
| 608 | + | |
| 532 | 609 | trace_instance_start(&record->trace); |
| 533 | 610 | } |
| 534 | 611 | |
| 535 | 612 | tool->start_time = time(NULL); |
| 536 | 613 | osnoise_top_set_signals(params); |
| 537 | 614 | |
| 538 | − do { | |
| 615 | + while (!stop_tracing) { | |
| 539 | 616 | sleep(params->sleep_time); |
| 540 | 617 | |
| 541 | 618 | retval = tracefs_iterate_raw_events(trace->tep, |
| @@ -552,16 +629,16 @@ int osnoise_top_main(int argc, char **argv) · 10 unmodified lines | ||
| 552 | 629 | if (!params->quiet) |
| 553 | 630 | osnoise_print_stats(params, tool); |
| 554 | 631 | |
| 555 | − if (!tracefs_trace_is_on(trace->inst)) | |
| 632 | + if (trace_is_off(&tool->trace, &record->trace)) | |
| 556 | 633 | break; |
| 557 | 634 | |
| 558 | − } while (!stop_tracing); | |
| 635 | + } | |
| 559 | 636 | |
| 560 | 637 | osnoise_print_stats(params, tool); |
| 561 | 638 | |
| 562 | 639 | return_value = 0; |
| 563 | 640 | |
| 564 | − if (!tracefs_trace_is_on(trace->inst)) { | |
| 641 | + if (trace_is_off(&tool->trace, &record->trace)) { | |
| 565 | 642 | printf("osnoise hit stop tracing\n"); |
| 566 | 643 | if (params->trace_output) { |
| 567 | 644 | printf(" Saving trace to %s\n", params->trace_output); |
| @@ -570,6 +647,8 @@ int osnoise_top_main(int argc, char **argv) · 2 unmodified lines | ||
| 570 | 647 | } |
| 571 | 648 | |
| 572 | 649 | out_top: |
| 650 | + trace_events_destroy(&record->trace, params->events); | |
| 651 | + params->events = NULL; | |
| 573 | 652 | osnoise_free_top(tool->data); |
| 574 | 653 | osnoise_destroy_tool(record); |
| 575 | 654 | osnoise_destroy_tool(tool); |
| @@ -28,7 +28,9 @@ struct timerlat_hist_params { · 27 unmodified lines | ||
| 28 | 28 | int output_divisor; |
| 29 | 29 | int duration; |
| 30 | 30 | int set_sched; |
| 31 | + int dma_latency; | |
| 31 | 32 | struct sched_attr sched_param; |
| 33 | + struct trace_events *events; | |
| 32 | 34 | |
| 33 | 35 | char no_irq; |
| 34 | 36 | char no_thread; |
| @@ -428,11 +430,13 @@ static void timerlat_hist_usage(char *usage) · 393 unmodified lines | ||
| 428 | 430 | |
| 429 | 431 | char *msg[] = { |
| 430 | 432 | "", |
| 431 | − " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] [-t[=file]] \\", | |
| 432 | − " [-c cpu-list] [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", | |
| 433 | − " [--no-index] [--with-zeros]", | |
| 433 | + " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\", | |
| 434 | + " [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] \\", | |
| 435 | + " [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", | |
| 436 | + " [--no-index] [--with-zeros] [--dma-latency us]", | |
| 434 | 437 | "", |
| 435 | 438 | " -h/--help: print this menu", |
| 439 | + " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", | |
| 436 | 440 | " -p/--period us: timerlat period in us", |
| 437 | 441 | " -i/--irq us: stop trace if the irq latency is higher than the argument in us", |
| 438 | 442 | " -T/--thread us: stop trace if the thread latency is higher than the argument in us", |
| @@ -440,7 +444,10 @@ static void timerlat_hist_usage(char *usage) · 1 unmodified line | ||
| 440 | 444 | " -c/--cpus cpus: run the tracer only on the given cpus", |
| 441 | 445 | " -d/--duration time[m|h|d]: duration of the session in seconds", |
| 442 | 446 | " -D/--debug: print debug info", |
| 443 | − " -T/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]", | |
| 447 | + " -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]", | |
| 448 | + " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", | |
| 449 | + " --filter <filter>: enable a trace event filter to the previous -e event", | |
| 450 | + " --trigger <trigger>: enable a trace event trigger to the previous -e event", | |
| 444 | 451 | " -n/--nano: display data in nanoseconds", |
| 445 | 452 | " -b/--bucket-size N: set the histogram bucket size (default 1)", |
| 446 | 453 | " -E/--entries N: set the number of entries of the histogram (default 256)", |
| @@ -450,6 +457,7 @@ static void timerlat_hist_usage(char *usage) · 3 unmodified lines | ||
| 450 | 457 | " --no-summary: do not print summary", |
| 451 | 458 | " --no-index: do not print index", |
| 452 | 459 | " --with-zeros: print zero only entries", |
| 460 | + " --dma-latency us: set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency", | |
| 453 | 461 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", |
| 454 | 462 | " o:prio - use SCHED_OTHER with prio", |
| 455 | 463 | " r:prio - use SCHED_RR with prio", |
| @@ -477,6 +485,8 @@ static struct timerlat_hist_params · 21 unmodified lines | ||
| 477 | 485 | *timerlat_hist_parse_args(int argc, char *argv[]) |
| 478 | 486 | { |
| 479 | 487 | struct timerlat_hist_params *params; |
| 488 | + struct trace_events *tevent; | |
| 489 | + int auto_thresh; | |
| 480 | 490 | int retval; |
| 481 | 491 | int c; |
| 482 | 492 | |
| @@ -484,6 +494,9 @@ static struct timerlat_hist_params · 1 unmodified line | ||
| 484 | 494 | if (!params) |
| 485 | 495 | exit(1); |
| 486 | 496 | |
| 497 | + /* disabled by default */ | |
| 498 | + params->dma_latency = -1; | |
| 499 | + | |
| 487 | 500 | /* display data in microseconds */ |
| 488 | 501 | params->output_divisor = 1000; |
| 489 | 502 | params->bucket_size = 1; |
| @@ -491,6 +504,7 @@ static struct timerlat_hist_params · 1 unmodified line | ||
| 491 | 504 | |
| 492 | 505 | while (1) { |
| 493 | 506 | static struct option long_options[] = { |
| 507 | + {"auto", required_argument, 0, 'a'}, | |
| 494 | 508 | {"cpus", required_argument, 0, 'c'}, |
| 495 | 509 | {"bucket-size", required_argument, 0, 'b'}, |
| 496 | 510 | {"debug", no_argument, 0, 'D'}, |
| @@ -504,19 +518,23 @@ static struct timerlat_hist_params · 7 unmodified lines | ||
| 504 | 518 | {"stack", required_argument, 0, 's'}, |
| 505 | 519 | {"thread", required_argument, 0, 'T'}, |
| 506 | 520 | {"trace", optional_argument, 0, 't'}, |
| 521 | + {"event", required_argument, 0, 'e'}, | |
| 507 | 522 | {"no-irq", no_argument, 0, '0'}, |
| 508 | 523 | {"no-thread", no_argument, 0, '1'}, |
| 509 | 524 | {"no-header", no_argument, 0, '2'}, |
| 510 | 525 | {"no-summary", no_argument, 0, '3'}, |
| 511 | 526 | {"no-index", no_argument, 0, '4'}, |
| 512 | 527 | {"with-zeros", no_argument, 0, '5'}, |
| 528 | + {"trigger", required_argument, 0, '6'}, | |
| 529 | + {"filter", required_argument, 0, '7'}, | |
| 530 | + {"dma-latency", required_argument, 0, '8'}, | |
| 513 | 531 | {0, 0, 0, 0} |
| 514 | 532 | }; |
| 515 | 533 | |
| 516 | 534 | /* getopt_long stores the option index here. */ |
| 517 | 535 | int option_index = 0; |
| 518 | 536 | |
| 519 | − c = getopt_long(argc, argv, "c:b:d:E:Dhi:np:P:s:t::T:012345", | |
| 537 | + c = getopt_long(argc, argv, "a:c:b:d:e:E:Dhi:np:P:s:t::T:0123456:7:8:", | |
| 520 | 538 | long_options, &option_index); |
| 521 | 539 | |
| 522 | 540 | /* detect the end of the options. */ |
| @@ -524,6 +542,19 @@ static struct timerlat_hist_params · 1 unmodified line | ||
| 524 | 542 | break; |
| 525 | 543 | |
| 526 | 544 | switch (c) { |
| 545 | + case 'a': | |
| 546 | + auto_thresh = get_llong_from_str(optarg); | |
| 547 | + | |
| 548 | + /* set thread stop to auto_thresh */ | |
| 549 | + params->stop_total_us = auto_thresh; | |
| 550 | + | |
| 551 | + /* get stack trace */ | |
| 552 | + params->print_stack = auto_thresh; | |
| 553 | + | |
| 554 | + /* set trace */ | |
| 555 | + params->trace_output = "timerlat_trace.txt"; | |
| 556 | + | |
| 557 | + break; | |
| 527 | 558 | case 'c': |
| 528 | 559 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); |
| 529 | 560 | if (retval) |
| @@ -543,6 +574,18 @@ static struct timerlat_hist_params · 13 unmodified lines | ||
| 543 | 574 | if (!params->duration) |
| 544 | 575 | timerlat_hist_usage("Invalid -D duration\n"); |
| 545 | 576 | break; |
| 577 | + case 'e': | |
| 578 | + tevent = trace_event_alloc(optarg); | |
| 579 | + if (!tevent) { | |
| 580 | + err_msg("Error alloc trace event"); | |
| 581 | + exit(EXIT_FAILURE); | |
| 582 | + } | |
| 583 | + | |
| 584 | + if (params->events) | |
| 585 | + tevent->next = params->events; | |
| 586 | + | |
| 587 | + params->events = tevent; | |
| 588 | + break; | |
| 546 | 589 | case 'E': |
| 547 | 590 | params->entries = get_llong_from_str(optarg); |
| 548 | 591 | if ((params->entries < 10) || (params->entries > 9999999)) |
| @@ -600,6 +643,35 @@ static struct timerlat_hist_params · 51 unmodified lines | ||
| 600 | 643 | case '5': /* with zeros */ |
| 601 | 644 | params->with_zeros = 1; |
| 602 | 645 | break; |
| 646 | + case '6': /* trigger */ | |
| 647 | + if (params->events) { | |
| 648 | + retval = trace_event_add_trigger(params->events, optarg); | |
| 649 | + if (retval) { | |
| 650 | + err_msg("Error adding trigger %s\n", optarg); | |
| 651 | + exit(EXIT_FAILURE); | |
| 652 | + } | |
| 653 | + } else { | |
| 654 | + timerlat_hist_usage("--trigger requires a previous -e\n"); | |
| 655 | + } | |
| 656 | + break; | |
| 657 | + case '7': /* filter */ | |
| 658 | + if (params->events) { | |
| 659 | + retval = trace_event_add_filter(params->events, optarg); | |
| 660 | + if (retval) { | |
| 661 | + err_msg("Error adding filter %s\n", optarg); | |
| 662 | + exit(EXIT_FAILURE); | |
| 663 | + } | |
| 664 | + } else { | |
| 665 | + timerlat_hist_usage("--filter requires a previous -e\n"); | |
| 666 | + } | |
| 667 | + break; | |
| 668 | + case '8': | |
| 669 | + params->dma_latency = get_llong_from_str(optarg); | |
| 670 | + if (params->dma_latency < 0 || params->dma_latency > 10000) { | |
| 671 | + err_msg("--dma-latency needs to be >= 0 and < 10000"); | |
| 672 | + exit(EXIT_FAILURE); | |
| 673 | + } | |
| 674 | + break; | |
| 603 | 675 | default: |
| 604 | 676 | timerlat_hist_usage("Invalid option"); |
| 605 | 677 | } |
| @@ -732,6 +804,7 @@ int timerlat_hist_main(int argc, char *argv[]) · 126 unmodified lines | ||
| 732 | 804 | struct osnoise_tool *record = NULL; |
| 733 | 805 | struct osnoise_tool *tool = NULL; |
| 734 | 806 | struct trace_instance *trace; |
| 807 | + int dma_latency_fd = -1; | |
| 735 | 808 | int return_value = 1; |
| 736 | 809 | int retval; |
| 737 | 810 | |
| @@ -767,6 +840,14 @@ int timerlat_hist_main(int argc, char *argv[]) · 29 unmodified lines | ||
| 767 | 840 | } |
| 768 | 841 | } |
| 769 | 842 | |
| 843 | + if (params->dma_latency >= 0) { | |
| 844 | + dma_latency_fd = set_cpu_dma_latency(params->dma_latency); | |
| 845 | + if (dma_latency_fd < 0) { | |
| 846 | + err_msg("Could not set /dev/cpu_dma_latency.\n"); | |
| 847 | + goto out_hist; | |
| 848 | + } | |
| 849 | + } | |
| 850 | + | |
| 770 | 851 | trace_instance_start(trace); |
| 771 | 852 | |
| 772 | 853 | if (params->trace_output) { |
| @@ -775,6 +856,13 @@ int timerlat_hist_main(int argc, char *argv[]) · 2 unmodified lines | ||
| 775 | 856 | err_msg("Failed to enable the trace instance\n"); |
| 776 | 857 | goto out_hist; |
| 777 | 858 | } |
| 859 | + | |
| 860 | + if (params->events) { | |
| 861 | + retval = trace_events_enable(&record->trace, params->events); | |
| 862 | + if (retval) | |
| 863 | + goto out_hist; | |
| 864 | + } | |
| 865 | + | |
| 778 | 866 | trace_instance_start(&record->trace); |
| 779 | 867 | } |
| 780 | 868 | |
| @@ -795,15 +883,15 @@ int timerlat_hist_main(int argc, char *argv[]) · 14 unmodified lines | ||
| 795 | 883 | goto out_hist; |
| 796 | 884 | } |
| 797 | 885 | |
| 798 | − if (!tracefs_trace_is_on(trace->inst)) | |
| 886 | + if (trace_is_off(&tool->trace, &record->trace)) | |
| 799 | 887 | break; |
| 800 | − }; | |
| 888 | + } | |
| 801 | 889 | |
| 802 | 890 | timerlat_print_stats(params, tool); |
| 803 | 891 | |
| 804 | 892 | return_value = 0; |
| 805 | 893 | |
| 806 | − if (!tracefs_trace_is_on(trace->inst)) { | |
| 894 | + if (trace_is_off(&tool->trace, &record->trace)) { | |
| 807 | 895 | printf("rtla timelat hit stop tracing\n"); |
| 808 | 896 | if (params->trace_output) { |
| 809 | 897 | printf(" Saving trace to %s\n", params->trace_output); |
| @@ -812,6 +900,10 @@ int timerlat_hist_main(int argc, char *argv[]) · 2 unmodified lines | ||
| 812 | 900 | } |
| 813 | 901 | |
| 814 | 902 | out_hist: |
| 903 | + if (dma_latency_fd >= 0) | |
| 904 | + close(dma_latency_fd); | |
| 905 | + trace_events_destroy(&record->trace, params->events); | |
| 906 | + params->events = NULL; | |
| 815 | 907 | timerlat_free_histogram(tool->data); |
| 816 | 908 | osnoise_destroy_tool(record); |
| 817 | 909 | osnoise_destroy_tool(tool); |
| @@ -29,7 +29,9 @@ struct timerlat_top_params { · 28 unmodified lines | ||
| 29 | 29 | int duration; |
| 30 | 30 | int quiet; |
| 31 | 31 | int set_sched; |
| 32 | + int dma_latency; | |
| 32 | 33 | struct sched_attr sched_param; |
| 34 | + struct trace_events *events; | |
| 33 | 35 | }; |
| 34 | 36 | |
| 35 | 37 | struct timerlat_top_cpu { |
| @@ -266,10 +268,12 @@ static void timerlat_top_usage(char *usage) · 230 unmodified lines | ||
| 266 | 268 | |
| 267 | 269 | static const char *const msg[] = { |
| 268 | 270 | "", |
| 269 | − " usage: rtla timerlat [top] [-h] [-q] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] [-t[=file]] \\", | |
| 270 | − " [-c cpu-list] [-P priority]", | |
| 271 | + " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\", | |
| 272 | + " [[-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] \\", | |
| 273 | + " [-P priority] [--dma-latency us]", | |
| 271 | 274 | "", |
| 272 | 275 | " -h/--help: print this menu", |
| 276 | + " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", | |
| 273 | 277 | " -p/--period us: timerlat period in us", |
| 274 | 278 | " -i/--irq us: stop trace if the irq latency is higher than the argument in us", |
| 275 | 279 | " -T/--thread us: stop trace if the thread latency is higher than the argument in us", |
| @@ -278,8 +282,12 @@ static void timerlat_top_usage(char *usage) · 2 unmodified lines | ||
| 278 | 282 | " -d/--duration time[m|h|d]: duration of the session in seconds", |
| 279 | 283 | " -D/--debug: print debug info", |
| 280 | 284 | " -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]", |
| 285 | + " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", | |
| 286 | + " --filter <command>: enable a trace event filter to the previous -e event", | |
| 287 | + " --trigger <command>: enable a trace event trigger to the previous -e event", | |
| 281 | 288 | " -n/--nano: display data in nanoseconds", |
| 282 | 289 | " -q/--quiet print only a summary at the end", |
| 290 | + " --dma-latency us: set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency", | |
| 283 | 291 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", |
| 284 | 292 | " o:prio - use SCHED_OTHER with prio", |
| 285 | 293 | " r:prio - use SCHED_RR with prio", |
| @@ -307,6 +315,8 @@ static struct timerlat_top_params · 21 unmodified lines | ||
| 307 | 315 | *timerlat_top_parse_args(int argc, char **argv) |
| 308 | 316 | { |
| 309 | 317 | struct timerlat_top_params *params; |
| 318 | + struct trace_events *tevent; | |
| 319 | + long long auto_thresh; | |
| 310 | 320 | int retval; |
| 311 | 321 | int c; |
| 312 | 322 | |
| @@ -314,14 +324,19 @@ static struct timerlat_top_params · 1 unmodified line | ||
| 314 | 324 | if (!params) |
| 315 | 325 | exit(1); |
| 316 | 326 | |
| 327 | + /* disabled by default */ | |
| 328 | + params->dma_latency = -1; | |
| 329 | + | |
| 317 | 330 | /* display data in microseconds */ |
| 318 | 331 | params->output_divisor = 1000; |
| 319 | 332 | |
| 320 | 333 | while (1) { |
| 321 | 334 | static struct option long_options[] = { |
| 335 | + {"auto", required_argument, 0, 'a'}, | |
| 322 | 336 | {"cpus", required_argument, 0, 'c'}, |
| 323 | 337 | {"debug", no_argument, 0, 'D'}, |
| 324 | 338 | {"duration", required_argument, 0, 'd'}, |
| 339 | + {"event", required_argument, 0, 'e'}, | |
| 325 | 340 | {"help", no_argument, 0, 'h'}, |
| 326 | 341 | {"irq", required_argument, 0, 'i'}, |
| 327 | 342 | {"nano", no_argument, 0, 'n'}, |
| @@ -331,13 +346,16 @@ static struct timerlat_top_params · 3 unmodified lines | ||
| 331 | 346 | {"stack", required_argument, 0, 's'}, |
| 332 | 347 | {"thread", required_argument, 0, 'T'}, |
| 333 | 348 | {"trace", optional_argument, 0, 't'}, |
| 349 | + {"trigger", required_argument, 0, '0'}, | |
| 350 | + {"filter", required_argument, 0, '1'}, | |
| 351 | + {"dma-latency", required_argument, 0, '2'}, | |
| 334 | 352 | {0, 0, 0, 0} |
| 335 | 353 | }; |
| 336 | 354 | |
| 337 | 355 | /* getopt_long stores the option index here. */ |
| 338 | 356 | int option_index = 0; |
| 339 | 357 | |
| 340 | − c = getopt_long(argc, argv, "c:d:Dhi:np:P:qs:t::T:", | |
| 358 | + c = getopt_long(argc, argv, "a:c:d:De:hi:np:P:qs:t::T:0:1:2:", | |
| 341 | 359 | long_options, &option_index); |
| 342 | 360 | |
| 343 | 361 | /* detect the end of the options. */ |
| @@ -345,6 +363,19 @@ static struct timerlat_top_params · 1 unmodified line | ||
| 345 | 363 | break; |
| 346 | 364 | |
| 347 | 365 | switch (c) { |
| 366 | + case 'a': | |
| 367 | + auto_thresh = get_llong_from_str(optarg); | |
| 368 | + | |
| 369 | + /* set thread stop to auto_thresh */ | |
| 370 | + params->stop_total_us = auto_thresh; | |
| 371 | + | |
| 372 | + /* get stack trace */ | |
| 373 | + params->print_stack = auto_thresh; | |
| 374 | + | |
| 375 | + /* set trace */ | |
| 376 | + params->trace_output = "timerlat_trace.txt"; | |
| 377 | + | |
| 378 | + break; | |
| 348 | 379 | case 'c': |
| 349 | 380 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); |
| 350 | 381 | if (retval) |
| @@ -359,6 +390,17 @@ static struct timerlat_top_params · 8 unmodified lines | ||
| 359 | 390 | if (!params->duration) |
| 360 | 391 | timerlat_top_usage("Invalid -D duration\n"); |
| 361 | 392 | break; |
| 393 | + case 'e': | |
| 394 | + tevent = trace_event_alloc(optarg); | |
| 395 | + if (!tevent) { | |
| 396 | + err_msg("Error alloc trace event"); | |
| 397 | + exit(EXIT_FAILURE); | |
| 398 | + } | |
| 399 | + | |
| 400 | + if (params->events) | |
| 401 | + tevent->next = params->events; | |
| 402 | + params->events = tevent; | |
| 403 | + break; | |
| 362 | 404 | case 'h': |
| 363 | 405 | case '?': |
| 364 | 406 | timerlat_top_usage(NULL); |
| @@ -396,6 +438,35 @@ static struct timerlat_top_params · 31 unmodified lines | ||
| 396 | 438 | else |
| 397 | 439 | params->trace_output = "timerlat_trace.txt"; |
| 398 | 440 | break; |
| 441 | + case '0': /* trigger */ | |
| 442 | + if (params->events) { | |
| 443 | + retval = trace_event_add_trigger(params->events, optarg); | |
| 444 | + if (retval) { | |
| 445 | + err_msg("Error adding trigger %s\n", optarg); | |
| 446 | + exit(EXIT_FAILURE); | |
| 447 | + } | |
| 448 | + } else { | |
| 449 | + timerlat_top_usage("--trigger requires a previous -e\n"); | |
| 450 | + } | |
| 451 | + break; | |
| 452 | + case '1': /* filter */ | |
| 453 | + if (params->events) { | |
| 454 | + retval = trace_event_add_filter(params->events, optarg); | |
| 455 | + if (retval) { | |
| 456 | + err_msg("Error adding filter %s\n", optarg); | |
| 457 | + exit(EXIT_FAILURE); | |
| 458 | + } | |
| 459 | + } else { | |
| 460 | + timerlat_top_usage("--filter requires a previous -e\n"); | |
| 461 | + } | |
| 462 | + break; | |
| 463 | + case '2': /* dma-latency */ | |
| 464 | + params->dma_latency = get_llong_from_str(optarg); | |
| 465 | + if (params->dma_latency < 0 || params->dma_latency > 10000) { | |
| 466 | + err_msg("--dma-latency needs to be >= 0 and < 10000"); | |
| 467 | + exit(EXIT_FAILURE); | |
| 468 | + } | |
| 469 | + break; | |
| 399 | 470 | default: |
| 400 | 471 | timerlat_top_usage("Invalid option"); |
| 401 | 472 | } |
| @@ -524,6 +595,7 @@ int timerlat_top_main(int argc, char *argv[]) · 122 unmodified lines | ||
| 524 | 595 | struct osnoise_tool *record = NULL; |
| 525 | 596 | struct osnoise_tool *top = NULL; |
| 526 | 597 | struct trace_instance *trace; |
| 598 | + int dma_latency_fd = -1; | |
| 527 | 599 | int return_value = 1; |
| 528 | 600 | int retval; |
| 529 | 601 | |
| @@ -559,6 +631,14 @@ int timerlat_top_main(int argc, char *argv[]) · 29 unmodified lines | ||
| 559 | 631 | } |
| 560 | 632 | } |
| 561 | 633 | |
| 634 | + if (params->dma_latency >= 0) { | |
| 635 | + dma_latency_fd = set_cpu_dma_latency(params->dma_latency); | |
| 636 | + if (dma_latency_fd < 0) { | |
| 637 | + err_msg("Could not set /dev/cpu_dma_latency.\n"); | |
| 638 | + goto out_top; | |
| 639 | + } | |
| 640 | + } | |
| 641 | + | |
| 562 | 642 | trace_instance_start(trace); |
| 563 | 643 | |
| 564 | 644 | if (params->trace_output) { |
| @@ -567,6 +647,13 @@ int timerlat_top_main(int argc, char *argv[]) · 2 unmodified lines | ||
| 567 | 647 | err_msg("Failed to enable the trace instance\n"); |
| 568 | 648 | goto out_top; |
| 569 | 649 | } |
| 650 | + | |
| 651 | + if (params->events) { | |
| 652 | + retval = trace_events_enable(&record->trace, params->events); | |
| 653 | + if (retval) | |
| 654 | + goto out_top; | |
| 655 | + } | |
| 656 | + | |
| 570 | 657 | trace_instance_start(&record->trace); |
| 571 | 658 | } |
| 572 | 659 | |
| @@ -590,16 +677,16 @@ int timerlat_top_main(int argc, char *argv[]) · 17 unmodified lines | ||
| 590 | 677 | if (!params->quiet) |
| 591 | 678 | timerlat_print_stats(params, top); |
| 592 | 679 | |
| 593 | − if (!tracefs_trace_is_on(trace->inst)) | |
| 680 | + if (trace_is_off(&top->trace, &record->trace)) | |
| 594 | 681 | break; |
| 595 | 682 | |
| 596 | − }; | |
| 683 | + } | |
| 597 | 684 | |
| 598 | 685 | timerlat_print_stats(params, top); |
| 599 | 686 | |
| 600 | 687 | return_value = 0; |
| 601 | 688 | |
| 602 | − if (!tracefs_trace_is_on(trace->inst)) { | |
| 689 | + if (trace_is_off(&top->trace, &record->trace)) { | |
| 603 | 690 | printf("rtla timelat hit stop tracing\n"); |
| 604 | 691 | if (params->trace_output) { |
| 605 | 692 | printf(" Saving trace to %s\n", params->trace_output); |
| @@ -608,6 +695,10 @@ int timerlat_top_main(int argc, char *argv[]) · 2 unmodified lines | ||
| 608 | 695 | } |
| 609 | 696 | |
| 610 | 697 | out_top: |
| 698 | + if (dma_latency_fd >= 0) | |
| 699 | + close(dma_latency_fd); | |
| 700 | + trace_events_destroy(&record->trace, params->events); | |
| 701 | + params->events = NULL; | |
| 611 | 702 | timerlat_free_top(top->data); |
| 612 | 703 | osnoise_destroy_tool(record); |
| 613 | 704 | osnoise_destroy_tool(top); |
| @@ -190,3 +190,348 @@ int trace_instance_start(struct trace_instance *trace) · 189 unmodified lines | ||
| 190 | 190 | { |
| 191 | 191 | return tracefs_trace_on(trace->inst); |
| 192 | 192 | } |
| 193 | + | |
| 194 | +/* | |
| 195 | + * trace_events_free - free a list of trace events | |
| 196 | + */ | |
| 197 | +static void trace_events_free(struct trace_events *events) | |
| 198 | +{ | |
| 199 | + struct trace_events *tevent = events; | |
| 200 | + struct trace_events *free_event; | |
| 201 | + | |
| 202 | + while (tevent) { | |
| 203 | + free_event = tevent; | |
| 204 | + | |
| 205 | + tevent = tevent->next; | |
| 206 | + | |
| 207 | + if (free_event->filter) | |
| 208 | + free(free_event->filter); | |
| 209 | + if (free_event->trigger) | |
| 210 | + free(free_event->trigger); | |
| 211 | + free(free_event->system); | |
| 212 | + free(free_event); | |
| 213 | + } | |
| 214 | +} | |
| 215 | + | |
| 216 | +/* | |
| 217 | + * trace_event_alloc - alloc and parse a single trace event | |
| 218 | + */ | |
| 219 | +struct trace_events *trace_event_alloc(const char *event_string) | |
| 220 | +{ | |
| 221 | + struct trace_events *tevent; | |
| 222 | + | |
| 223 | + tevent = calloc(1, sizeof(*tevent)); | |
| 224 | + if (!tevent) | |
| 225 | + return NULL; | |
| 226 | + | |
| 227 | + tevent->system = strdup(event_string); | |
| 228 | + if (!tevent->system) { | |
| 229 | + free(tevent); | |
| 230 | + return NULL; | |
| 231 | + } | |
| 232 | + | |
| 233 | + tevent->event = strstr(tevent->system, ":"); | |
| 234 | + if (tevent->event) { | |
| 235 | + *tevent->event = '\0'; | |
| 236 | + tevent->event = &tevent->event[1]; | |
| 237 | + } | |
| 238 | + | |
| 239 | + return tevent; | |
| 240 | +} | |
| 241 | + | |
| 242 | +/* | |
| 243 | + * trace_event_add_filter - record an event filter | |
| 244 | + */ | |
| 245 | +int trace_event_add_filter(struct trace_events *event, char *filter) | |
| 246 | +{ | |
| 247 | + if (event->filter) | |
| 248 | + free(event->filter); | |
| 249 | + | |
| 250 | + event->filter = strdup(filter); | |
| 251 | + if (!event->filter) | |
| 252 | + return 1; | |
| 253 | + | |
| 254 | + return 0; | |
| 255 | +} | |
| 256 | + | |
| 257 | +/* | |
| 258 | + * trace_event_add_trigger - record an event trigger action | |
| 259 | + */ | |
| 260 | +int trace_event_add_trigger(struct trace_events *event, char *trigger) | |
| 261 | +{ | |
| 262 | + if (event->trigger) | |
| 263 | + free(event->trigger); | |
| 264 | + | |
| 265 | + event->trigger = strdup(trigger); | |
| 266 | + if (!event->trigger) | |
| 267 | + return 1; | |
| 268 | + | |
| 269 | + return 0; | |
| 270 | +} | |
| 271 | + | |
| 272 | +/* | |
| 273 | + * trace_event_disable_filter - disable an event filter | |
| 274 | + */ | |
| 275 | +static void trace_event_disable_filter(struct trace_instance *instance, | |
| 276 | + struct trace_events *tevent) | |
| 277 | +{ | |
| 278 | + char filter[1024]; | |
| 279 | + int retval; | |
| 280 | + | |
| 281 | + if (!tevent->filter) | |
| 282 | + return; | |
| 283 | + | |
| 284 | + if (!tevent->filter_enabled) | |
| 285 | + return; | |
| 286 | + | |
| 287 | + debug_msg("Disabling %s:%s filter %s\n", tevent->system, | |
| 288 | + tevent->event ? : "*", tevent->filter); | |
| 289 | + | |
| 290 | + snprintf(filter, 1024, "!%s\n", tevent->filter); | |
| 291 | + | |
| 292 | + retval = tracefs_event_file_write(instance->inst, tevent->system, | |
| 293 | + tevent->event, "filter", filter); | |
| 294 | + if (retval < 0) | |
| 295 | + err_msg("Error disabling %s:%s filter %s\n", tevent->system, | |
| 296 | + tevent->event ? : "*", tevent->filter); | |
| 297 | +} | |
| 298 | + | |
| 299 | +/* | |
| 300 | + * trace_event_save_hist - save the content of an event hist | |
| 301 | + * | |
| 302 | + * If the trigger is a hist: one, save the content of the hist file. | |
| 303 | + */ | |
| 304 | +static void trace_event_save_hist(struct trace_instance *instance, | |
| 305 | + struct trace_events *tevent) | |
| 306 | +{ | |
| 307 | + int retval, index, out_fd; | |
| 308 | + mode_t mode = 0644; | |
| 309 | + char path[1024]; | |
| 310 | + char *hist; | |
| 311 | + | |
| 312 | + if (!tevent) | |
| 313 | + return; | |
| 314 | + | |
| 315 | + /* trigger enables hist */ | |
| 316 | + if (!tevent->trigger) | |
| 317 | + return; | |
| 318 | + | |
| 319 | + /* is this a hist: trigger? */ | |
| 320 | + retval = strncmp(tevent->trigger, "hist:", strlen("hist:")); | |
| 321 | + if (retval) | |
| 322 | + return; | |
| 323 | + | |
| 324 | + snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event); | |
| 325 | + | |
| 326 | + printf(" Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path); | |
| 327 | + | |
| 328 | + out_fd = creat(path, mode); | |
| 329 | + if (out_fd < 0) { | |
| 330 | + err_msg(" Failed to create %s output file\n", path); | |
| 331 | + return; | |
| 332 | + } | |
| 333 | + | |
| 334 | + hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0); | |
| 335 | + if (!hist) { | |
| 336 | + err_msg(" Failed to read %s:%s hist file\n", tevent->system, tevent->event); | |
| 337 | + goto out_close; | |
| 338 | + } | |
| 339 | + | |
| 340 | + index = 0; | |
| 341 | + do { | |
| 342 | + index += write(out_fd, &hist[index], strlen(hist) - index); | |
| 343 | + } while (index < strlen(hist)); | |
| 344 | + | |
| 345 | + free(hist); | |
| 346 | +out_close: | |
| 347 | + close(out_fd); | |
| 348 | +} | |
| 349 | + | |
| 350 | +/* | |
| 351 | + * trace_event_disable_trigger - disable an event trigger | |
| 352 | + */ | |
| 353 | +static void trace_event_disable_trigger(struct trace_instance *instance, | |
| 354 | + struct trace_events *tevent) | |
| 355 | +{ | |
| 356 | + char trigger[1024]; | |
| 357 | + int retval; | |
| 358 | + | |
| 359 | + if (!tevent->trigger) | |
| 360 | + return; | |
| 361 | + | |
| 362 | + if (!tevent->trigger_enabled) | |
| 363 | + return; | |
| 364 | + | |
| 365 | + debug_msg("Disabling %s:%s trigger %s\n", tevent->system, | |
| 366 | + tevent->event ? : "*", tevent->trigger); | |
| 367 | + | |
| 368 | + trace_event_save_hist(instance, tevent); | |
| 369 | + | |
| 370 | + snprintf(trigger, 1024, "!%s\n", tevent->trigger); | |
| 371 | + | |
| 372 | + retval = tracefs_event_file_write(instance->inst, tevent->system, | |
| 373 | + tevent->event, "trigger", trigger); | |
| 374 | + if (retval < 0) | |
| 375 | + err_msg("Error disabling %s:%s trigger %s\n", tevent->system, | |
| 376 | + tevent->event ? : "*", tevent->trigger); | |
| 377 | +} | |
| 378 | + | |
| 379 | +/* | |
| 380 | + * trace_events_disable - disable all trace events | |
| 381 | + */ | |
| 382 | +void trace_events_disable(struct trace_instance *instance, | |
| 383 | + struct trace_events *events) | |
| 384 | +{ | |
| 385 | + struct trace_events *tevent = events; | |
| 386 | + | |
| 387 | + if (!events) | |
| 388 | + return; | |
| 389 | + | |
| 390 | + while (tevent) { | |
| 391 | + debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*"); | |
| 392 | + if (tevent->enabled) { | |
| 393 | + trace_event_disable_filter(instance, tevent); | |
| 394 | + trace_event_disable_trigger(instance, tevent); | |
| 395 | + tracefs_event_disable(instance->inst, tevent->system, tevent->event); | |
| 396 | + } | |
| 397 | + | |
| 398 | + tevent->enabled = 0; | |
| 399 | + tevent = tevent->next; | |
| 400 | + } | |
| 401 | +} | |
| 402 | + | |
| 403 | +/* | |
| 404 | + * trace_event_enable_filter - enable an event filter associated with an event | |
| 405 | + */ | |
| 406 | +static int trace_event_enable_filter(struct trace_instance *instance, | |
| 407 | + struct trace_events *tevent) | |
| 408 | +{ | |
| 409 | + char filter[1024]; | |
| 410 | + int retval; | |
| 411 | + | |
| 412 | + if (!tevent->filter) | |
| 413 | + return 0; | |
| 414 | + | |
| 415 | + if (!tevent->event) { | |
| 416 | + err_msg("Filter %s applies only for single events, not for all %s:* events\n", | |
| 417 | + tevent->filter, tevent->system); | |
| 418 | + return 1; | |
| 419 | + } | |
| 420 | + | |
| 421 | + snprintf(filter, 1024, "%s\n", tevent->filter); | |
| 422 | + | |
| 423 | + debug_msg("Enabling %s:%s filter %s\n", tevent->system, | |
| 424 | + tevent->event ? : "*", tevent->filter); | |
| 425 | + | |
| 426 | + retval = tracefs_event_file_write(instance->inst, tevent->system, | |
| 427 | + tevent->event, "filter", filter); | |
| 428 | + if (retval < 0) { | |
| 429 | + err_msg("Error enabling %s:%s filter %s\n", tevent->system, | |
| 430 | + tevent->event ? : "*", tevent->filter); | |
| 431 | + return 1; | |
| 432 | + } | |
| 433 | + | |
| 434 | + tevent->filter_enabled = 1; | |
| 435 | + return 0; | |
| 436 | +} | |
| 437 | + | |
| 438 | +/* | |
| 439 | + * trace_event_enable_trigger - enable an event trigger associated with an event | |
| 440 | + */ | |
| 441 | +static int trace_event_enable_trigger(struct trace_instance *instance, | |
| 442 | + struct trace_events *tevent) | |
| 443 | +{ | |
| 444 | + char trigger[1024]; | |
| 445 | + int retval; | |
| 446 | + | |
| 447 | + if (!tevent->trigger) | |
| 448 | + return 0; | |
| 449 | + | |
| 450 | + if (!tevent->event) { | |
| 451 | + err_msg("Trigger %s applies only for single events, not for all %s:* events\n", | |
| 452 | + tevent->trigger, tevent->system); | |
| 453 | + return 1; | |
| 454 | + } | |
| 455 | + | |
| 456 | + snprintf(trigger, 1024, "%s\n", tevent->trigger); | |
| 457 | + | |
| 458 | + debug_msg("Enabling %s:%s trigger %s\n", tevent->system, | |
| 459 | + tevent->event ? : "*", tevent->trigger); | |
| 460 | + | |
| 461 | + retval = tracefs_event_file_write(instance->inst, tevent->system, | |
| 462 | + tevent->event, "trigger", trigger); | |
| 463 | + if (retval < 0) { | |
| 464 | + err_msg("Error enabling %s:%s trigger %s\n", tevent->system, | |
| 465 | + tevent->event ? : "*", tevent->trigger); | |
| 466 | + return 1; | |
| 467 | + } | |
| 468 | + | |
| 469 | + tevent->trigger_enabled = 1; | |
| 470 | + | |
| 471 | + return 0; | |
| 472 | +} | |
| 473 | + | |
| 474 | +/* | |
| 475 | + * trace_events_enable - enable all events | |
| 476 | + */ | |
| 477 | +int trace_events_enable(struct trace_instance *instance, | |
| 478 | + struct trace_events *events) | |
| 479 | +{ | |
| 480 | + struct trace_events *tevent = events; | |
| 481 | + int retval; | |
| 482 | + | |
| 483 | + while (tevent) { | |
| 484 | + debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*"); | |
| 485 | + retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event); | |
| 486 | + if (retval < 0) { | |
| 487 | + err_msg("Error enabling event %s:%s\n", tevent->system, | |
| 488 | + tevent->event ? : "*"); | |
| 489 | + return 1; | |
| 490 | + } | |
| 491 | + | |
| 492 | + retval = trace_event_enable_filter(instance, tevent); | |
| 493 | + if (retval) | |
| 494 | + return 1; | |
| 495 | + | |
| 496 | + retval = trace_event_enable_trigger(instance, tevent); | |
| 497 | + if (retval) | |
| 498 | + return 1; | |
| 499 | + | |
| 500 | + tevent->enabled = 1; | |
| 501 | + tevent = tevent->next; | |
| 502 | + } | |
| 503 | + | |
| 504 | + return 0; | |
| 505 | +} | |
| 506 | + | |
| 507 | +/* | |
| 508 | + * trace_events_destroy - disable and free all trace events | |
| 509 | + */ | |
| 510 | +void trace_events_destroy(struct trace_instance *instance, | |
| 511 | + struct trace_events *events) | |
| 512 | +{ | |
| 513 | + if (!events) | |
| 514 | + return; | |
| 515 | + | |
| 516 | + trace_events_disable(instance, events); | |
| 517 | + trace_events_free(events); | |
| 518 | +} | |
| 519 | + | |
| 520 | +int trace_is_off(struct trace_instance *tool, struct trace_instance *trace) | |
| 521 | +{ | |
| 522 | + /* | |
| 523 | + * The tool instance is always present, it is the one used to collect | |
| 524 | + * data. | |
| 525 | + */ | |
| 526 | + if (!tracefs_trace_is_on(tool->inst)) | |
| 527 | + return 1; | |
| 528 | + | |
| 529 | + /* | |
| 530 | + * The trace instance is only enabled when -t is set. IOW, when the system | |
| 531 | + * is tracing. | |
| 532 | + */ | |
| 533 | + if (trace && !tracefs_trace_is_on(trace->inst)) | |
| 534 | + return 1; | |
| 535 | + | |
| 536 | + return 0; | |
| 537 | +} | |
| @@ -2,6 +2,17 @@ · 1 unmodified line | ||
| 2 | 2 | #include <tracefs.h> |
| 3 | 3 | #include <stddef.h> |
| 4 | 4 | |
| 5 | +struct trace_events { | |
| 6 | + struct trace_events *next; | |
| 7 | + char *system; | |
| 8 | + char *event; | |
| 9 | + char *filter; | |
| 10 | + char *trigger; | |
| 11 | + char enabled; | |
| 12 | + char filter_enabled; | |
| 13 | + char trigger_enabled; | |
| 14 | +}; | |
| 15 | + | |
| 5 | 16 | struct trace_instance { |
| 6 | 17 | struct tracefs_instance *inst; |
| 7 | 18 | struct tep_handle *tep; |
| @@ -25,3 +36,15 @@ void destroy_instance(struct tracefs_instance *inst); · 17 unmodified lines | ||
| 25 | 36 | int save_trace_to_file(struct tracefs_instance *inst, const char *filename); |
| 26 | 37 | int collect_registered_events(struct tep_event *tep, struct tep_record *record, |
| 27 | 38 | int cpu, void *context); |
| 39 | + | |
| 40 | +struct trace_events *trace_event_alloc(const char *event_string); | |
| 41 | +void trace_events_disable(struct trace_instance *instance, | |
| 42 | + struct trace_events *events); | |
| 43 | +void trace_events_destroy(struct trace_instance *instance, | |
| 44 | + struct trace_events *events); | |
| 45 | +int trace_events_enable(struct trace_instance *instance, | |
| 46 | + struct trace_events *events); | |
| 47 | + | |
| 48 | +int trace_event_add_filter(struct trace_events *event, char *filter); | |
| 49 | +int trace_event_add_trigger(struct trace_events *event, char *trigger); | |
| 50 | +int trace_is_off(struct trace_instance *tool, struct trace_instance *trace); | |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <unistd.h> |
| 11 | 11 | #include <ctype.h> |
| 12 | 12 | #include <errno.h> |
| 13 | +#include <fcntl.h> | |
| 13 | 14 | #include <sched.h> |
| 14 | 15 | #include <stdio.h> |
| 15 | 16 | |
| @@ -431,3 +432,35 @@ int parse_prio(char *arg, struct sched_attr *sched_param) · 415 unmodified lines | ||
| 431 | 432 | } |
| 432 | 433 | return 0; |
| 433 | 434 | } |
| 435 | + | |
| 436 | +/* | |
| 437 | + * set_cpu_dma_latency - set the /dev/cpu_dma_latecy | |
| 438 | + * | |
| 439 | + * This is used to reduce the exit from idle latency. The value | |
| 440 | + * will be reset once the file descriptor of /dev/cpu_dma_latecy | |
| 441 | + * is closed. | |
| 442 | + * | |
| 443 | + * Return: the /dev/cpu_dma_latecy file descriptor | |
| 444 | + */ | |
| 445 | +int set_cpu_dma_latency(int32_t latency) | |
| 446 | +{ | |
| 447 | + int retval; | |
| 448 | + int fd; | |
| 449 | + | |
| 450 | + fd = open("/dev/cpu_dma_latency", O_RDWR); | |
| 451 | + if (fd < 0) { | |
| 452 | + err_msg("Error opening /dev/cpu_dma_latency\n"); | |
| 453 | + return -1; | |
| 454 | + } | |
| 455 | + | |
| 456 | + retval = write(fd, &latency, 4); | |
| 457 | + if (retval < 1) { | |
| 458 | + err_msg("Error setting /dev/cpu_dma_latency\n"); | |
| 459 | + close(fd); | |
| 460 | + return -1; | |
| 461 | + } | |
| 462 | + | |
| 463 | + debug_msg("Set /dev/cpu_dma_latency to %d\n", latency); | |
| 464 | + | |
| 465 | + return fd; | |
| 466 | +} | |
| @@ -54,3 +54,4 @@ struct sched_attr { · 53 unmodified lines | ||
| 54 | 54 | |
| 55 | 55 | int parse_prio(char *arg, struct sched_attr *sched_param); |
| 56 | 56 | int set_comm_sched_attr(const char *comm, struct sched_attr *attr); |
| 57 | +int set_cpu_dma_latency(int32_t latency); | |