Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'trace-tools-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull rtla trace tooling updates from Steven Rostedt:

- Officially add Tomas Glozar as a maintainer to RTLA tool

- Add for_each_monitored_cpu() helper

In multiple places, RTLA tools iterate over the list of CPUs running
tracer threads.

Use single helper instead of repeating the for/if combination.

- Remove unused variable option_index in argument parsing

RTLA tools use getopt_long() for argument parsing. For its last
argument, an unused variable "option_index" is passed.

Remove the variable and pass NULL to getopt_long() to shorten the
naturally long parsing functions, and make them more readable.

- Fix unassigned nr_cpus after code consolidation

In recent code consolidation, timerlat tool cleanup, previously
implemented separately for each tool, was moved to a common function
timerlat_free().

The cleanup relies on nr_cpus being set. This was not done in the new
function, leaving the variable uninitialized.

Initialize the variable properly, and remove silencing of compiler
warning for uninitialized variables.

- Stop tracing on user latency in BPF mode

Despite the name, rtla-timerlat's -T/--thread option sets timerlat's
stop_tracing_total_us option, which also stops tracing on
return-from-user latency, not only on thread latency.

Implement the same behavior also in BPF sample collection stop
tracing handler to avoid a discrepancy and restore correspondence of
behavior with the equivalent option of cyclictest.

- Fix threshold actions always triggering

A bug in threshold action logic caused the action to execute even if
tracing did not stop because of threshold.

Fix the logic to stop correctly.

- Fix few minor issues in tests

Extend tests that were shown to need it to 5s, fix osnoise test
calling timerlat by mistake, and use new, more reliable output
checking in timerlat's "top stop at failed action" test.

- Do not print usage on argument parsing error

RTLA prints the entire usage message on encountering errors in
argument parsing, like a malformed CPU list.

The usage message has gotten too long. Instead of printing it, use
newly added fatal() helper function to simply exit with the error
message, excluding the usage.

- Fix unintuitive -C/--cgroup interface

"-C cgroup" and "--cgroup cgroup" are invalid syntax, despite that
being a common way to specify an option with argument. Moreover,
using them fails silently and no cgroup is set.

Create new helper function to unify the handling of all such options
and allow all of:

-Xsomething
-X=something
-X something

as well as the equivalent for the long option.

- Fix -a overriding -t argument filename

Fix a bug where -a following -t custom_file.txt overrides the custom
filename with the default timerlat_trace.txt.

- Stop tracing correctly on multiple events at once

In some race scenarios, RTLA BPF sample collection might send
multiple stop tracing events via the BPF ringbuffer at once.

Compare the number of events for != 0 instead of == 1 to cover for
this scenario and stop tracing properly.

* tag 'trace-tools-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
rtla/timerlat: Exit top main loop on any non-zero wait_retval
rtla/tests: Don't rely on matching ^1ALL
rtla: Fix -a overriding -t argument
rtla: Fix -C/--cgroup interface
tools/rtla: Replace osnoise_hist_usage("...") with fatal("...")
tools/rtla: Replace osnoise_top_usage("...") with fatal("...")
tools/rtla: Replace timerlat_hist_usage("...") with fatal("...")
tools/rtla: Replace timerlat_top_usage("...") with fatal("...")
tools/rtla: Add fatal() and replace error handling pattern
rtla/tests: Fix osnoise test calling timerlat
rtla/tests: Extend action tests to 5s
tools/rtla: Fix --on-threshold always triggering
rtla/timerlat_bpf: Stop tracing on user latency
tools/rtla: Fix unassigned nr_cpus
tools/rtla: Remove unused optional option_index
tools/rtla: Add for_each_monitored_cpu() helper
MAINTAINERS: Add Tomas Glozar as a maintainer to RTLA tool

+251 -373
+1 -1
Documentation/tools/rtla/common_options.txt
··· 48 48 49 49 If not set, tracer threads keep their default priority. For rtla user threads, it is set to SCHED_FIFO with priority 95. For kernel threads, see *osnoise* and *timerlat* tracer documentation for the running kernel version. 50 50 51 - **-C**, **--cgroup**\[*=cgroup*] 51 + **-C**, **--cgroup** \[*cgroup*] 52 52 53 53 Set a *cgroup* to the tracer's threads. If the **-C** option is passed without arguments, the tracer's thread will inherit **rtla**'s *cgroup*. Otherwise, the threads will be placed on the *cgroup* passed to the option. 54 54
+4
MAINTAINERS
··· 21802 21802 21803 21803 Real-time Linux Analysis (RTLA) tools 21804 21804 M: Steven Rostedt <rostedt@goodmis.org> 21805 + M: Tomas Glozar <tglozar@redhat.com> 21805 21806 L: linux-trace-kernel@vger.kernel.org 21807 + L: linux-kernel@vger.kernel.org 21806 21808 S: Maintained 21809 + Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ 21810 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git 21807 21811 F: Documentation/tools/rtla/ 21808 21812 F: tools/tracing/rtla/ 21809 21813
+1 -1
tools/tracing/rtla/Makefile.rtla
··· 18 18 FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ 19 19 -fasynchronous-unwind-tables -fstack-clash-protection 20 20 WOPTS := -O -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 \ 21 - -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized 21 + -Wp,-D_GLIBCXX_ASSERTIONS 22 22 23 23 ifeq ($(CC),clang) 24 24 FOPTS := $(filter-out -flto=auto -ffat-lto-objects, $(FOPTS))
+15 -9
tools/tracing/rtla/src/common.c
··· 268 268 tool->ops->print_stats(tool); 269 269 270 270 if (osnoise_trace_is_off(tool, record)) { 271 + if (stop_tracing) 272 + /* stop tracing requested, do not perform actions */ 273 + return 0; 274 + 271 275 actions_perform(&params->threshold_actions); 272 276 273 277 if (!params->threshold_actions.continue_flag) ··· 319 315 } 320 316 321 317 if (osnoise_trace_is_off(tool, tool->record)) { 318 + if (stop_tracing) 319 + /* stop tracing requested, do not perform actions */ 320 + break; 321 + 322 322 actions_perform(&params->threshold_actions); 323 323 324 - if (!params->threshold_actions.continue_flag) { 324 + if (!params->threshold_actions.continue_flag) 325 325 /* continue flag not set, break */ 326 326 break; 327 327 328 - /* continue action reached, re-enable tracing */ 329 - if (tool->record) 330 - trace_instance_start(&tool->record->trace); 331 - if (tool->aa) 332 - trace_instance_start(&tool->aa->trace); 333 - trace_instance_start(&tool->trace); 334 - } 335 - break; 328 + /* continue action reached, re-enable tracing */ 329 + if (tool->record) 330 + trace_instance_start(&tool->record->trace); 331 + if (tool->aa) 332 + trace_instance_start(&tool->aa->trace); 333 + trace_instance_start(&tool->trace); 336 334 } 337 335 338 336 /* is there still any user-threads ? */
+4
tools/tracing/rtla/src/common.h
··· 107 107 struct timerlat_u_params user; 108 108 }; 109 109 110 + #define for_each_monitored_cpu(cpu, nr_cpus, common) \ 111 + for (cpu = 0; cpu < nr_cpus; cpu++) \ 112 + if (!(common)->cpus || CPU_ISSET(cpu, &(common)->monitored_cpus)) 113 + 110 114 struct tool_ops; 111 115 112 116 /*
+44 -92
tools/tracing/rtla/src/osnoise_hist.c
··· 247 247 if (!params->common.hist.no_index) 248 248 trace_seq_printf(s, "Index"); 249 249 250 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 251 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 252 - continue; 250 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 253 251 254 252 if (!data->hist[cpu].count) 255 253 continue; ··· 276 278 if (!params->common.hist.no_index) 277 279 trace_seq_printf(trace->seq, "count:"); 278 280 279 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 280 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 281 - continue; 281 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 282 282 283 283 if (!data->hist[cpu].count) 284 284 continue; ··· 288 292 if (!params->common.hist.no_index) 289 293 trace_seq_printf(trace->seq, "min: "); 290 294 291 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 292 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 293 - continue; 295 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 294 296 295 297 if (!data->hist[cpu].count) 296 298 continue; ··· 301 307 if (!params->common.hist.no_index) 302 308 trace_seq_printf(trace->seq, "avg: "); 303 309 304 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 305 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 306 - continue; 310 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 307 311 308 312 if (!data->hist[cpu].count) 309 313 continue; ··· 317 325 if (!params->common.hist.no_index) 318 326 trace_seq_printf(trace->seq, "max: "); 319 327 320 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 321 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 322 - continue; 328 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 323 329 324 330 if (!data->hist[cpu].count) 325 331 continue; ··· 352 362 trace_seq_printf(trace->seq, "%-6d", 353 363 bucket * data->bucket_size); 354 364 355 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 356 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 357 - continue; 365 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 358 366 359 367 if (!data->hist[cpu].count) 360 368 continue; ··· 388 400 if (!params->common.hist.no_index) 389 401 trace_seq_printf(trace->seq, "over: "); 390 402 391 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 392 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 393 - continue; 403 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 394 404 395 405 if (!data->hist[cpu].count) 396 406 continue; ··· 407 421 /* 408 422 * osnoise_hist_usage - prints osnoise hist usage message 409 423 */ 410 - static void osnoise_hist_usage(char *usage) 424 + static void osnoise_hist_usage(void) 411 425 { 412 426 int i; 413 427 414 428 static const char * const msg[] = { 415 429 "", 416 430 " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", 417 - " [-T us] [-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", 431 + " [-T us] [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", 418 432 " [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\", 419 - " [--no-index] [--with-zeros] [-C[=cgroup_name]] [--warm-up]", 433 + " [--no-index] [--with-zeros] [-C [cgroup_name]] [--warm-up]", 420 434 "", 421 435 " -h/--help: print this menu", 422 436 " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", ··· 427 441 " -T/--threshold us: the minimum delta to be considered a noise", 428 442 " -c/--cpus cpu-list: list of cpus to run osnoise threads", 429 443 " -H/--house-keeping cpus: run rtla control threads only on the given cpus", 430 - " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 444 + " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 431 445 " -d/--duration time[s|m|h|d]: duration of the session", 432 446 " -D/--debug: print debug info", 433 - " -t/--trace[file]: save the stopped trace to [file|osnoise_trace.txt]", 447 + " -t/--trace [file]: save the stopped trace to [file|osnoise_trace.txt]", 434 448 " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", 435 449 " --filter <filter>: enable a trace event filter to the previous -e event", 436 450 " --trigger <trigger>: enable a trace event trigger to the previous -e event", ··· 453 467 NULL, 454 468 }; 455 469 456 - if (usage) 457 - fprintf(stderr, "%s\n", usage); 458 - 459 470 fprintf(stderr, "rtla osnoise hist: a per-cpu histogram of the OS noise (version %s)\n", 460 471 VERSION); 461 472 462 473 for (i = 0; msg[i]; i++) 463 474 fprintf(stderr, "%s\n", msg[i]); 464 - 465 - if (usage) 466 - exit(EXIT_FAILURE); 467 475 468 476 exit(EXIT_SUCCESS); 469 477 } ··· 518 538 {0, 0, 0, 0} 519 539 }; 520 540 521 - /* getopt_long stores the option index here. */ 522 - int option_index = 0; 523 - 524 541 c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:", 525 - long_options, &option_index); 542 + long_options, NULL); 526 543 527 544 /* detect the end of the options. */ 528 545 if (c == -1) ··· 534 557 params->threshold = 1; 535 558 536 559 /* set trace */ 537 - trace_output = "osnoise_trace.txt"; 560 + if (!trace_output) 561 + trace_output = "osnoise_trace.txt"; 538 562 539 563 break; 540 564 case 'b': 541 565 params->common.hist.bucket_size = get_llong_from_str(optarg); 542 566 if (params->common.hist.bucket_size == 0 || 543 567 params->common.hist.bucket_size >= 1000000) 544 - osnoise_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); 568 + fatal("Bucket size needs to be > 0 and <= 1000000"); 545 569 break; 546 570 case 'c': 547 571 retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 548 572 if (retval) 549 - osnoise_hist_usage("\nInvalid -c cpu list\n"); 573 + fatal("Invalid -c cpu list"); 550 574 params->common.cpus = optarg; 551 575 break; 552 576 case 'C': 553 577 params->common.cgroup = 1; 554 - if (!optarg) { 555 - /* will inherit this cgroup */ 556 - params->common.cgroup_name = NULL; 557 - } else if (*optarg == '=') { 558 - /* skip the = */ 559 - params->common.cgroup_name = ++optarg; 560 - } 578 + params->common.cgroup_name = parse_optional_arg(argc, argv); 561 579 break; 562 580 case 'D': 563 581 config_debug = 1; ··· 560 588 case 'd': 561 589 params->common.duration = parse_seconds_duration(optarg); 562 590 if (!params->common.duration) 563 - osnoise_hist_usage("Invalid -D duration\n"); 591 + fatal("Invalid -D duration"); 564 592 break; 565 593 case 'e': 566 594 tevent = trace_event_alloc(optarg); 567 - if (!tevent) { 568 - err_msg("Error alloc trace event"); 569 - exit(EXIT_FAILURE); 570 - } 595 + if (!tevent) 596 + fatal("Error alloc trace event"); 571 597 572 598 if (params->common.events) 573 599 tevent->next = params->common.events; ··· 576 606 params->common.hist.entries = get_llong_from_str(optarg); 577 607 if (params->common.hist.entries < 10 || 578 608 params->common.hist.entries > 9999999) 579 - osnoise_hist_usage("Entries must be > 10 and < 9999999\n"); 609 + fatal("Entries must be > 10 and < 9999999"); 580 610 break; 581 611 case 'h': 582 612 case '?': 583 - osnoise_hist_usage(NULL); 613 + osnoise_hist_usage(); 584 614 break; 585 615 case 'H': 586 616 params->common.hk_cpus = 1; 587 617 retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 588 - if (retval) { 589 - err_msg("Error parsing house keeping CPUs\n"); 590 - exit(EXIT_FAILURE); 591 - } 618 + if (retval) 619 + fatal("Error parsing house keeping CPUs"); 592 620 break; 593 621 case 'p': 594 622 params->period = get_llong_from_str(optarg); 595 623 if (params->period > 10000000) 596 - osnoise_hist_usage("Period longer than 10 s\n"); 624 + fatal("Period longer than 10 s"); 597 625 break; 598 626 case 'P': 599 627 retval = parse_prio(optarg, &params->common.sched_param); 600 628 if (retval == -1) 601 - osnoise_hist_usage("Invalid -P priority"); 629 + fatal("Invalid -P priority"); 602 630 params->common.set_sched = 1; 603 631 break; 604 632 case 'r': 605 633 params->runtime = get_llong_from_str(optarg); 606 634 if (params->runtime < 100) 607 - osnoise_hist_usage("Runtime shorter than 100 us\n"); 635 + fatal("Runtime shorter than 100 us"); 608 636 break; 609 637 case 's': 610 638 params->common.stop_us = get_llong_from_str(optarg); ··· 614 646 params->threshold = get_llong_from_str(optarg); 615 647 break; 616 648 case 't': 617 - if (optarg) { 618 - if (optarg[0] == '=') 619 - trace_output = &optarg[1]; 620 - else 621 - trace_output = &optarg[0]; 622 - } else if (optind < argc && argv[optind][0] != '0') 623 - trace_output = argv[optind]; 624 - else 649 + trace_output = parse_optional_arg(argc, argv); 650 + if (!trace_output) 625 651 trace_output = "osnoise_trace.txt"; 626 652 break; 627 653 case '0': /* no header */ ··· 633 671 case '4': /* trigger */ 634 672 if (params->common.events) { 635 673 retval = trace_event_add_trigger(params->common.events, optarg); 636 - if (retval) { 637 - err_msg("Error adding trigger %s\n", optarg); 638 - exit(EXIT_FAILURE); 639 - } 674 + if (retval) 675 + fatal("Error adding trigger %s", optarg); 640 676 } else { 641 - osnoise_hist_usage("--trigger requires a previous -e\n"); 677 + fatal("--trigger requires a previous -e"); 642 678 } 643 679 break; 644 680 case '5': /* filter */ 645 681 if (params->common.events) { 646 682 retval = trace_event_add_filter(params->common.events, optarg); 647 - if (retval) { 648 - err_msg("Error adding filter %s\n", optarg); 649 - exit(EXIT_FAILURE); 650 - } 683 + if (retval) 684 + fatal("Error adding filter %s", optarg); 651 685 } else { 652 - osnoise_hist_usage("--filter requires a previous -e\n"); 686 + fatal("--filter requires a previous -e"); 653 687 } 654 688 break; 655 689 case '6': ··· 657 699 case '8': 658 700 retval = actions_parse(&params->common.threshold_actions, optarg, 659 701 "osnoise_trace.txt"); 660 - if (retval) { 661 - err_msg("Invalid action %s\n", optarg); 662 - exit(EXIT_FAILURE); 663 - } 702 + if (retval) 703 + fatal("Invalid action %s", optarg); 664 704 break; 665 705 case '9': 666 706 retval = actions_parse(&params->common.end_actions, optarg, 667 707 "osnoise_trace.txt"); 668 - if (retval) { 669 - err_msg("Invalid action %s\n", optarg); 670 - exit(EXIT_FAILURE); 671 - } 708 + if (retval) 709 + fatal("Invalid action %s", optarg); 672 710 break; 673 711 default: 674 - osnoise_hist_usage("Invalid option"); 712 + fatal("Invalid option"); 675 713 } 676 714 } 677 715 678 716 if (trace_output) 679 717 actions_add_trace_output(&params->common.threshold_actions, trace_output); 680 718 681 - if (geteuid()) { 682 - err_msg("rtla needs root permission\n"); 683 - exit(EXIT_FAILURE); 684 - } 719 + if (geteuid()) 720 + fatal("rtla needs root permission"); 685 721 686 722 if (params->common.hist.no_index && !params->common.hist.with_zeros) 687 - osnoise_hist_usage("no-index set and with-zeros not set - it does not make sense"); 723 + fatal("no-index set and with-zeros not set - it does not make sense"); 688 724 689 725 return &params->common; 690 726 }
+35 -71
tools/tracing/rtla/src/osnoise_top.c
··· 243 243 244 244 osnoise_top_header(top); 245 245 246 - for (i = 0; i < nr_cpus; i++) { 247 - if (params->common.cpus && !CPU_ISSET(i, &params->common.monitored_cpus)) 248 - continue; 246 + for_each_monitored_cpu(i, nr_cpus, &params->common) { 249 247 osnoise_top_print(top, i); 250 248 } 251 249 ··· 255 257 /* 256 258 * osnoise_top_usage - prints osnoise top usage message 257 259 */ 258 - static void osnoise_top_usage(struct osnoise_params *params, char *usage) 260 + static void osnoise_top_usage(struct osnoise_params *params) 259 261 { 260 262 int i; 261 263 262 264 static const char * const msg[] = { 263 265 " [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", 264 - " [-T us] [-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", 265 - " [-c cpu-list] [-H cpu-list] [-P priority] [-C[=cgroup_name]] [--warm-up s]", 266 + " [-T us] [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", 267 + " [-c cpu-list] [-H cpu-list] [-P priority] [-C [cgroup_name]] [--warm-up s]", 266 268 "", 267 269 " -h/--help: print this menu", 268 270 " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", ··· 273 275 " -T/--threshold us: the minimum delta to be considered a noise", 274 276 " -c/--cpus cpu-list: list of cpus to run osnoise threads", 275 277 " -H/--house-keeping cpus: run rtla control threads only on the given cpus", 276 - " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 278 + " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 277 279 " -d/--duration time[s|m|h|d]: duration of the session", 278 280 " -D/--debug: print debug info", 279 - " -t/--trace[file]: save the stopped trace to [file|osnoise_trace.txt]", 281 + " -t/--trace [file]: save the stopped trace to [file|osnoise_trace.txt]", 280 282 " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", 281 283 " --filter <filter>: enable a trace event filter to the previous -e event", 282 284 " --trigger <trigger>: enable a trace event trigger to the previous -e event", ··· 293 295 " --on-end: define action to be executed at measurement end, multiple are allowed", 294 296 NULL, 295 297 }; 296 - 297 - if (usage) 298 - fprintf(stderr, "%s\n", usage); 299 298 300 299 if (params->mode == MODE_OSNOISE) { 301 300 fprintf(stderr, ··· 312 317 313 318 for (i = 0; msg[i]; i++) 314 319 fprintf(stderr, "%s\n", msg[i]); 315 - 316 - if (usage) 317 - exit(EXIT_FAILURE); 318 320 319 321 exit(EXIT_SUCCESS); 320 322 } ··· 370 378 {0, 0, 0, 0} 371 379 }; 372 380 373 - /* getopt_long stores the option index here. */ 374 - int option_index = 0; 375 - 376 381 c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:", 377 - long_options, &option_index); 382 + long_options, NULL); 378 383 379 384 /* Detect the end of the options. */ 380 385 if (c == -1) ··· 386 397 params->threshold = 1; 387 398 388 399 /* set trace */ 389 - trace_output = "osnoise_trace.txt"; 400 + if (!trace_output) 401 + trace_output = "osnoise_trace.txt"; 390 402 391 403 break; 392 404 case 'c': 393 405 retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 394 406 if (retval) 395 - osnoise_top_usage(params, "\nInvalid -c cpu list\n"); 407 + fatal("Invalid -c cpu list"); 396 408 params->common.cpus = optarg; 397 409 break; 398 410 case 'C': 399 411 params->common.cgroup = 1; 400 - if (!optarg) { 401 - /* will inherit this cgroup */ 402 - params->common.cgroup_name = NULL; 403 - } else if (*optarg == '=') { 404 - /* skip the = */ 405 - params->common.cgroup_name = ++optarg; 406 - } 412 + params->common.cgroup_name = parse_optional_arg(argc, argv); 407 413 break; 408 414 case 'D': 409 415 config_debug = 1; ··· 406 422 case 'd': 407 423 params->common.duration = parse_seconds_duration(optarg); 408 424 if (!params->common.duration) 409 - osnoise_top_usage(params, "Invalid -d duration\n"); 425 + fatal("Invalid -d duration"); 410 426 break; 411 427 case 'e': 412 428 tevent = trace_event_alloc(optarg); 413 - if (!tevent) { 414 - err_msg("Error alloc trace event"); 415 - exit(EXIT_FAILURE); 416 - } 429 + if (!tevent) 430 + fatal("Error alloc trace event"); 417 431 418 432 if (params->common.events) 419 433 tevent->next = params->common.events; ··· 420 438 break; 421 439 case 'h': 422 440 case '?': 423 - osnoise_top_usage(params, NULL); 441 + osnoise_top_usage(params); 424 442 break; 425 443 case 'H': 426 444 params->common.hk_cpus = 1; 427 445 retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 428 - if (retval) { 429 - err_msg("Error parsing house keeping CPUs\n"); 430 - exit(EXIT_FAILURE); 431 - } 446 + if (retval) 447 + fatal("Error parsing house keeping CPUs"); 432 448 break; 433 449 case 'p': 434 450 params->period = get_llong_from_str(optarg); 435 451 if (params->period > 10000000) 436 - osnoise_top_usage(params, "Period longer than 10 s\n"); 452 + fatal("Period longer than 10 s"); 437 453 break; 438 454 case 'P': 439 455 retval = parse_prio(optarg, &params->common.sched_param); 440 456 if (retval == -1) 441 - osnoise_top_usage(params, "Invalid -P priority"); 457 + fatal("Invalid -P priority"); 442 458 params->common.set_sched = 1; 443 459 break; 444 460 case 'q': ··· 445 465 case 'r': 446 466 params->runtime = get_llong_from_str(optarg); 447 467 if (params->runtime < 100) 448 - osnoise_top_usage(params, "Runtime shorter than 100 us\n"); 468 + fatal("Runtime shorter than 100 us"); 449 469 break; 450 470 case 's': 451 471 params->common.stop_us = get_llong_from_str(optarg); ··· 454 474 params->common.stop_total_us = get_llong_from_str(optarg); 455 475 break; 456 476 case 't': 457 - if (optarg) { 458 - if (optarg[0] == '=') 459 - trace_output = &optarg[1]; 460 - else 461 - trace_output = &optarg[0]; 462 - } else if (optind < argc && argv[optind][0] != '-') 463 - trace_output = argv[optind]; 464 - else 477 + trace_output = parse_optional_arg(argc, argv); 478 + if (!trace_output) 465 479 trace_output = "osnoise_trace.txt"; 466 480 break; 467 481 case 'T': ··· 464 490 case '0': /* trigger */ 465 491 if (params->common.events) { 466 492 retval = trace_event_add_trigger(params->common.events, optarg); 467 - if (retval) { 468 - err_msg("Error adding trigger %s\n", optarg); 469 - exit(EXIT_FAILURE); 470 - } 493 + if (retval) 494 + fatal("Error adding trigger %s", optarg); 471 495 } else { 472 - osnoise_top_usage(params, "--trigger requires a previous -e\n"); 496 + fatal("--trigger requires a previous -e"); 473 497 } 474 498 break; 475 499 case '1': /* filter */ 476 500 if (params->common.events) { 477 501 retval = trace_event_add_filter(params->common.events, optarg); 478 - if (retval) { 479 - err_msg("Error adding filter %s\n", optarg); 480 - exit(EXIT_FAILURE); 481 - } 502 + if (retval) 503 + fatal("Error adding filter %s", optarg); 482 504 } else { 483 - osnoise_top_usage(params, "--filter requires a previous -e\n"); 505 + fatal("--filter requires a previous -e"); 484 506 } 485 507 break; 486 508 case '2': ··· 488 518 case '4': 489 519 retval = actions_parse(&params->common.threshold_actions, optarg, 490 520 "osnoise_trace.txt"); 491 - if (retval) { 492 - err_msg("Invalid action %s\n", optarg); 493 - exit(EXIT_FAILURE); 494 - } 521 + if (retval) 522 + fatal("Invalid action %s", optarg); 495 523 break; 496 524 case '5': 497 525 retval = actions_parse(&params->common.end_actions, optarg, 498 526 "osnoise_trace.txt"); 499 - if (retval) { 500 - err_msg("Invalid action %s\n", optarg); 501 - exit(EXIT_FAILURE); 502 - } 527 + if (retval) 528 + fatal("Invalid action %s", optarg); 503 529 break; 504 530 default: 505 - osnoise_top_usage(params, "Invalid option"); 531 + fatal("Invalid option"); 506 532 } 507 533 } 508 534 509 535 if (trace_output) 510 536 actions_add_trace_output(&params->common.threshold_actions, trace_output); 511 537 512 - if (geteuid()) { 513 - err_msg("osnoise needs root permission\n"); 514 - exit(EXIT_FAILURE); 515 - } 538 + if (geteuid()) 539 + fatal("osnoise needs root permission"); 516 540 517 541 return &params->common; 518 542 }
+3
tools/tracing/rtla/src/timerlat.bpf.c
··· 148 148 } else { 149 149 update_main_hist(&hist_user, bucket); 150 150 update_summary(&summary_user, latency, bucket); 151 + 152 + if (thread_threshold != 0 && latency_us >= thread_threshold) 153 + set_stop_tracing(); 151 154 } 152 155 153 156 return 0;
+4 -8
tools/tracing/rtla/src/timerlat.c
··· 126 126 127 127 nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 128 128 129 - for (i = 0; i < nr_cpus; i++) { 130 - if (params->common.cpus && !CPU_ISSET(i, &params->common.monitored_cpus)) 131 - continue; 129 + for_each_monitored_cpu(i, nr_cpus, &params->common) { 132 130 if (save_cpu_idle_disable_state(i) < 0) { 133 131 err_msg("Could not save cpu idle state.\n"); 134 132 return -1; ··· 213 215 void timerlat_free(struct osnoise_tool *tool) 214 216 { 215 217 struct timerlat_params *params = to_timerlat_params(tool->params); 216 - int nr_cpus, i; 218 + int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 219 + int i; 217 220 218 221 timerlat_aa_destroy(); 219 222 if (dma_latency_fd >= 0) 220 223 close(dma_latency_fd); 221 224 if (params->deepest_idle_state >= -1) { 222 - for (i = 0; i < nr_cpus; i++) { 223 - if (params->common.cpus && 224 - !CPU_ISSET(i, &params->common.monitored_cpus)) 225 - continue; 225 + for_each_monitored_cpu(i, nr_cpus, &params->common) { 226 226 restore_cpu_idle_disable_state(i); 227 227 } 228 228 }
+48 -100
tools/tracing/rtla/src/timerlat_hist.c
··· 305 305 if (!params->common.hist.no_index) 306 306 trace_seq_printf(s, "Index"); 307 307 308 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 309 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 310 - continue; 308 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 311 309 312 310 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 313 311 continue; ··· 357 359 if (!params->common.hist.no_index) 358 360 trace_seq_printf(trace->seq, "count:"); 359 361 360 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 361 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 362 - continue; 362 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 363 363 364 364 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 365 365 continue; ··· 379 383 if (!params->common.hist.no_index) 380 384 trace_seq_printf(trace->seq, "min: "); 381 385 382 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 383 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 384 - continue; 386 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 385 387 386 388 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 387 389 continue; ··· 407 413 if (!params->common.hist.no_index) 408 414 trace_seq_printf(trace->seq, "avg: "); 409 415 410 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 411 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 412 - continue; 416 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 413 417 414 418 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 415 419 continue; ··· 435 443 if (!params->common.hist.no_index) 436 444 trace_seq_printf(trace->seq, "max: "); 437 445 438 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 439 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 440 - continue; 446 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 441 447 442 448 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 443 449 continue; ··· 480 490 sum.min_thread = ~0; 481 491 sum.min_user = ~0; 482 492 483 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 484 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 485 - continue; 493 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 486 494 487 495 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 488 496 continue; ··· 627 639 trace_seq_printf(trace->seq, "%-6d", 628 640 bucket * data->bucket_size); 629 641 630 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 631 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 632 - continue; 642 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 633 643 634 644 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 635 645 continue; ··· 665 679 if (!params->common.hist.no_index) 666 680 trace_seq_printf(trace->seq, "over: "); 667 681 668 - for (cpu = 0; cpu < data->nr_cpus; cpu++) { 669 - if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 670 - continue; 682 + for_each_monitored_cpu(cpu, data->nr_cpus, &params->common) { 671 683 672 684 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 673 685 continue; ··· 694 710 /* 695 711 * timerlat_hist_usage - prints timerlat top usage message 696 712 */ 697 - static void timerlat_hist_usage(char *usage) 713 + static void timerlat_hist_usage(void) 698 714 { 699 715 int i; 700 716 701 717 char *msg[] = { 702 718 "", 703 719 " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\", 704 - " [-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\", 720 + " [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\", 705 721 " [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", 706 - " [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u|-k]", 722 + " [--no-index] [--with-zeros] [--dma-latency us] [-C [cgroup_name]] [--no-aa] [--dump-task] [-u|-k]", 707 723 " [--warm-up s] [--deepest-idle-state n]", 708 724 "", 709 725 " -h/--help: print this menu", ··· 714 730 " -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us", 715 731 " -c/--cpus cpus: run the tracer only on the given cpus", 716 732 " -H/--house-keeping cpus: run rtla control threads only on the given cpus", 717 - " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 733 + " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 718 734 " -d/--duration time[m|h|d]: duration of the session in seconds", 719 735 " --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)", 720 736 " -D/--debug: print debug info", 721 - " -t/--trace[file]: save the stopped trace to [file|timerlat_trace.txt]", 737 + " -t/--trace [file]: save the stopped trace to [file|timerlat_trace.txt]", 722 738 " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", 723 739 " --filter <filter>: enable a trace event filter to the previous -e event", 724 740 " --trigger <trigger>: enable a trace event trigger to the previous -e event", ··· 750 766 NULL, 751 767 }; 752 768 753 - if (usage) 754 - fprintf(stderr, "%s\n", usage); 755 - 756 769 fprintf(stderr, "rtla timerlat hist: a per-cpu histogram of the timer latency (version %s)\n", 757 770 VERSION); 758 771 759 772 for (i = 0; msg[i]; i++) 760 773 fprintf(stderr, "%s\n", msg[i]); 761 - 762 - if (usage) 763 - exit(EXIT_FAILURE); 764 774 765 775 exit(EXIT_SUCCESS); 766 776 } ··· 834 856 {0, 0, 0, 0} 835 857 }; 836 858 837 - /* getopt_long stores the option index here. */ 838 - int option_index = 0; 839 - 840 859 c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", 841 - long_options, &option_index); 860 + long_options, NULL); 842 861 843 862 /* detect the end of the options. */ 844 863 if (c == -1) ··· 853 878 params->print_stack = auto_thresh; 854 879 855 880 /* set trace */ 856 - trace_output = "timerlat_trace.txt"; 881 + if (!trace_output) 882 + trace_output = "timerlat_trace.txt"; 857 883 858 884 break; 859 885 case 'c': 860 886 retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 861 887 if (retval) 862 - timerlat_hist_usage("\nInvalid -c cpu list\n"); 888 + fatal("Invalid -c cpu list"); 863 889 params->common.cpus = optarg; 864 890 break; 865 891 case 'C': 866 892 params->common.cgroup = 1; 867 - if (!optarg) { 868 - /* will inherit this cgroup */ 869 - params->common.cgroup_name = NULL; 870 - } else if (*optarg == '=') { 871 - /* skip the = */ 872 - params->common.cgroup_name = ++optarg; 873 - } 893 + params->common.cgroup_name = parse_optional_arg(argc, argv); 874 894 break; 875 895 case 'b': 876 896 params->common.hist.bucket_size = get_llong_from_str(optarg); 877 897 if (params->common.hist.bucket_size == 0 || 878 898 params->common.hist.bucket_size >= 1000000) 879 - timerlat_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); 899 + fatal("Bucket size needs to be > 0 and <= 1000000"); 880 900 break; 881 901 case 'D': 882 902 config_debug = 1; ··· 879 909 case 'd': 880 910 params->common.duration = parse_seconds_duration(optarg); 881 911 if (!params->common.duration) 882 - timerlat_hist_usage("Invalid -D duration\n"); 912 + fatal("Invalid -D duration"); 883 913 break; 884 914 case 'e': 885 915 tevent = trace_event_alloc(optarg); 886 - if (!tevent) { 887 - err_msg("Error alloc trace event"); 888 - exit(EXIT_FAILURE); 889 - } 916 + if (!tevent) 917 + fatal("Error alloc trace event"); 890 918 891 919 if (params->common.events) 892 920 tevent->next = params->common.events; ··· 895 927 params->common.hist.entries = get_llong_from_str(optarg); 896 928 if (params->common.hist.entries < 10 || 897 929 params->common.hist.entries > 9999999) 898 - timerlat_hist_usage("Entries must be > 10 and < 9999999\n"); 930 + fatal("Entries must be > 10 and < 9999999"); 899 931 break; 900 932 case 'h': 901 933 case '?': 902 - timerlat_hist_usage(NULL); 934 + timerlat_hist_usage(); 903 935 break; 904 936 case 'H': 905 937 params->common.hk_cpus = 1; 906 938 retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 907 - if (retval) { 908 - err_msg("Error parsing house keeping CPUs\n"); 909 - exit(EXIT_FAILURE); 910 - } 939 + if (retval) 940 + fatal("Error parsing house keeping CPUs"); 911 941 break; 912 942 case 'i': 913 943 params->common.stop_us = get_llong_from_str(optarg); ··· 919 953 case 'p': 920 954 params->timerlat_period_us = get_llong_from_str(optarg); 921 955 if (params->timerlat_period_us > 1000000) 922 - timerlat_hist_usage("Period longer than 1 s\n"); 956 + fatal("Period longer than 1 s"); 923 957 break; 924 958 case 'P': 925 959 retval = parse_prio(optarg, &params->common.sched_param); 926 960 if (retval == -1) 927 - timerlat_hist_usage("Invalid -P priority"); 961 + fatal("Invalid -P priority"); 928 962 params->common.set_sched = 1; 929 963 break; 930 964 case 's': ··· 934 968 params->common.stop_total_us = get_llong_from_str(optarg); 935 969 break; 936 970 case 't': 937 - if (optarg) { 938 - if (optarg[0] == '=') 939 - trace_output = &optarg[1]; 940 - else 941 - trace_output = &optarg[0]; 942 - } else if (optind < argc && argv[optind][0] != '-') 943 - trace_output = argv[optind]; 944 - else 971 + trace_output = parse_optional_arg(argc, argv); 972 + if (!trace_output) 945 973 trace_output = "timerlat_trace.txt"; 946 974 break; 947 975 case 'u': ··· 965 1005 case '6': /* trigger */ 966 1006 if (params->common.events) { 967 1007 retval = trace_event_add_trigger(params->common.events, optarg); 968 - if (retval) { 969 - err_msg("Error adding trigger %s\n", optarg); 970 - exit(EXIT_FAILURE); 971 - } 1008 + if (retval) 1009 + fatal("Error adding trigger %s", optarg); 972 1010 } else { 973 - timerlat_hist_usage("--trigger requires a previous -e\n"); 1011 + fatal("--trigger requires a previous -e"); 974 1012 } 975 1013 break; 976 1014 case '7': /* filter */ 977 1015 if (params->common.events) { 978 1016 retval = trace_event_add_filter(params->common.events, optarg); 979 - if (retval) { 980 - err_msg("Error adding filter %s\n", optarg); 981 - exit(EXIT_FAILURE); 982 - } 1017 + if (retval) 1018 + fatal("Error adding filter %s", optarg); 983 1019 } else { 984 - timerlat_hist_usage("--filter requires a previous -e\n"); 1020 + fatal("--filter requires a previous -e"); 985 1021 } 986 1022 break; 987 1023 case '8': 988 1024 params->dma_latency = get_llong_from_str(optarg); 989 - if (params->dma_latency < 0 || params->dma_latency > 10000) { 990 - err_msg("--dma-latency needs to be >= 0 and < 10000"); 991 - exit(EXIT_FAILURE); 992 - } 1025 + if (params->dma_latency < 0 || params->dma_latency > 10000) 1026 + fatal("--dma-latency needs to be >= 0 and < 10000"); 993 1027 break; 994 1028 case '9': 995 1029 params->no_aa = 1; ··· 1003 1049 case '\5': 1004 1050 retval = actions_parse(&params->common.threshold_actions, optarg, 1005 1051 "timerlat_trace.txt"); 1006 - if (retval) { 1007 - err_msg("Invalid action %s\n", optarg); 1008 - exit(EXIT_FAILURE); 1009 - } 1052 + if (retval) 1053 + fatal("Invalid action %s", optarg); 1010 1054 break; 1011 1055 case '\6': 1012 1056 retval = actions_parse(&params->common.end_actions, optarg, 1013 1057 "timerlat_trace.txt"); 1014 - if (retval) { 1015 - err_msg("Invalid action %s\n", optarg); 1016 - exit(EXIT_FAILURE); 1017 - } 1058 + if (retval) 1059 + fatal("Invalid action %s", optarg); 1018 1060 break; 1019 1061 default: 1020 - timerlat_hist_usage("Invalid option"); 1062 + fatal("Invalid option"); 1021 1063 } 1022 1064 } 1023 1065 1024 1066 if (trace_output) 1025 1067 actions_add_trace_output(&params->common.threshold_actions, trace_output); 1026 1068 1027 - if (geteuid()) { 1028 - err_msg("rtla needs root permission\n"); 1029 - exit(EXIT_FAILURE); 1030 - } 1069 + if (geteuid()) 1070 + fatal("rtla needs root permission"); 1031 1071 1032 1072 if (params->common.hist.no_irq && params->common.hist.no_thread) 1033 - timerlat_hist_usage("no-irq and no-thread set, there is nothing to do here"); 1073 + fatal("no-irq and no-thread set, there is nothing to do here"); 1034 1074 1035 1075 if (params->common.hist.no_index && !params->common.hist.with_zeros) 1036 - timerlat_hist_usage("no-index set with with-zeros is not set - it does not make sense"); 1076 + fatal("no-index set with with-zeros is not set - it does not make sense"); 1037 1077 1038 1078 /* 1039 1079 * Auto analysis only happens if stop tracing, thus: ··· 1036 1088 params->no_aa = 1; 1037 1089 1038 1090 if (params->common.kernel_workload && params->common.user_workload) 1039 - timerlat_hist_usage("--kernel-threads and --user-threads are mutually exclusive!"); 1091 + fatal("--kernel-threads and --user-threads are mutually exclusive!"); 1040 1092 1041 1093 /* 1042 1094 * If auto-analysis or trace output is enabled, switch from BPF mode to
+39 -77
tools/tracing/rtla/src/timerlat_top.c
··· 459 459 460 460 timerlat_top_header(params, top); 461 461 462 - for (i = 0; i < nr_cpus; i++) { 463 - if (params->common.cpus && !CPU_ISSET(i, &params->common.monitored_cpus)) 464 - continue; 462 + for_each_monitored_cpu(i, nr_cpus, &params->common) { 465 463 timerlat_top_print(top, i); 466 464 timerlat_top_update_sum(top, i, &summary); 467 465 } ··· 474 476 /* 475 477 * timerlat_top_usage - prints timerlat top usage message 476 478 */ 477 - static void timerlat_top_usage(char *usage) 479 + static void timerlat_top_usage(void) 478 480 { 479 481 int i; 480 482 481 483 static const char *const msg[] = { 482 484 "", 483 485 " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\", 484 - " [[-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\", 485 - " [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]", 486 + " [[-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\", 487 + " [-P priority] [--dma-latency us] [--aa-only us] [-C [cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]", 486 488 "", 487 489 " -h/--help: print this menu", 488 490 " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", ··· 493 495 " -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us", 494 496 " -c/--cpus cpus: run the tracer only on the given cpus", 495 497 " -H/--house-keeping cpus: run rtla control threads only on the given cpus", 496 - " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 498 + " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 497 499 " -d/--duration time[s|m|h|d]: duration of the session", 498 500 " -D/--debug: print debug info", 499 501 " --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)", 500 - " -t/--trace[file]: save the stopped trace to [file|timerlat_trace.txt]", 502 + " -t/--trace [file]: save the stopped trace to [file|timerlat_trace.txt]", 501 503 " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", 502 504 " --filter <command>: enable a trace event filter to the previous -e event", 503 505 " --trigger <command>: enable a trace event trigger to the previous -e event", ··· 522 524 NULL, 523 525 }; 524 526 525 - if (usage) 526 - fprintf(stderr, "%s\n", usage); 527 - 528 527 fprintf(stderr, "rtla timerlat top: a per-cpu summary of the timer latency (version %s)\n", 529 528 VERSION); 530 529 531 530 for (i = 0; msg[i]; i++) 532 531 fprintf(stderr, "%s\n", msg[i]); 533 - 534 - if (usage) 535 - exit(EXIT_FAILURE); 536 532 537 533 exit(EXIT_SUCCESS); 538 534 } ··· 598 606 {0, 0, 0, 0} 599 607 }; 600 608 601 - /* getopt_long stores the option index here. */ 602 - int option_index = 0; 603 - 604 609 c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", 605 - long_options, &option_index); 610 + long_options, NULL); 606 611 607 612 /* detect the end of the options. */ 608 613 if (c == -1) ··· 617 628 params->print_stack = auto_thresh; 618 629 619 630 /* set trace */ 620 - trace_output = "timerlat_trace.txt"; 631 + if (!trace_output) 632 + trace_output = "timerlat_trace.txt"; 621 633 622 634 break; 623 635 case '5': ··· 638 648 case 'c': 639 649 retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 640 650 if (retval) 641 - timerlat_top_usage("\nInvalid -c cpu list\n"); 651 + fatal("Invalid -c cpu list"); 642 652 params->common.cpus = optarg; 643 653 break; 644 654 case 'C': 645 655 params->common.cgroup = 1; 646 - if (!optarg) { 647 - /* will inherit this cgroup */ 648 - params->common.cgroup_name = NULL; 649 - } else if (*optarg == '=') { 650 - /* skip the = */ 651 - params->common.cgroup_name = ++optarg; 652 - } 656 + params->common.cgroup_name = optarg; 653 657 break; 654 658 case 'D': 655 659 config_debug = 1; ··· 651 667 case 'd': 652 668 params->common.duration = parse_seconds_duration(optarg); 653 669 if (!params->common.duration) 654 - timerlat_top_usage("Invalid -d duration\n"); 670 + fatal("Invalid -d duration"); 655 671 break; 656 672 case 'e': 657 673 tevent = trace_event_alloc(optarg); 658 - if (!tevent) { 659 - err_msg("Error alloc trace event"); 660 - exit(EXIT_FAILURE); 661 - } 674 + if (!tevent) 675 + fatal("Error alloc trace event"); 662 676 663 677 if (params->common.events) 664 678 tevent->next = params->common.events; ··· 664 682 break; 665 683 case 'h': 666 684 case '?': 667 - timerlat_top_usage(NULL); 685 + timerlat_top_usage(); 668 686 break; 669 687 case 'H': 670 688 params->common.hk_cpus = 1; 671 689 retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 672 - if (retval) { 673 - err_msg("Error parsing house keeping CPUs\n"); 674 - exit(EXIT_FAILURE); 675 - } 690 + if (retval) 691 + fatal("Error parsing house keeping CPUs"); 676 692 break; 677 693 case 'i': 678 694 params->common.stop_us = get_llong_from_str(optarg); ··· 684 704 case 'p': 685 705 params->timerlat_period_us = get_llong_from_str(optarg); 686 706 if (params->timerlat_period_us > 1000000) 687 - timerlat_top_usage("Period longer than 1 s\n"); 707 + fatal("Period longer than 1 s"); 688 708 break; 689 709 case 'P': 690 710 retval = parse_prio(optarg, &params->common.sched_param); 691 711 if (retval == -1) 692 - timerlat_top_usage("Invalid -P priority"); 712 + fatal("Invalid -P priority"); 693 713 params->common.set_sched = 1; 694 714 break; 695 715 case 'q': ··· 702 722 params->common.stop_total_us = get_llong_from_str(optarg); 703 723 break; 704 724 case 't': 705 - if (optarg) { 706 - if (optarg[0] == '=') 707 - trace_output = &optarg[1]; 708 - else 709 - trace_output = &optarg[0]; 710 - } else if (optind < argc && argv[optind][0] != '-') 711 - trace_output = argv[optind]; 712 - else 725 + trace_output = parse_optional_arg(argc, argv); 726 + if (!trace_output) 713 727 trace_output = "timerlat_trace.txt"; 714 728 break; 715 729 case 'u': ··· 715 741 case '0': /* trigger */ 716 742 if (params->common.events) { 717 743 retval = trace_event_add_trigger(params->common.events, optarg); 718 - if (retval) { 719 - err_msg("Error adding trigger %s\n", optarg); 720 - exit(EXIT_FAILURE); 721 - } 744 + if (retval) 745 + fatal("Error adding trigger %s", optarg); 722 746 } else { 723 - timerlat_top_usage("--trigger requires a previous -e\n"); 747 + fatal("--trigger requires a previous -e"); 724 748 } 725 749 break; 726 750 case '1': /* filter */ 727 751 if (params->common.events) { 728 752 retval = trace_event_add_filter(params->common.events, optarg); 729 - if (retval) { 730 - err_msg("Error adding filter %s\n", optarg); 731 - exit(EXIT_FAILURE); 732 - } 753 + if (retval) 754 + fatal("Error adding filter %s", optarg); 733 755 } else { 734 - timerlat_top_usage("--filter requires a previous -e\n"); 756 + fatal("--filter requires a previous -e"); 735 757 } 736 758 break; 737 759 case '2': /* dma-latency */ 738 760 params->dma_latency = get_llong_from_str(optarg); 739 - if (params->dma_latency < 0 || params->dma_latency > 10000) { 740 - err_msg("--dma-latency needs to be >= 0 and < 10000"); 741 - exit(EXIT_FAILURE); 742 - } 761 + if (params->dma_latency < 0 || params->dma_latency > 10000) 762 + fatal("--dma-latency needs to be >= 0 and < 10000"); 743 763 break; 744 764 case '3': /* no-aa */ 745 765 params->no_aa = 1; ··· 753 785 case '9': 754 786 retval = actions_parse(&params->common.threshold_actions, optarg, 755 787 "timerlat_trace.txt"); 756 - if (retval) { 757 - err_msg("Invalid action %s\n", optarg); 758 - exit(EXIT_FAILURE); 759 - } 788 + if (retval) 789 + fatal("Invalid action %s", optarg); 760 790 break; 761 791 case '\1': 762 792 retval = actions_parse(&params->common.end_actions, optarg, 763 793 "timerlat_trace.txt"); 764 - if (retval) { 765 - err_msg("Invalid action %s\n", optarg); 766 - exit(EXIT_FAILURE); 767 - } 794 + if (retval) 795 + fatal("Invalid action %s", optarg); 768 796 break; 769 797 default: 770 - timerlat_top_usage("Invalid option"); 798 + fatal("Invalid option"); 771 799 } 772 800 } 773 801 774 802 if (trace_output) 775 803 actions_add_trace_output(&params->common.threshold_actions, trace_output); 776 804 777 - if (geteuid()) { 778 - err_msg("rtla needs root permission\n"); 779 - exit(EXIT_FAILURE); 780 - } 805 + if (geteuid()) 806 + fatal("rtla needs root permission"); 781 807 782 808 /* 783 809 * Auto analysis only happens if stop tracing, thus: ··· 780 818 params->no_aa = 1; 781 819 782 820 if (params->no_aa && params->common.aa_only) 783 - timerlat_top_usage("--no-aa and --aa-only are mutually exclusive!"); 821 + fatal("--no-aa and --aa-only are mutually exclusive!"); 784 822 785 823 if (params->common.kernel_workload && params->common.user_workload) 786 - timerlat_top_usage("--kernel-threads and --user-threads are mutually exclusive!"); 824 + fatal("--kernel-threads and --user-threads are mutually exclusive!"); 787 825 788 826 /* 789 827 * If auto-analysis or trace output is enabled, switch from BPF mode to ··· 878 916 if (!params->common.quiet) 879 917 timerlat_print_stats(tool); 880 918 881 - if (wait_retval == 1) { 919 + if (wait_retval != 0) { 882 920 /* Stopping requested by tracer */ 883 921 actions_perform(&params->common.threshold_actions); 884 922
+4 -8
tools/tracing/rtla/src/timerlat_u.c
··· 51 51 52 52 if (!params->sched_param) { 53 53 retval = sched_setscheduler(0, SCHED_FIFO, &sp); 54 - if (retval < 0) { 55 - err_msg("Error setting timerlat u default priority: %s\n", strerror(errno)); 56 - exit(1); 57 - } 54 + if (retval < 0) 55 + fatal("Error setting timerlat u default priority: %s", strerror(errno)); 58 56 } else { 59 57 retval = __set_sched_attr(getpid(), params->sched_param); 60 58 if (retval) { ··· 76 78 snprintf(buffer, sizeof(buffer), "osnoise/per_cpu/cpu%d/timerlat_fd", cpu); 77 79 78 80 timerlat_fd = tracefs_instance_file_open(NULL, buffer, O_RDONLY); 79 - if (timerlat_fd < 0) { 80 - err_msg("Error opening %s:%s\n", buffer, strerror(errno)); 81 - exit(1); 82 - } 81 + if (timerlat_fd < 0) 82 + fatal("Error opening %s:%s", buffer, strerror(errno)); 83 83 84 84 debug_msg("User-space timerlat pid %d on cpu %d\n", gettid(), cpu); 85 85
+41
tools/tracing/rtla/src/utils.c
··· 57 57 } 58 58 59 59 /* 60 + * fatal - print an error message and EOL to stderr and exit with ERROR 61 + */ 62 + void fatal(const char *fmt, ...) 63 + { 64 + va_list ap; 65 + 66 + va_start(ap, fmt); 67 + vfprintf(stderr, fmt, ap); 68 + va_end(ap); 69 + fprintf(stderr, "\n"); 70 + 71 + exit(ERROR); 72 + } 73 + 74 + /* 60 75 * get_llong_from_str - get a long long int from a string 61 76 */ 62 77 long long get_llong_from_str(char *start) ··· 973 958 debug_msg("rtla automatically moved to an auto house-keeping cpu set\n"); 974 959 975 960 return 1; 961 + } 962 + 963 + /** 964 + * parse_optional_arg - Parse optional argument value 965 + * 966 + * Parse optional argument value, which can be in the form of: 967 + * -sarg, -s/--long=arg, -s/--long arg 968 + * 969 + * Returns arg value if found, NULL otherwise. 970 + */ 971 + char *parse_optional_arg(int argc, char **argv) 972 + { 973 + if (optarg) { 974 + if (optarg[0] == '=') { 975 + /* skip the = */ 976 + return &optarg[1]; 977 + } else { 978 + return optarg; 979 + } 980 + /* parse argument of form -s [arg] and --long [arg]*/ 981 + } else if (optind < argc && argv[optind][0] != '-') { 982 + /* consume optind */ 983 + return argv[optind++]; 984 + } else { 985 + return NULL; 986 + } 976 987 }
+2
tools/tracing/rtla/src/utils.h
··· 19 19 extern int config_debug; 20 20 void debug_msg(const char *fmt, ...); 21 21 void err_msg(const char *fmt, ...); 22 + void fatal(const char *fmt, ...); 22 23 23 24 long parse_seconds_duration(char *val); 24 25 void get_duration(time_t start_time, char *output, int output_size); 25 26 26 27 int parse_cpu_list(char *cpu_list, char **monitored_cpus); 28 + char *parse_optional_arg(int argc, char **argv); 27 29 long long get_llong_from_str(char *start); 28 30 29 31 static inline void
+3 -3
tools/tracing/rtla/tests/osnoise.t
··· 37 37 check "hist stop at failed action" \ 38 38 "osnoise hist -S 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA osnoise histogram$" 39 39 check "top stop at failed action" \ 40 - "timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" 40 + "osnoise top -S 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" 41 41 check "hist with continue" \ 42 - "osnoise hist -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 42 + "osnoise hist -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 43 43 check "top with continue" \ 44 - "osnoise top -q -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 44 + "osnoise top -q -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 45 45 check "hist with trace output at end" \ 46 46 "osnoise hist -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$" 47 47 check "top with trace output at end" \
+3 -3
tools/tracing/rtla/tests/timerlat.t
··· 58 58 check "hist stop at failed action" \ 59 59 "timerlat hist -T 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA timerlat histogram$" 60 60 check "top stop at failed action" \ 61 - "timerlat top -T 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1ALL" 61 + "timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" 62 62 check "hist with continue" \ 63 - "timerlat hist -T 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 63 + "timerlat hist -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 64 64 check "top with continue" \ 65 - "timerlat top -q -T 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 65 + "timerlat top -q -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 66 66 check "hist with trace output at end" \ 67 67 "timerlat hist -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$" 68 68 check "top with trace output at end" \