1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 4 */ 5 6 #define _GNU_SOURCE 7 #include <stdlib.h> 8 #include <string.h> 9 #include <stdio.h> 10 #include <unistd.h> 11 #include <sys/types.h> 12 13 #include <linux/compiler.h> 14 15 #define RTLA_ALLOW_CLI_P_H 16 #include "cli_p.h" 17 18 static const char * const osnoise_top_usage[] = { 19 "rtla osnoise [top] [<options>] [-h|--help]", 20 NULL, 21 }; 22 23 static const char * const osnoise_hist_usage[] = { 24 "rtla osnoise hist [<options>] [-h|--help]", 25 NULL, 26 }; 27 28 static const char * const timerlat_top_usage[] = { 29 "rtla timerlat [top] [<options>] [-h|--help]", 30 NULL, 31 }; 32 33 static const char * const timerlat_hist_usage[] = { 34 "rtla timerlat hist [<options>] [-h|--help]", 35 NULL, 36 }; 37 38 static const char * const hwnoise_usage[] = { 39 "rtla hwnoise [<options>] [-h|--help]", 40 NULL, 41 }; 42 43 static const int common_parse_options_flags = PARSE_OPT_OPTARG_ALLOW_NEXT; 44 45 bool in_unit_test; 46 47 /* 48 * osnoise_top_parse_args - allocs, parse and fill the cmd line parameters 49 */ 50 struct common_params *osnoise_top_parse_args(int argc, char **argv) 51 { 52 struct osnoise_params *params; 53 struct osnoise_cb_data cb_data; 54 const char * const *usage; 55 56 params = calloc_fatal(1, sizeof(*params)); 57 58 cb_data.params = params; 59 cb_data.trace_output = NULL; 60 61 if (strcmp(argv[0], "hwnoise") == 0) { 62 params->mode = MODE_HWNOISE; 63 /* 64 * Reduce CPU usage for 75% to avoid killing the system. 65 */ 66 params->runtime = 750000; 67 params->period = 1000000; 68 usage = hwnoise_usage; 69 } else { 70 usage = osnoise_top_usage; 71 } 72 73 const struct option osnoise_top_options[] = { 74 OPT_GROUP("Tracing Options:"), 75 OSNOISE_OPT_PERIOD, 76 OSNOISE_OPT_RUNTIME, 77 RTLA_OPT_STOP('s', "stop", "single sample"), 78 RTLA_OPT_STOP_TOTAL('S', "stop-total", "total sample"), 79 OSNOISE_OPT_THRESHOLD, 80 RTLA_OPT_TRACE_OUTPUT("osnoise", opt_osnoise_trace_output_cb), 81 82 OPT_GROUP("Event Configuration:"), 83 RTLA_OPT_EVENT, 84 RTLA_OPT_FILTER, 85 RTLA_OPT_TRIGGER, 86 87 OPT_GROUP("CPU Configuration:"), 88 RTLA_OPT_CPUS, 89 RTLA_OPT_HOUSEKEEPING, 90 91 OPT_GROUP("Thread Configuration:"), 92 RTLA_OPT_PRIORITY, 93 RTLA_OPT_CGROUP, 94 95 OPT_GROUP("Output:"), 96 RTLA_OPT_QUIET, 97 98 OPT_GROUP("System Tuning:"), 99 RTLA_OPT_TRACE_BUFFER_SIZE, 100 RTLA_OPT_WARM_UP, 101 102 OPT_GROUP("Auto Analysis and Actions:"), 103 RTLA_OPT_AUTO(opt_osnoise_auto_cb), 104 RTLA_OPT_ON_THRESHOLD("stop-total", opt_osnoise_on_threshold_cb), 105 RTLA_OPT_ON_END(opt_osnoise_on_end_cb), 106 107 OPT_GROUP("General:"), 108 RTLA_OPT_DURATION, 109 RTLA_OPT_DEBUG, 110 111 OPT_END(), 112 }; 113 114 actions_init(¶ms->common.threshold_actions); 115 actions_init(¶ms->common.end_actions); 116 117 argc = parse_options(argc, (const char **)argv, 118 osnoise_top_options, 119 usage, 120 common_parse_options_flags); 121 if (argc < 0) 122 return NULL; 123 124 if (cb_data.trace_output) 125 actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output); 126 127 if (geteuid() && !in_unit_test) 128 fatal("osnoise needs root permission"); 129 130 return ¶ms->common; 131 } 132 133 /* 134 * osnoise_hist_parse_args - allocs, parse and fill the cmd line parameters 135 */ 136 struct common_params *osnoise_hist_parse_args(int argc, char **argv) 137 { 138 struct osnoise_params *params; 139 struct osnoise_cb_data cb_data; 140 141 params = calloc_fatal(1, sizeof(*params)); 142 143 cb_data.params = params; 144 cb_data.trace_output = NULL; 145 146 const struct option osnoise_hist_options[] = { 147 OPT_GROUP("Tracing Options:"), 148 OSNOISE_OPT_PERIOD, 149 OSNOISE_OPT_RUNTIME, 150 RTLA_OPT_STOP('s', "stop", "single sample"), 151 RTLA_OPT_STOP_TOTAL('S', "stop-total", "total sample"), 152 OSNOISE_OPT_THRESHOLD, 153 RTLA_OPT_TRACE_OUTPUT("osnoise", opt_osnoise_trace_output_cb), 154 155 OPT_GROUP("Event Configuration:"), 156 RTLA_OPT_EVENT, 157 RTLA_OPT_FILTER, 158 RTLA_OPT_TRIGGER, 159 160 OPT_GROUP("CPU Configuration:"), 161 RTLA_OPT_CPUS, 162 RTLA_OPT_HOUSEKEEPING, 163 164 OPT_GROUP("Thread Configuration:"), 165 RTLA_OPT_PRIORITY, 166 RTLA_OPT_CGROUP, 167 168 OPT_GROUP("Histogram Options:"), 169 HIST_OPT_BUCKET_SIZE, 170 HIST_OPT_ENTRIES, 171 HIST_OPT_NO_HEADER, 172 HIST_OPT_NO_SUMMARY, 173 HIST_OPT_NO_INDEX, 174 HIST_OPT_WITH_ZEROS, 175 176 OPT_GROUP("System Tuning:"), 177 RTLA_OPT_TRACE_BUFFER_SIZE, 178 RTLA_OPT_WARM_UP, 179 180 OPT_GROUP("Auto Analysis and Actions:"), 181 RTLA_OPT_AUTO(opt_osnoise_auto_cb), 182 RTLA_OPT_ON_THRESHOLD("stop-total", opt_osnoise_on_threshold_cb), 183 RTLA_OPT_ON_END(opt_osnoise_on_end_cb), 184 185 OPT_GROUP("General:"), 186 RTLA_OPT_DURATION, 187 RTLA_OPT_DEBUG, 188 189 OPT_END(), 190 }; 191 192 actions_init(¶ms->common.threshold_actions); 193 actions_init(¶ms->common.end_actions); 194 195 /* display data in microseconds */ 196 params->common.output_divisor = 1000; 197 params->common.hist.bucket_size = 1; 198 params->common.hist.entries = 256; 199 200 argc = parse_options(argc, (const char **)argv, 201 osnoise_hist_options, osnoise_hist_usage, 202 common_parse_options_flags); 203 if (argc < 0) 204 return NULL; 205 206 if (cb_data.trace_output) 207 actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output); 208 209 if (geteuid() && !in_unit_test) 210 fatal("rtla needs root permission"); 211 212 if (params->common.hist.no_index && !params->common.hist.with_zeros) 213 fatal("no-index set and with-zeros not set - it does not make sense"); 214 215 return ¶ms->common; 216 } 217 218 struct common_params *timerlat_top_parse_args(int argc, char **argv) 219 { 220 struct timerlat_params *params; 221 struct timerlat_cb_data cb_data; 222 223 params = calloc_fatal(1, sizeof(*params)); 224 225 cb_data.params = params; 226 cb_data.trace_output = NULL; 227 228 const struct option timerlat_top_options[] = { 229 OPT_GROUP("Tracing Options:"), 230 TIMERLAT_OPT_PERIOD, 231 RTLA_OPT_STOP('i', "irq", "irq latency"), 232 RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"), 233 TIMERLAT_OPT_STACK, 234 RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb), 235 236 OPT_GROUP("Event Configuration:"), 237 RTLA_OPT_EVENT, 238 RTLA_OPT_FILTER, 239 RTLA_OPT_TRIGGER, 240 241 OPT_GROUP("CPU Configuration:"), 242 RTLA_OPT_CPUS, 243 RTLA_OPT_HOUSEKEEPING, 244 245 OPT_GROUP("Thread Configuration:"), 246 RTLA_OPT_PRIORITY, 247 RTLA_OPT_CGROUP, 248 RTLA_OPT_USER_THREADS, 249 RTLA_OPT_KERNEL_THREADS, 250 RTLA_OPT_USER_LOAD, 251 TIMERLAT_OPT_ALIGNED, 252 253 OPT_GROUP("Output:"), 254 TIMERLAT_OPT_NANO, 255 RTLA_OPT_QUIET, 256 257 OPT_GROUP("System Tuning:"), 258 TIMERLAT_OPT_DMA_LATENCY, 259 TIMERLAT_OPT_DEEPEST_IDLE_STATE, 260 RTLA_OPT_TRACE_BUFFER_SIZE, 261 RTLA_OPT_WARM_UP, 262 263 OPT_GROUP("Auto Analysis and Actions:"), 264 RTLA_OPT_AUTO(opt_timerlat_auto_cb), 265 TIMERLAT_OPT_AA_ONLY, 266 TIMERLAT_OPT_NO_AA, 267 TIMERLAT_OPT_DUMPS_TASKS, 268 RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb), 269 RTLA_OPT_ON_END(opt_timerlat_on_end_cb), 270 TIMERLAT_OPT_BPF_ACTION, 271 TIMERLAT_OPT_STACK_FORMAT, 272 273 OPT_GROUP("General:"), 274 RTLA_OPT_DURATION, 275 RTLA_OPT_DEBUG, 276 277 OPT_END(), 278 }; 279 280 actions_init(¶ms->common.threshold_actions); 281 actions_init(¶ms->common.end_actions); 282 283 /* disabled by default */ 284 params->dma_latency = -1; 285 params->deepest_idle_state = -2; 286 287 /* display data in microseconds */ 288 params->common.output_divisor = 1000; 289 290 /* default to BPF mode */ 291 params->mode = TRACING_MODE_BPF; 292 293 /* default to truncate stack format */ 294 params->stack_format = STACK_FORMAT_TRUNCATE; 295 296 argc = parse_options(argc, (const char **)argv, 297 timerlat_top_options, timerlat_top_usage, 298 common_parse_options_flags); 299 if (argc < 0) 300 return NULL; 301 302 if (cb_data.trace_output) 303 actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output); 304 305 if (geteuid() && !in_unit_test) 306 fatal("rtla needs root permission"); 307 308 /* 309 * Auto analysis only happens if stop tracing, thus: 310 */ 311 if (!params->common.stop_us && !params->common.stop_total_us) 312 params->no_aa = 1; 313 314 if (params->no_aa && params->common.aa_only) 315 fatal("--no-aa and --aa-only are mutually exclusive!"); 316 317 if (params->common.kernel_workload && params->common.user_workload) 318 fatal("--kernel-threads and --user-threads are mutually exclusive!"); 319 320 /* 321 * If auto-analysis or trace output is enabled, switch from BPF mode to 322 * mixed mode 323 */ 324 if (params->mode == TRACING_MODE_BPF && 325 (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || 326 params->common.end_actions.present[ACTION_TRACE_OUTPUT] || 327 !params->no_aa)) 328 params->mode = TRACING_MODE_MIXED; 329 330 return ¶ms->common; 331 } 332 333 struct common_params *timerlat_hist_parse_args(int argc, char **argv) 334 { 335 struct timerlat_params *params; 336 struct timerlat_cb_data cb_data; 337 338 params = calloc_fatal(1, sizeof(*params)); 339 340 cb_data.params = params; 341 cb_data.trace_output = NULL; 342 343 const struct option timerlat_hist_options[] = { 344 OPT_GROUP("Tracing Options:"), 345 TIMERLAT_OPT_PERIOD, 346 RTLA_OPT_STOP('i', "irq", "irq latency"), 347 RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"), 348 TIMERLAT_OPT_STACK, 349 RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb), 350 351 OPT_GROUP("Event Configuration:"), 352 RTLA_OPT_EVENT, 353 RTLA_OPT_FILTER, 354 RTLA_OPT_TRIGGER, 355 356 OPT_GROUP("CPU Configuration:"), 357 RTLA_OPT_CPUS, 358 RTLA_OPT_HOUSEKEEPING, 359 360 OPT_GROUP("Thread Configuration:"), 361 RTLA_OPT_PRIORITY, 362 RTLA_OPT_CGROUP, 363 RTLA_OPT_USER_THREADS, 364 RTLA_OPT_KERNEL_THREADS, 365 RTLA_OPT_USER_LOAD, 366 TIMERLAT_OPT_ALIGNED, 367 368 OPT_GROUP("Histogram Options:"), 369 HIST_OPT_BUCKET_SIZE, 370 HIST_OPT_ENTRIES, 371 HIST_OPT_NO_IRQ, 372 HIST_OPT_NO_THREAD, 373 HIST_OPT_NO_HEADER, 374 HIST_OPT_NO_SUMMARY, 375 HIST_OPT_NO_INDEX, 376 HIST_OPT_WITH_ZEROS, 377 378 OPT_GROUP("Output:"), 379 TIMERLAT_OPT_NANO, 380 381 OPT_GROUP("System Tuning:"), 382 TIMERLAT_OPT_DMA_LATENCY, 383 TIMERLAT_OPT_DEEPEST_IDLE_STATE, 384 RTLA_OPT_TRACE_BUFFER_SIZE, 385 RTLA_OPT_WARM_UP, 386 387 OPT_GROUP("Auto Analysis and Actions:"), 388 RTLA_OPT_AUTO(opt_timerlat_auto_cb), 389 TIMERLAT_OPT_NO_AA, 390 TIMERLAT_OPT_DUMPS_TASKS, 391 RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb), 392 RTLA_OPT_ON_END(opt_timerlat_on_end_cb), 393 TIMERLAT_OPT_BPF_ACTION, 394 TIMERLAT_OPT_STACK_FORMAT, 395 396 OPT_GROUP("General:"), 397 RTLA_OPT_DURATION, 398 RTLA_OPT_DEBUG, 399 400 OPT_END(), 401 }; 402 403 actions_init(¶ms->common.threshold_actions); 404 actions_init(¶ms->common.end_actions); 405 406 /* disabled by default */ 407 params->dma_latency = -1; 408 409 /* disabled by default */ 410 params->deepest_idle_state = -2; 411 412 /* display data in microseconds */ 413 params->common.output_divisor = 1000; 414 params->common.hist.bucket_size = 1; 415 params->common.hist.entries = 256; 416 417 /* default to BPF mode */ 418 params->mode = TRACING_MODE_BPF; 419 420 /* default to truncate stack format */ 421 params->stack_format = STACK_FORMAT_TRUNCATE; 422 423 argc = parse_options(argc, (const char **)argv, 424 timerlat_hist_options, timerlat_hist_usage, 425 common_parse_options_flags); 426 if (argc < 0) 427 return NULL; 428 429 if (cb_data.trace_output) 430 actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output); 431 432 if (geteuid() && !in_unit_test) 433 fatal("rtla needs root permission"); 434 435 if (params->common.hist.no_irq && params->common.hist.no_thread) 436 fatal("no-irq and no-thread set, there is nothing to do here"); 437 438 if (params->common.hist.no_index && !params->common.hist.with_zeros) 439 fatal("no-index set with with-zeros is not set - it does not make sense"); 440 441 /* 442 * Auto analysis only happens if stop tracing, thus: 443 */ 444 if (!params->common.stop_us && !params->common.stop_total_us) 445 params->no_aa = 1; 446 447 if (params->common.kernel_workload && params->common.user_workload) 448 fatal("--kernel-threads and --user-threads are mutually exclusive!"); 449 450 /* 451 * If auto-analysis or trace output is enabled, switch from BPF mode to 452 * mixed mode 453 */ 454 if (params->mode == TRACING_MODE_BPF && 455 (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || 456 params->common.end_actions.present[ACTION_TRACE_OUTPUT] || 457 !params->no_aa)) 458 params->mode = TRACING_MODE_MIXED; 459 460 return ¶ms->common; 461 } 462 463 /* 464 * rtla_usage - print rtla usage 465 */ 466 __noreturn static void rtla_usage(int err) 467 { 468 int i; 469 470 static const char * const msg[] = { 471 "", 472 "rtla version " VERSION, 473 "", 474 " usage: rtla COMMAND ...", 475 "", 476 " commands:", 477 " osnoise - gives information about the operating system noise (osnoise)", 478 " hwnoise - gives information about hardware-related noise", 479 " timerlat - measures the timer irq and thread latency", 480 "", 481 NULL, 482 }; 483 484 for (i = 0; msg[i]; i++) 485 fprintf(stderr, "%s\n", msg[i]); 486 exit(err); 487 } 488 489 /* 490 * run_tool_command - try to run a rtla tool command 491 * 492 * It returns 0 if it fails. The tool's main will generally not 493 * return as they should call exit(). 494 */ 495 int run_tool_command(int argc, char **argv, int start_position) 496 { 497 if (strcmp(argv[start_position], "osnoise") == 0) { 498 osnoise_main(argc-start_position, &argv[start_position]); 499 goto ran; 500 } else if (strcmp(argv[start_position], "hwnoise") == 0) { 501 hwnoise_main(argc-start_position, &argv[start_position]); 502 goto ran; 503 } else if (strcmp(argv[start_position], "timerlat") == 0) { 504 timerlat_main(argc-start_position, &argv[start_position]); 505 goto ran; 506 } 507 508 return 0; 509 ran: 510 return 1; 511 } 512 513 /* Set main as weak to allow overriding it for building unit test binary */ 514 #pragma weak main 515 516 int main(int argc, char *argv[]) 517 { 518 int retval; 519 520 /* is it an alias? */ 521 retval = run_tool_command(argc, argv, 0); 522 if (retval) 523 exit(0); 524 525 if (argc < 2) 526 goto usage; 527 528 if (strcmp(argv[1], "-h") == 0) 529 rtla_usage(129); 530 else if (strcmp(argv[1], "--help") == 0) 531 rtla_usage(129); 532 533 retval = run_tool_command(argc, argv, 1); 534 if (retval) 535 exit(0); 536 537 usage: 538 rtla_usage(129); 539 } 540