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

rtla: Add hwnoise tool

The hwnoise tool is a special mode for the osnoise top tool.

hwnoise dispatches the osnoise tracer and displays a summary of the noise.
The difference is that it runs the tracer with the OSNOISE_IRQ_DISABLE
option set, thus only allowing only hardware-related noise, resulting in
a simplified output. hwnoise has the same features of osnoise.

An example of the tool's output:

# rtla hwnoise -c 1-11 -T 1 -d 10m -q
Hardware-related Noise
duration: 0 00:10:00 | time is in us
CPU Period Runtime Noise % CPU Aval Max Noise Max Single HW NMI
1 #599 599000000 138 99.99997 3 3 4 74
2 #599 599000000 85 99.99998 3 3 4 75
3 #599 599000000 86 99.99998 4 3 6 75
4 #599 599000000 81 99.99998 4 4 2 75
5 #599 599000000 85 99.99998 2 2 2 75

Link: https://lkml.kernel.org/r/2d6f49a6f3a4f8b51b2c806458b1cff71ad4d014.1675805361.git.bristot@kernel.org

Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
Cc: Daniel Bristot de Oliveira <bristot@kernel.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: Bagas Sanjaya <bagasdotme@gmail.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Daniel Bristot de Oliveira and committed by
Steven Rostedt (Google)
1f428356 ce6cc6f7

+198 -16
+2
tools/tracing/rtla/Makefile
··· 119 119 $(STRIP) $(DESTDIR)$(BINDIR)/rtla 120 120 @test ! -f $(DESTDIR)$(BINDIR)/osnoise || rm $(DESTDIR)$(BINDIR)/osnoise 121 121 ln -s rtla $(DESTDIR)$(BINDIR)/osnoise 122 + @test ! -f $(DESTDIR)$(BINDIR)/hwnoise || rm $(DESTDIR)$(BINDIR)/hwnoise 123 + ln -s rtla $(DESTDIR)$(BINDIR)/hwnoise 122 124 @test ! -f $(DESTDIR)$(BINDIR)/timerlat || rm $(DESTDIR)$(BINDIR)/timerlat 123 125 ln -s rtla $(DESTDIR)$(BINDIR)/timerlat 124 126
+117
tools/tracing/rtla/src/osnoise.c
··· 734 734 context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL; 735 735 } 736 736 737 + static int osnoise_options_get_option(char *option) 738 + { 739 + char *options = tracefs_instance_file_read(NULL, "osnoise/options", NULL); 740 + char no_option[128]; 741 + int retval = 0; 742 + char *opt; 743 + 744 + if (!options) 745 + return OSNOISE_OPTION_INIT_VAL; 746 + 747 + /* 748 + * Check first if the option is disabled. 749 + */ 750 + snprintf(no_option, sizeof(no_option), "NO_%s", option); 751 + 752 + opt = strstr(options, no_option); 753 + if (opt) 754 + goto out_free; 755 + 756 + /* 757 + * Now that it is not disabled, if the string is there, it is 758 + * enabled. If the string is not there, the option does not exist. 759 + */ 760 + opt = strstr(options, option); 761 + if (opt) 762 + retval = 1; 763 + else 764 + retval = OSNOISE_OPTION_INIT_VAL; 765 + 766 + out_free: 767 + free(options); 768 + return retval; 769 + } 770 + 771 + static int osnoise_options_set_option(char *option, bool onoff) 772 + { 773 + char no_option[128]; 774 + 775 + if (onoff) 776 + return tracefs_instance_file_write(NULL, "osnoise/options", option); 777 + 778 + snprintf(no_option, sizeof(no_option), "NO_%s", option); 779 + 780 + return tracefs_instance_file_write(NULL, "osnoise/options", no_option); 781 + } 782 + 783 + static int osnoise_get_irq_disable(struct osnoise_context *context) 784 + { 785 + if (context->opt_irq_disable != OSNOISE_OPTION_INIT_VAL) 786 + return context->opt_irq_disable; 787 + 788 + if (context->orig_opt_irq_disable != OSNOISE_OPTION_INIT_VAL) 789 + return context->orig_opt_irq_disable; 790 + 791 + context->orig_opt_irq_disable = osnoise_options_get_option("OSNOISE_IRQ_DISABLE"); 792 + 793 + return context->orig_opt_irq_disable; 794 + } 795 + 796 + int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff) 797 + { 798 + int opt_irq_disable = osnoise_get_irq_disable(context); 799 + int retval; 800 + 801 + if (opt_irq_disable == OSNOISE_OPTION_INIT_VAL) 802 + return -1; 803 + 804 + if (opt_irq_disable == onoff) 805 + return 0; 806 + 807 + retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", onoff); 808 + if (retval < 0) 809 + return -1; 810 + 811 + context->opt_irq_disable = onoff; 812 + 813 + return 0; 814 + } 815 + 816 + static void osnoise_restore_irq_disable(struct osnoise_context *context) 817 + { 818 + int retval; 819 + 820 + if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL) 821 + return; 822 + 823 + if (context->orig_opt_irq_disable == context->opt_irq_disable) 824 + goto out_done; 825 + 826 + retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", context->orig_opt_irq_disable); 827 + if (retval < 0) 828 + err_msg("Could not restore original OSNOISE_IRQ_DISABLE option\n"); 829 + 830 + out_done: 831 + context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 832 + } 833 + 834 + static void osnoise_put_irq_disable(struct osnoise_context *context) 835 + { 836 + osnoise_restore_irq_disable(context); 837 + 838 + if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL) 839 + return; 840 + 841 + context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 842 + } 843 + 737 844 /* 738 845 * enable_osnoise - enable osnoise tracer in the trace_instance 739 846 */ ··· 905 798 context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL; 906 799 context->tracing_thresh = OSNOISE_OPTION_INIT_VAL; 907 800 801 + context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 802 + context->opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 803 + 908 804 osnoise_get_context(context); 909 805 910 806 return context; ··· 934 824 osnoise_put_timerlat_period_us(context); 935 825 osnoise_put_print_stack(context); 936 826 osnoise_put_tracing_thresh(context); 827 + osnoise_put_irq_disable(context); 937 828 938 829 free(context); 939 830 } ··· 1068 957 usage: 1069 958 osnoise_usage(1); 1070 959 exit(1); 960 + } 961 + 962 + int hwnoise_main(int argc, char *argv[]) 963 + { 964 + osnoise_top_main(argc, argv); 965 + exit(0); 1071 966 }
+7
tools/tracing/rtla/src/osnoise.h
··· 38 38 /* -1 as init value because 0 is disabled */ 39 39 long long orig_print_stack; 40 40 long long print_stack; 41 + 42 + /* -1 as init value because 0 is off */ 43 + int orig_opt_irq_disable; 44 + int opt_irq_disable; 41 45 }; 42 46 43 47 /* ··· 83 79 int osnoise_set_print_stack(struct osnoise_context *context, 84 80 long long print_stack); 85 81 82 + int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff); 83 + 86 84 /* 87 85 * osnoise_tool - osnoise based tool definition. 88 86 */ ··· 103 97 int osnoise_hist_main(int argc, char *argv[]); 104 98 int osnoise_top_main(int argc, char **argv); 105 99 int osnoise_main(int argc, char **argv); 100 + int hwnoise_main(int argc, char **argv);
+68 -16
tools/tracing/rtla/src/osnoise_top.c
··· 14 14 #include "osnoise.h" 15 15 #include "utils.h" 16 16 17 + enum osnoise_mode { 18 + MODE_OSNOISE = 0, 19 + MODE_HWNOISE 20 + }; 21 + 17 22 /* 18 23 * osnoise top parameters 19 24 */ ··· 37 32 int set_sched; 38 33 struct sched_attr sched_param; 39 34 struct trace_events *events; 35 + enum osnoise_mode mode; 40 36 }; 41 37 42 38 struct osnoise_top_cpu { ··· 149 143 */ 150 144 static void osnoise_top_header(struct osnoise_tool *top) 151 145 { 146 + struct osnoise_top_params *params = top->params; 152 147 struct trace_seq *s = top->trace.seq; 153 148 char duration[26]; 154 149 155 150 get_duration(top->start_time, duration, sizeof(duration)); 156 151 157 152 trace_seq_printf(s, "\033[2;37;40m"); 158 - trace_seq_printf(s, " Operating System Noise"); 159 - trace_seq_printf(s, " "); 160 - trace_seq_printf(s, " "); 153 + trace_seq_printf(s, " "); 154 + 155 + if (params->mode == MODE_OSNOISE) { 156 + trace_seq_printf(s, "Operating System Noise"); 157 + trace_seq_printf(s, " "); 158 + } else if (params->mode == MODE_HWNOISE) { 159 + trace_seq_printf(s, "Hardware-related Noise"); 160 + } 161 + 162 + trace_seq_printf(s, " "); 161 163 trace_seq_printf(s, "\033[0;0;0m"); 162 164 trace_seq_printf(s, "\n"); 163 165 ··· 176 162 trace_seq_printf(s, " Noise "); 177 163 trace_seq_printf(s, " %% CPU Aval "); 178 164 trace_seq_printf(s, " Max Noise Max Single "); 179 - trace_seq_printf(s, " HW NMI IRQ Softirq Thread"); 165 + trace_seq_printf(s, " HW NMI"); 166 + 167 + if (params->mode == MODE_HWNOISE) 168 + goto eol; 169 + 170 + trace_seq_printf(s, " IRQ Softirq Thread"); 171 + 172 + eol: 180 173 trace_seq_printf(s, "\033[0;0;0m"); 181 174 trace_seq_printf(s, "\n"); 182 175 } ··· 202 181 */ 203 182 static void osnoise_top_print(struct osnoise_tool *tool, int cpu) 204 183 { 184 + struct osnoise_top_params *params = tool->params; 205 185 struct trace_seq *s = tool->trace.seq; 206 186 struct osnoise_top_cpu *cpu_data; 207 187 struct osnoise_top_data *data; ··· 227 205 228 206 trace_seq_printf(s, "%12llu ", cpu_data->hw_count); 229 207 trace_seq_printf(s, "%12llu ", cpu_data->nmi_count); 208 + 209 + if (params->mode == MODE_HWNOISE) { 210 + trace_seq_printf(s, "\n"); 211 + return; 212 + } 213 + 230 214 trace_seq_printf(s, "%12llu ", cpu_data->irq_count); 231 215 trace_seq_printf(s, "%12llu ", cpu_data->softirq_count); 232 216 trace_seq_printf(s, "%12llu\n", cpu_data->thread_count); ··· 269 241 /* 270 242 * osnoise_top_usage - prints osnoise top usage message 271 243 */ 272 - void osnoise_top_usage(char *usage) 244 + static void osnoise_top_usage(struct osnoise_top_params *params, char *usage) 273 245 { 274 246 int i; 275 247 276 248 static const char * const msg[] = { 277 - " usage: rtla osnoise [top] [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", 249 + " [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", 278 250 " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", 279 251 " [-c cpu-list] [-P priority]", 280 252 "", ··· 305 277 if (usage) 306 278 fprintf(stderr, "%s\n", usage); 307 279 308 - fprintf(stderr, "rtla osnoise top: a per-cpu summary of the OS noise (version %s)\n", 280 + if (params->mode == MODE_OSNOISE) { 281 + fprintf(stderr, 282 + "rtla osnoise top: a per-cpu summary of the OS noise (version %s)\n", 309 283 VERSION); 284 + 285 + fprintf(stderr, " usage: rtla osnoise [top]"); 286 + } 287 + 288 + if (params->mode == MODE_HWNOISE) { 289 + fprintf(stderr, 290 + "rtla hwnoise: a summary of hardware-related noise (version %s)\n", 291 + VERSION); 292 + 293 + fprintf(stderr, " usage: rtla hwnoise"); 294 + } 310 295 311 296 for (i = 0; msg[i]; i++) 312 297 fprintf(stderr, "%s\n", msg[i]); ··· 339 298 params = calloc(1, sizeof(*params)); 340 299 if (!params) 341 300 exit(1); 301 + 302 + if (strcmp(argv[0], "hwnoise") == 0) 303 + params->mode = MODE_HWNOISE; 342 304 343 305 while (1) { 344 306 static struct option long_options[] = { ··· 389 345 case 'c': 390 346 retval = parse_cpu_list(optarg, &params->monitored_cpus); 391 347 if (retval) 392 - osnoise_top_usage("\nInvalid -c cpu list\n"); 348 + osnoise_top_usage(params, "\nInvalid -c cpu list\n"); 393 349 params->cpus = optarg; 394 350 break; 395 351 case 'D': ··· 398 354 case 'd': 399 355 params->duration = parse_seconds_duration(optarg); 400 356 if (!params->duration) 401 - osnoise_top_usage("Invalid -D duration\n"); 357 + osnoise_top_usage(params, "Invalid -D duration\n"); 402 358 break; 403 359 case 'e': 404 360 tevent = trace_event_alloc(optarg); ··· 414 370 break; 415 371 case 'h': 416 372 case '?': 417 - osnoise_top_usage(NULL); 373 + osnoise_top_usage(params, NULL); 418 374 break; 419 375 case 'p': 420 376 params->period = get_llong_from_str(optarg); 421 377 if (params->period > 10000000) 422 - osnoise_top_usage("Period longer than 10 s\n"); 378 + osnoise_top_usage(params, "Period longer than 10 s\n"); 423 379 break; 424 380 case 'P': 425 381 retval = parse_prio(optarg, &params->sched_param); 426 382 if (retval == -1) 427 - osnoise_top_usage("Invalid -P priority"); 383 + osnoise_top_usage(params, "Invalid -P priority"); 428 384 params->set_sched = 1; 429 385 break; 430 386 case 'q': ··· 433 389 case 'r': 434 390 params->runtime = get_llong_from_str(optarg); 435 391 if (params->runtime < 100) 436 - osnoise_top_usage("Runtime shorter than 100 us\n"); 392 + osnoise_top_usage(params, "Runtime shorter than 100 us\n"); 437 393 break; 438 394 case 's': 439 395 params->stop_us = get_llong_from_str(optarg); ··· 459 415 exit(EXIT_FAILURE); 460 416 } 461 417 } else { 462 - osnoise_top_usage("--trigger requires a previous -e\n"); 418 + osnoise_top_usage(params, "--trigger requires a previous -e\n"); 463 419 } 464 420 break; 465 421 case '1': /* filter */ ··· 470 426 exit(EXIT_FAILURE); 471 427 } 472 428 } else { 473 - osnoise_top_usage("--filter requires a previous -e\n"); 429 + osnoise_top_usage(params, "--filter requires a previous -e\n"); 474 430 } 475 431 break; 476 432 default: 477 - osnoise_top_usage("Invalid option"); 433 + osnoise_top_usage(params, "Invalid option"); 478 434 } 479 435 } 480 436 ··· 535 491 retval = osnoise_set_tracing_thresh(tool->context, params->threshold); 536 492 if (retval) { 537 493 err_msg("Failed to set tracing_thresh\n"); 494 + goto out_err; 495 + } 496 + } 497 + 498 + if (params->mode == MODE_HWNOISE) { 499 + retval = osnoise_set_irq_disable(tool->context, 1); 500 + if (retval) { 501 + err_msg("Failed to set OSNOISE_IRQ_DISABLE option\n"); 538 502 goto out_err; 539 503 } 540 504 }
+4
tools/tracing/rtla/src/rtla.c
··· 26 26 "", 27 27 " commands:", 28 28 " osnoise - gives information about the operating system noise (osnoise)", 29 + " hwnoise - gives information about hardware-related noise", 29 30 " timerlat - measures the timer irq and thread latency", 30 31 "", 31 32 NULL, ··· 47 46 { 48 47 if (strcmp(argv[start_position], "osnoise") == 0) { 49 48 osnoise_main(argc-start_position, &argv[start_position]); 49 + goto ran; 50 + } else if (strcmp(argv[start_position], "hwnoise") == 0) { 51 + hwnoise_main(argc-start_position, &argv[start_position]); 50 52 goto ran; 51 53 } else if (strcmp(argv[start_position], "timerlat") == 0) { 52 54 timerlat_main(argc-start_position, &argv[start_position]);