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 | Save the stopped trace to [*file|osnoise_trace.txt*]. | 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 | **-P**, **--priority** *o:prio|r:prio|f:prio|d:runtime:period* | 36 | **-P**, **--priority** *o:prio|r:prio|f:prio|d:runtime:period* |
| 18 | 37 | ||
| 19 | Set scheduling parameters to the osnoise tracer threads, the format to set the priority are: | 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 | **-p**, **--period** *us* | 6 | **-p**, **--period** *us* |
| 2 | 7 | ||
| 3 | Set the *osnoise* tracer period in microseconds. | 8 | Set the *osnoise* tracer period in microseconds. |
| @@ -15,3 +20,8 @@ · 11 unmodified lines | |||
| 15 | 20 | ||
| 16 | Stop the trace if the total sample is higher than the argument in microseconds. | 21 | Stop the trace if the total sample is higher than the argument in microseconds. |
| 17 | If **-T** is set, it will also save the trace to the output. | 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 | **-p**, **--period** *us* | 8 | **-p**, **--period** *us* |
| 2 | 9 | ||
| 3 | Set the *timerlat* tracer period in microseconds. | 10 | Set the *timerlat* tracer period in microseconds. |
| @@ -14,3 +21,8 @@ · 10 unmodified lines | |||
| 14 | 21 | ||
| 15 | Save the stack trace at the *IRQ* if a *Thread* latency is higher than the | 22 | Save the stack trace at the *IRQ* if a *Thread* latency is higher than the |
| 16 | argument in us. | 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 | context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; | 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 | * enable_osnoise - enable osnoise tracer in the trace_instance | 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 | context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; | 795 | context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; |
| 717 | context->print_stack = OSNOISE_OPTION_INIT_VAL; | 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 | osnoise_get_context(context); | 801 | osnoise_get_context(context); |
| 720 | 802 | ||
| 721 | return context; | 803 | return context; |
| @@ -741,6 +823,7 @@ void osnoise_put_context(struct osnoise_context *context) · 19 unmodified lines | |||
| 741 | osnoise_put_stop_total_us(context); | 823 | osnoise_put_stop_total_us(context); |
| 742 | osnoise_put_timerlat_period_us(context); | 824 | osnoise_put_timerlat_period_us(context); |
| 743 | osnoise_put_print_stack(context); | 825 | osnoise_put_print_stack(context); |
| 826 | osnoise_put_tracing_thresh(context); | ||
| 744 | 827 | ||
| 745 | free(context); | 828 | free(context); |
| 746 | } | 829 | } |
| @@ -23,6 +23,10 @@ struct osnoise_context { · 22 unmodified lines | |||
| 23 | long long orig_timerlat_period_us; | 23 | long long orig_timerlat_period_us; |
| 24 | long long timerlat_period_us; | 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 | /* -1 as init value because 0 is disabled */ | 30 | /* -1 as init value because 0 is disabled */ |
| 27 | long long orig_stop_us; | 31 | long long orig_stop_us; |
| 28 | long long stop_us; | 32 | long long stop_us; |
| @@ -67,6 +71,10 @@ int osnoise_set_timerlat_period_us(struct osnoise_context *context, · 38 unmodified lines | |||
| 67 | long long timerlat_period_us); | 71 | long long timerlat_period_us); |
| 68 | void osnoise_restore_timerlat_period_us(struct osnoise_context *context); | 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 | void osnoise_restore_print_stack(struct osnoise_context *context); | 78 | void osnoise_restore_print_stack(struct osnoise_context *context); |
| 71 | int osnoise_set_print_stack(struct osnoise_context *context, | 79 | int osnoise_set_print_stack(struct osnoise_context *context, |
| 72 | long long print_stack); | 80 | long long print_stack); |
| @@ -21,6 +21,7 @@ struct osnoise_hist_params { · 20 unmodified lines | |||
| 21 | char *trace_output; | 21 | char *trace_output; |
| 22 | unsigned long long runtime; | 22 | unsigned long long runtime; |
| 23 | unsigned long long period; | 23 | unsigned long long period; |
| 24 | long long threshold; | ||
| 24 | long long stop_us; | 25 | long long stop_us; |
| 25 | long long stop_total_us; | 26 | long long stop_total_us; |
| 26 | int sleep_time; | 27 | int sleep_time; |
| @@ -28,6 +29,7 @@ struct osnoise_hist_params { · 1 unmodified line | |||
| 28 | int set_sched; | 29 | int set_sched; |
| 29 | int output_divisor; | 30 | int output_divisor; |
| 30 | struct sched_attr sched_param; | 31 | struct sched_attr sched_param; |
| 32 | struct trace_events *events; | ||
| 31 | 33 | ||
| 32 | char no_header; | 34 | char no_header; |
| 33 | char no_summary; | 35 | char no_summary; |
| @@ -425,19 +427,25 @@ static void osnoise_hist_usage(char *usage) · 391 unmodified lines | |||
| 425 | 427 | ||
| 426 | static const char * const msg[] = { | 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]] \\", | 430 | " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", |
| 429 | " [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\", | 431 | " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", |
| 430 | " [--no-index] [--with-zeros]", | 432 | " [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] [--no-index] \\", |
| 433 | " [--with-zeros]", | ||
| 431 | "", | 434 | "", |
| 432 | " -h/--help: print this menu", | 435 | " -h/--help: print this menu", |
| 436 | " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", | ||
| 433 | " -p/--period us: osnoise period in us", | 437 | " -p/--period us: osnoise period in us", |
| 434 | " -r/--runtime us: osnoise runtime in us", | 438 | " -r/--runtime us: osnoise runtime in us", |
| 435 | " -s/--stop us: stop trace if a single sample is higher than the argument in us", | 439 | " -s/--stop us: stop trace if a single sample is higher than the argument in us", |
| 436 | " -S/--stop-total us: stop trace if the total sample is higher than the argument in us", | 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 | " -c/--cpus cpu-list: list of cpus to run osnoise threads", | 442 | " -c/--cpus cpu-list: list of cpus to run osnoise threads", |
| 438 | " -d/--duration time[s|m|h|d]: duration of the session", | 443 | " -d/--duration time[s|m|h|d]: duration of the session", |
| 439 | " -D/--debug: print debug info", | 444 | " -D/--debug: print debug info", |
| 440 | " -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]", | 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 | " -b/--bucket-size N: set the histogram bucket size (default 1)", | 449 | " -b/--bucket-size N: set the histogram bucket size (default 1)", |
| 442 | " -E/--entries N: set the number of entries of the histogram (default 256)", | 450 | " -E/--entries N: set the number of entries of the histogram (default 256)", |
| 443 | " --no-header: do not print header", | 451 | " --no-header: do not print header", |
| @@ -471,6 +479,7 @@ static struct osnoise_hist_params · 27 unmodified lines | |||
| 471 | *osnoise_hist_parse_args(int argc, char *argv[]) | 479 | *osnoise_hist_parse_args(int argc, char *argv[]) |
| 472 | { | 480 | { |
| 473 | struct osnoise_hist_params *params; | 481 | struct osnoise_hist_params *params; |
| 482 | struct trace_events *tevent; | ||
| 474 | int retval; | 483 | int retval; |
| 475 | int c; | 484 | int c; |
| 476 | 485 | ||
| @@ -485,6 +494,7 @@ static struct osnoise_hist_params · 8 unmodified lines | |||
| 485 | 494 | ||
| 486 | while (1) { | 495 | while (1) { |
| 487 | static struct option long_options[] = { | 496 | static struct option long_options[] = { |
| 497 | {"auto", required_argument, 0, 'a'}, | ||
| 488 | {"bucket-size", required_argument, 0, 'b'}, | 498 | {"bucket-size", required_argument, 0, 'b'}, |
| 489 | {"entries", required_argument, 0, 'E'}, | 499 | {"entries", required_argument, 0, 'E'}, |
| 490 | {"cpus", required_argument, 0, 'c'}, | 500 | {"cpus", required_argument, 0, 'c'}, |
| @@ -497,17 +507,21 @@ static struct osnoise_hist_params · 6 unmodified lines | |||
| 497 | {"stop", required_argument, 0, 's'}, | 507 | {"stop", required_argument, 0, 's'}, |
| 498 | {"stop-total", required_argument, 0, 'S'}, | 508 | {"stop-total", required_argument, 0, 'S'}, |
| 499 | {"trace", optional_argument, 0, 't'}, | 509 | {"trace", optional_argument, 0, 't'}, |
| 510 | {"event", required_argument, 0, 'e'}, | ||
| 511 | {"threshold", required_argument, 0, 'T'}, | ||
| 500 | {"no-header", no_argument, 0, '0'}, | 512 | {"no-header", no_argument, 0, '0'}, |
| 501 | {"no-summary", no_argument, 0, '1'}, | 513 | {"no-summary", no_argument, 0, '1'}, |
| 502 | {"no-index", no_argument, 0, '2'}, | 514 | {"no-index", no_argument, 0, '2'}, |
| 503 | {"with-zeros", no_argument, 0, '3'}, | 515 | {"with-zeros", no_argument, 0, '3'}, |
| 516 | {"trigger", required_argument, 0, '4'}, | ||
| 517 | {"filter", required_argument, 0, '5'}, | ||
| 504 | {0, 0, 0, 0} | 518 | {0, 0, 0, 0} |
| 505 | }; | 519 | }; |
| 506 | 520 | ||
| 507 | /* getopt_long stores the option index here. */ | 521 | /* getopt_long stores the option index here. */ |
| 508 | int option_index = 0; | 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 | long_options, &option_index); | 525 | long_options, &option_index); |
| 512 | 526 | ||
| 513 | /* detect the end of the options. */ | 527 | /* detect the end of the options. */ |
| @@ -515,6 +529,17 @@ static struct osnoise_hist_params · 1 unmodified line | |||
| 515 | break; | 529 | break; |
| 516 | 530 | ||
| 517 | switch (c) { | 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 | case 'b': | 543 | case 'b': |
| 519 | params->bucket_size = get_llong_from_str(optarg); | 544 | params->bucket_size = get_llong_from_str(optarg); |
| 520 | if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) | 545 | if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) |
| @@ -534,6 +559,18 @@ static struct osnoise_hist_params · 13 unmodified lines | |||
| 534 | if (!params->duration) | 559 | if (!params->duration) |
| 535 | osnoise_hist_usage("Invalid -D duration\n"); | 560 | osnoise_hist_usage("Invalid -D duration\n"); |
| 536 | break; | 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 | case 'E': | 574 | case 'E': |
| 538 | params->entries = get_llong_from_str(optarg); | 575 | params->entries = get_llong_from_str(optarg); |
| 539 | if ((params->entries < 10) || (params->entries > 9999999)) | 576 | if ((params->entries < 10) || (params->entries > 9999999)) |
| @@ -565,6 +602,9 @@ static struct osnoise_hist_params · 25 unmodified lines | |||
| 565 | case 'S': | 602 | case 'S': |
| 566 | params->stop_total_us = get_llong_from_str(optarg); | 603 | params->stop_total_us = get_llong_from_str(optarg); |
| 567 | break; | 604 | break; |
| 605 | case 'T': | ||
| 606 | params->threshold = get_llong_from_str(optarg); | ||
| 607 | break; | ||
| 568 | case 't': | 608 | case 't': |
| 569 | if (optarg) | 609 | if (optarg) |
| 570 | /* skip = */ | 610 | /* skip = */ |
| @@ -584,6 +624,28 @@ static struct osnoise_hist_params · 13 unmodified lines | |||
| 584 | case '3': /* with zeros */ | 624 | case '3': /* with zeros */ |
| 585 | params->with_zeros = 1; | 625 | params->with_zeros = 1; |
| 586 | break; | 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 | default: | 649 | default: |
| 588 | osnoise_hist_usage("Invalid option"); | 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 | return 0; | 718 | return 0; |
| 649 | 719 | ||
| 650 | out_err: | 720 | out_err: |
| @@ -751,6 +821,13 @@ int osnoise_hist_main(int argc, char *argv[]) · 100 unmodified lines | |||
| 751 | err_msg("Failed to enable the trace instance\n"); | 821 | err_msg("Failed to enable the trace instance\n"); |
| 752 | goto out_hist; | 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 | trace_instance_start(&record->trace); | 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 | goto out_hist; | 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 | break; | 852 | break; |
| 776 | }; | 853 | } |
| 777 | 854 | ||
| 778 | osnoise_read_trace_hist(tool); | 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 | return_value = 0; | 859 | return_value = 0; |
| 783 | 860 | ||
| 784 | if (!tracefs_trace_is_on(trace->inst)) { | 861 | if (trace_is_off(&tool->trace, &record->trace)) { |
| 785 | printf("rtla timelat hit stop tracing\n"); | 862 | printf("rtla osnoise hit stop tracing\n"); |
| 786 | if (params->trace_output) { | 863 | if (params->trace_output) { |
| 787 | printf(" Saving trace to %s\n", params->trace_output); | 864 | printf(" Saving trace to %s\n", params->trace_output); |
| 788 | save_trace_to_file(record->trace.inst, params->trace_output); | 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 | out_hist: | 869 | out_hist: |
| 870 | trace_events_destroy(&record->trace, params->events); | ||
| 871 | params->events = NULL; | ||
| 793 | osnoise_free_histogram(tool->data); | 872 | osnoise_free_histogram(tool->data); |
| 794 | out_destroy: | 873 | out_destroy: |
| 795 | osnoise_destroy_tool(record); | 874 | osnoise_destroy_tool(record); |
| @@ -23,6 +23,7 @@ struct osnoise_top_params { · 22 unmodified lines | |||
| 23 | char *trace_output; | 23 | char *trace_output; |
| 24 | unsigned long long runtime; | 24 | unsigned long long runtime; |
| 25 | unsigned long long period; | 25 | unsigned long long period; |
| 26 | long long threshold; | ||
| 26 | long long stop_us; | 27 | long long stop_us; |
| 27 | long long stop_total_us; | 28 | long long stop_total_us; |
| 28 | int sleep_time; | 29 | int sleep_time; |
| @@ -30,6 +31,7 @@ struct osnoise_top_params { · 1 unmodified line | |||
| 30 | int quiet; | 31 | int quiet; |
| 31 | int set_sched; | 32 | int set_sched; |
| 32 | struct sched_attr sched_param; | 33 | struct sched_attr sched_param; |
| 34 | struct trace_events *events; | ||
| 33 | }; | 35 | }; |
| 34 | 36 | ||
| 35 | struct osnoise_top_cpu { | 37 | struct osnoise_top_cpu { |
| @@ -244,18 +246,24 @@ void osnoise_top_usage(char *usage) · 208 unmodified lines | |||
| 244 | int i; | 246 | int i; |
| 245 | 247 | ||
| 246 | static const char * const msg[] = { | 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 | " [-c cpu-list] [-P priority]", | 251 | " [-c cpu-list] [-P priority]", |
| 249 | "", | 252 | "", |
| 250 | " -h/--help: print this menu", | 253 | " -h/--help: print this menu", |
| 254 | " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", | ||
| 251 | " -p/--period us: osnoise period in us", | 255 | " -p/--period us: osnoise period in us", |
| 252 | " -r/--runtime us: osnoise runtime in us", | 256 | " -r/--runtime us: osnoise runtime in us", |
| 253 | " -s/--stop us: stop trace if a single sample is higher than the argument in us", | 257 | " -s/--stop us: stop trace if a single sample is higher than the argument in us", |
| 254 | " -S/--stop-total us: stop trace if the total sample is higher than the argument in us", | 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 | " -c/--cpus cpu-list: list of cpus to run osnoise threads", | 260 | " -c/--cpus cpu-list: list of cpus to run osnoise threads", |
| 256 | " -d/--duration time[s|m|h|d]: duration of the session", | 261 | " -d/--duration time[s|m|h|d]: duration of the session", |
| 257 | " -D/--debug: print debug info", | 262 | " -D/--debug: print debug info", |
| 258 | " -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]", | 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 | " -q/--quiet print only a summary at the end", | 267 | " -q/--quiet print only a summary at the end", |
| 260 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", | 268 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", |
| 261 | " o:prio - use SCHED_OTHER with prio", | 269 | " o:prio - use SCHED_OTHER with prio", |
| @@ -283,6 +291,7 @@ void osnoise_top_usage(char *usage) · 21 unmodified lines | |||
| 283 | struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) | 291 | struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) |
| 284 | { | 292 | { |
| 285 | struct osnoise_top_params *params; | 293 | struct osnoise_top_params *params; |
| 294 | struct trace_events *tevent; | ||
| 286 | int retval; | 295 | int retval; |
| 287 | int c; | 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 | while (1) { | 302 | while (1) { |
| 294 | static struct option long_options[] = { | 303 | static struct option long_options[] = { |
| 304 | {"auto", required_argument, 0, 'a'}, | ||
| 295 | {"cpus", required_argument, 0, 'c'}, | 305 | {"cpus", required_argument, 0, 'c'}, |
| 296 | {"debug", no_argument, 0, 'D'}, | 306 | {"debug", no_argument, 0, 'D'}, |
| 297 | {"duration", required_argument, 0, 'd'}, | 307 | {"duration", required_argument, 0, 'd'}, |
| 308 | {"event", required_argument, 0, 'e'}, | ||
| 298 | {"help", no_argument, 0, 'h'}, | 309 | {"help", no_argument, 0, 'h'}, |
| 299 | {"period", required_argument, 0, 'p'}, | 310 | {"period", required_argument, 0, 'p'}, |
| 300 | {"priority", required_argument, 0, 'P'}, | 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 | {"runtime", required_argument, 0, 'r'}, | 313 | {"runtime", required_argument, 0, 'r'}, |
| 303 | {"stop", required_argument, 0, 's'}, | 314 | {"stop", required_argument, 0, 's'}, |
| 304 | {"stop-total", required_argument, 0, 'S'}, | 315 | {"stop-total", required_argument, 0, 'S'}, |
| 316 | {"threshold", required_argument, 0, 'T'}, | ||
| 305 | {"trace", optional_argument, 0, 't'}, | 317 | {"trace", optional_argument, 0, 't'}, |
| 318 | {"trigger", required_argument, 0, '0'}, | ||
| 319 | {"filter", required_argument, 0, '1'}, | ||
| 306 | {0, 0, 0, 0} | 320 | {0, 0, 0, 0} |
| 307 | }; | 321 | }; |
| 308 | 322 | ||
| 309 | /* getopt_long stores the option index here. */ | 323 | /* getopt_long stores the option index here. */ |
| 310 | int option_index = 0; | 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 | long_options, &option_index); | 327 | long_options, &option_index); |
| 314 | 328 | ||
| 315 | /* Detect the end of the options. */ | 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 | break; | 331 | break; |
| 318 | 332 | ||
| 319 | switch (c) { | 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 | case 'c': | 345 | case 'c': |
| 321 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); | 346 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); |
| 322 | if (retval) | 347 | if (retval) |
| @@ -331,6 +356,18 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) · 8 unmodified lines | |||
| 331 | if (!params->duration) | 356 | if (!params->duration) |
| 332 | osnoise_top_usage("Invalid -D duration\n"); | 357 | osnoise_top_usage("Invalid -D duration\n"); |
| 333 | break; | 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 | case 'h': | 371 | case 'h': |
| 335 | case '?': | 372 | case '?': |
| 336 | osnoise_top_usage(NULL); | 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 | else | 404 | else |
| 368 | params->trace_output = "osnoise_trace.txt"; | 405 | params->trace_output = "osnoise_trace.txt"; |
| 369 | break; | 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 | default: | 432 | default: |
| 371 | osnoise_top_usage("Invalid option"); | 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 | return 0; | 498 | return 0; |
| 429 | 499 | ||
| 430 | out_err: | 500 | out_err: |
| @@ -529,13 +599,20 @@ int osnoise_top_main(int argc, char **argv) · 98 unmodified lines | |||
| 529 | err_msg("Failed to enable the trace instance\n"); | 599 | err_msg("Failed to enable the trace instance\n"); |
| 530 | goto out_top; | 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 | trace_instance_start(&record->trace); | 609 | trace_instance_start(&record->trace); |
| 533 | } | 610 | } |
| 534 | 611 | ||
| 535 | tool->start_time = time(NULL); | 612 | tool->start_time = time(NULL); |
| 536 | osnoise_top_set_signals(params); | 613 | osnoise_top_set_signals(params); |
| 537 | 614 | ||
| 538 | do { | 615 | while (!stop_tracing) { |
| 539 | sleep(params->sleep_time); | 616 | sleep(params->sleep_time); |
| 540 | 617 | ||
| 541 | retval = tracefs_iterate_raw_events(trace->tep, | 618 | retval = tracefs_iterate_raw_events(trace->tep, |
| @@ -552,16 +629,16 @@ int osnoise_top_main(int argc, char **argv) · 10 unmodified lines | |||
| 552 | if (!params->quiet) | 629 | if (!params->quiet) |
| 553 | osnoise_print_stats(params, tool); | 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 | break; | 633 | break; |
| 557 | 634 | ||
| 558 | } while (!stop_tracing); | 635 | } |
| 559 | 636 | ||
| 560 | osnoise_print_stats(params, tool); | 637 | osnoise_print_stats(params, tool); |
| 561 | 638 | ||
| 562 | return_value = 0; | 639 | return_value = 0; |
| 563 | 640 | ||
| 564 | if (!tracefs_trace_is_on(trace->inst)) { | 641 | if (trace_is_off(&tool->trace, &record->trace)) { |
| 565 | printf("osnoise hit stop tracing\n"); | 642 | printf("osnoise hit stop tracing\n"); |
| 566 | if (params->trace_output) { | 643 | if (params->trace_output) { |
| 567 | printf(" Saving trace to %s\n", params->trace_output); | 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 | out_top: | 649 | out_top: |
| 650 | trace_events_destroy(&record->trace, params->events); | ||
| 651 | params->events = NULL; | ||
| 573 | osnoise_free_top(tool->data); | 652 | osnoise_free_top(tool->data); |
| 574 | osnoise_destroy_tool(record); | 653 | osnoise_destroy_tool(record); |
| 575 | osnoise_destroy_tool(tool); | 654 | osnoise_destroy_tool(tool); |
| @@ -28,7 +28,9 @@ struct timerlat_hist_params { · 27 unmodified lines | |||
| 28 | int output_divisor; | 28 | int output_divisor; |
| 29 | int duration; | 29 | int duration; |
| 30 | int set_sched; | 30 | int set_sched; |
| 31 | int dma_latency; | ||
| 31 | struct sched_attr sched_param; | 32 | struct sched_attr sched_param; |
| 33 | struct trace_events *events; | ||
| 32 | 34 | ||
| 33 | char no_irq; | 35 | char no_irq; |
| 34 | char no_thread; | 36 | char no_thread; |
| @@ -428,11 +430,13 @@ static void timerlat_hist_usage(char *usage) · 393 unmodified lines | |||
| 428 | 430 | ||
| 429 | char *msg[] = { | 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]] \\", | 433 | " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\", |
| 432 | " [-c cpu-list] [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", | 434 | " [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] \\", |
| 433 | " [--no-index] [--with-zeros]", | 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 | " -h/--help: print this menu", | 438 | " -h/--help: print this menu", |
| 439 | " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", | ||
| 436 | " -p/--period us: timerlat period in us", | 440 | " -p/--period us: timerlat period in us", |
| 437 | " -i/--irq us: stop trace if the irq latency is higher than the argument in us", | 441 | " -i/--irq us: stop trace if the irq latency is higher than the argument in us", |
| 438 | " -T/--thread us: stop trace if the thread latency is higher than the argument in us", | 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 | " -c/--cpus cpus: run the tracer only on the given cpus", | 444 | " -c/--cpus cpus: run the tracer only on the given cpus", |
| 441 | " -d/--duration time[m|h|d]: duration of the session in seconds", | 445 | " -d/--duration time[m|h|d]: duration of the session in seconds", |
| 442 | " -D/--debug: print debug info", | 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 | " -n/--nano: display data in nanoseconds", | 451 | " -n/--nano: display data in nanoseconds", |
| 445 | " -b/--bucket-size N: set the histogram bucket size (default 1)", | 452 | " -b/--bucket-size N: set the histogram bucket size (default 1)", |
| 446 | " -E/--entries N: set the number of entries of the histogram (default 256)", | 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 | " --no-summary: do not print summary", | 457 | " --no-summary: do not print summary", |
| 451 | " --no-index: do not print index", | 458 | " --no-index: do not print index", |
| 452 | " --with-zeros: print zero only entries", | 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 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", | 461 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", |
| 454 | " o:prio - use SCHED_OTHER with prio", | 462 | " o:prio - use SCHED_OTHER with prio", |
| 455 | " r:prio - use SCHED_RR with prio", | 463 | " r:prio - use SCHED_RR with prio", |
| @@ -477,6 +485,8 @@ static struct timerlat_hist_params · 21 unmodified lines | |||
| 477 | *timerlat_hist_parse_args(int argc, char *argv[]) | 485 | *timerlat_hist_parse_args(int argc, char *argv[]) |
| 478 | { | 486 | { |
| 479 | struct timerlat_hist_params *params; | 487 | struct timerlat_hist_params *params; |
| 488 | struct trace_events *tevent; | ||
| 489 | int auto_thresh; | ||
| 480 | int retval; | 490 | int retval; |
| 481 | int c; | 491 | int c; |
| 482 | 492 | ||
| @@ -484,6 +494,9 @@ static struct timerlat_hist_params · 1 unmodified line | |||
| 484 | if (!params) | 494 | if (!params) |
| 485 | exit(1); | 495 | exit(1); |
| 486 | 496 | ||
| 497 | /* disabled by default */ | ||
| 498 | params->dma_latency = -1; | ||
| 499 | |||
| 487 | /* display data in microseconds */ | 500 | /* display data in microseconds */ |
| 488 | params->output_divisor = 1000; | 501 | params->output_divisor = 1000; |
| 489 | params->bucket_size = 1; | 502 | params->bucket_size = 1; |
| @@ -491,6 +504,7 @@ static struct timerlat_hist_params · 1 unmodified line | |||
| 491 | 504 | ||
| 492 | while (1) { | 505 | while (1) { |
| 493 | static struct option long_options[] = { | 506 | static struct option long_options[] = { |
| 507 | {"auto", required_argument, 0, 'a'}, | ||
| 494 | {"cpus", required_argument, 0, 'c'}, | 508 | {"cpus", required_argument, 0, 'c'}, |
| 495 | {"bucket-size", required_argument, 0, 'b'}, | 509 | {"bucket-size", required_argument, 0, 'b'}, |
| 496 | {"debug", no_argument, 0, 'D'}, | 510 | {"debug", no_argument, 0, 'D'}, |
| @@ -504,19 +518,23 @@ static struct timerlat_hist_params · 7 unmodified lines | |||
| 504 | {"stack", required_argument, 0, 's'}, | 518 | {"stack", required_argument, 0, 's'}, |
| 505 | {"thread", required_argument, 0, 'T'}, | 519 | {"thread", required_argument, 0, 'T'}, |
| 506 | {"trace", optional_argument, 0, 't'}, | 520 | {"trace", optional_argument, 0, 't'}, |
| 521 | {"event", required_argument, 0, 'e'}, | ||
| 507 | {"no-irq", no_argument, 0, '0'}, | 522 | {"no-irq", no_argument, 0, '0'}, |
| 508 | {"no-thread", no_argument, 0, '1'}, | 523 | {"no-thread", no_argument, 0, '1'}, |
| 509 | {"no-header", no_argument, 0, '2'}, | 524 | {"no-header", no_argument, 0, '2'}, |
| 510 | {"no-summary", no_argument, 0, '3'}, | 525 | {"no-summary", no_argument, 0, '3'}, |
| 511 | {"no-index", no_argument, 0, '4'}, | 526 | {"no-index", no_argument, 0, '4'}, |
| 512 | {"with-zeros", no_argument, 0, '5'}, | 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 | {0, 0, 0, 0} | 531 | {0, 0, 0, 0} |
| 514 | }; | 532 | }; |
| 515 | 533 | ||
| 516 | /* getopt_long stores the option index here. */ | 534 | /* getopt_long stores the option index here. */ |
| 517 | int option_index = 0; | 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 | long_options, &option_index); | 538 | long_options, &option_index); |
| 521 | 539 | ||
| 522 | /* detect the end of the options. */ | 540 | /* detect the end of the options. */ |
| @@ -524,6 +542,19 @@ static struct timerlat_hist_params · 1 unmodified line | |||
| 524 | break; | 542 | break; |
| 525 | 543 | ||
| 526 | switch (c) { | 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 | case 'c': | 558 | case 'c': |
| 528 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); | 559 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); |
| 529 | if (retval) | 560 | if (retval) |
| @@ -543,6 +574,18 @@ static struct timerlat_hist_params · 13 unmodified lines | |||
| 543 | if (!params->duration) | 574 | if (!params->duration) |
| 544 | timerlat_hist_usage("Invalid -D duration\n"); | 575 | timerlat_hist_usage("Invalid -D duration\n"); |
| 545 | break; | 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 | case 'E': | 589 | case 'E': |
| 547 | params->entries = get_llong_from_str(optarg); | 590 | params->entries = get_llong_from_str(optarg); |
| 548 | if ((params->entries < 10) || (params->entries > 9999999)) | 591 | if ((params->entries < 10) || (params->entries > 9999999)) |
| @@ -600,6 +643,35 @@ static struct timerlat_hist_params · 51 unmodified lines | |||
| 600 | case '5': /* with zeros */ | 643 | case '5': /* with zeros */ |
| 601 | params->with_zeros = 1; | 644 | params->with_zeros = 1; |
| 602 | break; | 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 | default: | 675 | default: |
| 604 | timerlat_hist_usage("Invalid option"); | 676 | timerlat_hist_usage("Invalid option"); |
| 605 | } | 677 | } |
| @@ -732,6 +804,7 @@ int timerlat_hist_main(int argc, char *argv[]) · 126 unmodified lines | |||
| 732 | struct osnoise_tool *record = NULL; | 804 | struct osnoise_tool *record = NULL; |
| 733 | struct osnoise_tool *tool = NULL; | 805 | struct osnoise_tool *tool = NULL; |
| 734 | struct trace_instance *trace; | 806 | struct trace_instance *trace; |
| 807 | int dma_latency_fd = -1; | ||
| 735 | int return_value = 1; | 808 | int return_value = 1; |
| 736 | int retval; | 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 | trace_instance_start(trace); | 851 | trace_instance_start(trace); |
| 771 | 852 | ||
| 772 | if (params->trace_output) { | 853 | if (params->trace_output) { |
| @@ -775,6 +856,13 @@ int timerlat_hist_main(int argc, char *argv[]) · 2 unmodified lines | |||
| 775 | err_msg("Failed to enable the trace instance\n"); | 856 | err_msg("Failed to enable the trace instance\n"); |
| 776 | goto out_hist; | 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 | trace_instance_start(&record->trace); | 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 | goto out_hist; | 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 | break; | 887 | break; |
| 800 | }; | 888 | } |
| 801 | 889 | ||
| 802 | timerlat_print_stats(params, tool); | 890 | timerlat_print_stats(params, tool); |
| 803 | 891 | ||
| 804 | return_value = 0; | 892 | return_value = 0; |
| 805 | 893 | ||
| 806 | if (!tracefs_trace_is_on(trace->inst)) { | 894 | if (trace_is_off(&tool->trace, &record->trace)) { |
| 807 | printf("rtla timelat hit stop tracing\n"); | 895 | printf("rtla timelat hit stop tracing\n"); |
| 808 | if (params->trace_output) { | 896 | if (params->trace_output) { |
| 809 | printf(" Saving trace to %s\n", params->trace_output); | 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 | out_hist: | 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 | timerlat_free_histogram(tool->data); | 907 | timerlat_free_histogram(tool->data); |
| 816 | osnoise_destroy_tool(record); | 908 | osnoise_destroy_tool(record); |
| 817 | osnoise_destroy_tool(tool); | 909 | osnoise_destroy_tool(tool); |
| @@ -29,7 +29,9 @@ struct timerlat_top_params { · 28 unmodified lines | |||
| 29 | int duration; | 29 | int duration; |
| 30 | int quiet; | 30 | int quiet; |
| 31 | int set_sched; | 31 | int set_sched; |
| 32 | int dma_latency; | ||
| 32 | struct sched_attr sched_param; | 33 | struct sched_attr sched_param; |
| 34 | struct trace_events *events; | ||
| 33 | }; | 35 | }; |
| 34 | 36 | ||
| 35 | struct timerlat_top_cpu { | 37 | struct timerlat_top_cpu { |
| @@ -266,10 +268,12 @@ static void timerlat_top_usage(char *usage) · 230 unmodified lines | |||
| 266 | 268 | ||
| 267 | static const char *const msg[] = { | 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]] \\", | 271 | " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\", |
| 270 | " [-c cpu-list] [-P priority]", | 272 | " [[-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] \\", |
| 273 | " [-P priority] [--dma-latency us]", | ||
| 271 | "", | 274 | "", |
| 272 | " -h/--help: print this menu", | 275 | " -h/--help: print this menu", |
| 276 | " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", | ||
| 273 | " -p/--period us: timerlat period in us", | 277 | " -p/--period us: timerlat period in us", |
| 274 | " -i/--irq us: stop trace if the irq latency is higher than the argument in us", | 278 | " -i/--irq us: stop trace if the irq latency is higher than the argument in us", |
| 275 | " -T/--thread us: stop trace if the thread latency is higher than the argument in us", | 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 | " -d/--duration time[m|h|d]: duration of the session in seconds", | 282 | " -d/--duration time[m|h|d]: duration of the session in seconds", |
| 279 | " -D/--debug: print debug info", | 283 | " -D/--debug: print debug info", |
| 280 | " -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]", | 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 | " -n/--nano: display data in nanoseconds", | 288 | " -n/--nano: display data in nanoseconds", |
| 282 | " -q/--quiet print only a summary at the end", | 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 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", | 291 | " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", |
| 284 | " o:prio - use SCHED_OTHER with prio", | 292 | " o:prio - use SCHED_OTHER with prio", |
| 285 | " r:prio - use SCHED_RR with prio", | 293 | " r:prio - use SCHED_RR with prio", |
| @@ -307,6 +315,8 @@ static struct timerlat_top_params · 21 unmodified lines | |||
| 307 | *timerlat_top_parse_args(int argc, char **argv) | 315 | *timerlat_top_parse_args(int argc, char **argv) |
| 308 | { | 316 | { |
| 309 | struct timerlat_top_params *params; | 317 | struct timerlat_top_params *params; |
| 318 | struct trace_events *tevent; | ||
| 319 | long long auto_thresh; | ||
| 310 | int retval; | 320 | int retval; |
| 311 | int c; | 321 | int c; |
| 312 | 322 | ||
| @@ -314,14 +324,19 @@ static struct timerlat_top_params · 1 unmodified line | |||
| 314 | if (!params) | 324 | if (!params) |
| 315 | exit(1); | 325 | exit(1); |
| 316 | 326 | ||
| 327 | /* disabled by default */ | ||
| 328 | params->dma_latency = -1; | ||
| 329 | |||
| 317 | /* display data in microseconds */ | 330 | /* display data in microseconds */ |
| 318 | params->output_divisor = 1000; | 331 | params->output_divisor = 1000; |
| 319 | 332 | ||
| 320 | while (1) { | 333 | while (1) { |
| 321 | static struct option long_options[] = { | 334 | static struct option long_options[] = { |
| 335 | {"auto", required_argument, 0, 'a'}, | ||
| 322 | {"cpus", required_argument, 0, 'c'}, | 336 | {"cpus", required_argument, 0, 'c'}, |
| 323 | {"debug", no_argument, 0, 'D'}, | 337 | {"debug", no_argument, 0, 'D'}, |
| 324 | {"duration", required_argument, 0, 'd'}, | 338 | {"duration", required_argument, 0, 'd'}, |
| 339 | {"event", required_argument, 0, 'e'}, | ||
| 325 | {"help", no_argument, 0, 'h'}, | 340 | {"help", no_argument, 0, 'h'}, |
| 326 | {"irq", required_argument, 0, 'i'}, | 341 | {"irq", required_argument, 0, 'i'}, |
| 327 | {"nano", no_argument, 0, 'n'}, | 342 | {"nano", no_argument, 0, 'n'}, |
| @@ -331,13 +346,16 @@ static struct timerlat_top_params · 3 unmodified lines | |||
| 331 | {"stack", required_argument, 0, 's'}, | 346 | {"stack", required_argument, 0, 's'}, |
| 332 | {"thread", required_argument, 0, 'T'}, | 347 | {"thread", required_argument, 0, 'T'}, |
| 333 | {"trace", optional_argument, 0, 't'}, | 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 | {0, 0, 0, 0} | 352 | {0, 0, 0, 0} |
| 335 | }; | 353 | }; |
| 336 | 354 | ||
| 337 | /* getopt_long stores the option index here. */ | 355 | /* getopt_long stores the option index here. */ |
| 338 | int option_index = 0; | 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 | long_options, &option_index); | 359 | long_options, &option_index); |
| 342 | 360 | ||
| 343 | /* detect the end of the options. */ | 361 | /* detect the end of the options. */ |
| @@ -345,6 +363,19 @@ static struct timerlat_top_params · 1 unmodified line | |||
| 345 | break; | 363 | break; |
| 346 | 364 | ||
| 347 | switch (c) { | 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 | case 'c': | 379 | case 'c': |
| 349 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); | 380 | retval = parse_cpu_list(optarg, ¶ms->monitored_cpus); |
| 350 | if (retval) | 381 | if (retval) |
| @@ -359,6 +390,17 @@ static struct timerlat_top_params · 8 unmodified lines | |||
| 359 | if (!params->duration) | 390 | if (!params->duration) |
| 360 | timerlat_top_usage("Invalid -D duration\n"); | 391 | timerlat_top_usage("Invalid -D duration\n"); |
| 361 | break; | 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 | case 'h': | 404 | case 'h': |
| 363 | case '?': | 405 | case '?': |
| 364 | timerlat_top_usage(NULL); | 406 | timerlat_top_usage(NULL); |
| @@ -396,6 +438,35 @@ static struct timerlat_top_params · 31 unmodified lines | |||
| 396 | else | 438 | else |
| 397 | params->trace_output = "timerlat_trace.txt"; | 439 | params->trace_output = "timerlat_trace.txt"; |
| 398 | break; | 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 | default: | 470 | default: |
| 400 | timerlat_top_usage("Invalid option"); | 471 | timerlat_top_usage("Invalid option"); |
| 401 | } | 472 | } |
| @@ -524,6 +595,7 @@ int timerlat_top_main(int argc, char *argv[]) · 122 unmodified lines | |||
| 524 | struct osnoise_tool *record = NULL; | 595 | struct osnoise_tool *record = NULL; |
| 525 | struct osnoise_tool *top = NULL; | 596 | struct osnoise_tool *top = NULL; |
| 526 | struct trace_instance *trace; | 597 | struct trace_instance *trace; |
| 598 | int dma_latency_fd = -1; | ||
| 527 | int return_value = 1; | 599 | int return_value = 1; |
| 528 | int retval; | 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 | trace_instance_start(trace); | 642 | trace_instance_start(trace); |
| 563 | 643 | ||
| 564 | if (params->trace_output) { | 644 | if (params->trace_output) { |
| @@ -567,6 +647,13 @@ int timerlat_top_main(int argc, char *argv[]) · 2 unmodified lines | |||
| 567 | err_msg("Failed to enable the trace instance\n"); | 647 | err_msg("Failed to enable the trace instance\n"); |
| 568 | goto out_top; | 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 | trace_instance_start(&record->trace); | 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 | if (!params->quiet) | 677 | if (!params->quiet) |
| 591 | timerlat_print_stats(params, top); | 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 | break; | 681 | break; |
| 595 | 682 | ||
| 596 | }; | 683 | } |
| 597 | 684 | ||
| 598 | timerlat_print_stats(params, top); | 685 | timerlat_print_stats(params, top); |
| 599 | 686 | ||
| 600 | return_value = 0; | 687 | return_value = 0; |
| 601 | 688 | ||
| 602 | if (!tracefs_trace_is_on(trace->inst)) { | 689 | if (trace_is_off(&top->trace, &record->trace)) { |
| 603 | printf("rtla timelat hit stop tracing\n"); | 690 | printf("rtla timelat hit stop tracing\n"); |
| 604 | if (params->trace_output) { | 691 | if (params->trace_output) { |
| 605 | printf(" Saving trace to %s\n", params->trace_output); | 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 | out_top: | 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 | timerlat_free_top(top->data); | 702 | timerlat_free_top(top->data); |
| 612 | osnoise_destroy_tool(record); | 703 | osnoise_destroy_tool(record); |
| 613 | osnoise_destroy_tool(top); | 704 | osnoise_destroy_tool(top); |
| @@ -190,3 +190,348 @@ int trace_instance_start(struct trace_instance *trace) · 189 unmodified lines | |||
| 190 | { | 190 | { |
| 191 | return tracefs_trace_on(trace->inst); | 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 | #include <tracefs.h> | 2 | #include <tracefs.h> |
| 3 | #include <stddef.h> | 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 | struct trace_instance { | 16 | struct trace_instance { |
| 6 | struct tracefs_instance *inst; | 17 | struct tracefs_instance *inst; |
| 7 | struct tep_handle *tep; | 18 | struct tep_handle *tep; |
| @@ -25,3 +36,15 @@ void destroy_instance(struct tracefs_instance *inst); · 17 unmodified lines | |||
| 25 | int save_trace_to_file(struct tracefs_instance *inst, const char *filename); | 36 | int save_trace_to_file(struct tracefs_instance *inst, const char *filename); |
| 26 | int collect_registered_events(struct tep_event *tep, struct tep_record *record, | 37 | int collect_registered_events(struct tep_event *tep, struct tep_record *record, |
| 27 | int cpu, void *context); | 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 | #include <unistd.h> | 10 | #include <unistd.h> |
| 11 | #include <ctype.h> | 11 | #include <ctype.h> |
| 12 | #include <errno.h> | 12 | #include <errno.h> |
| 13 | #include <fcntl.h> | ||
| 13 | #include <sched.h> | 14 | #include <sched.h> |
| 14 | #include <stdio.h> | 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 | return 0; | 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 | int parse_prio(char *arg, struct sched_attr *sched_param); | 55 | int parse_prio(char *arg, struct sched_attr *sched_param); |
| 56 | int set_comm_sched_attr(const char *comm, struct sched_attr *attr); | 56 | int set_comm_sched_attr(const char *comm, struct sched_attr *attr); |
| 57 | int set_cpu_dma_latency(int32_t latency); | ||