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 252 OPT_GROUP("Output:"), 253 TIMERLAT_OPT_NANO, 254 RTLA_OPT_QUIET, 255 256 OPT_GROUP("System Tuning:"), 257 TIMERLAT_OPT_DMA_LATENCY, 258 TIMERLAT_OPT_DEEPEST_IDLE_STATE, 259 RTLA_OPT_TRACE_BUFFER_SIZE, 260 RTLA_OPT_WARM_UP, 261 262 OPT_GROUP("Auto Analysis and Actions:"), 263 RTLA_OPT_AUTO(opt_timerlat_auto_cb), 264 TIMERLAT_OPT_AA_ONLY, 265 TIMERLAT_OPT_NO_AA, 266 TIMERLAT_OPT_DUMPS_TASKS, 267 RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb), 268 RTLA_OPT_ON_END(opt_timerlat_on_end_cb), 269 TIMERLAT_OPT_BPF_ACTION, 270 TIMERLAT_OPT_STACK_FORMAT, 271 272 OPT_GROUP("General:"), 273 RTLA_OPT_DURATION, 274 RTLA_OPT_DEBUG, 275 276 OPT_END(), 277 }; 278 279 actions_init(¶ms->common.threshold_actions); 280 actions_init(¶ms->common.end_actions); 281 282 /* disabled by default */ 283 params->dma_latency = -1; 284 params->deepest_idle_state = -2; 285 286 /* display data in microseconds */ 287 params->common.output_divisor = 1000; 288 289 /* default to BPF mode */ 290 params->mode = TRACING_MODE_BPF; 291 292 /* default to truncate stack format */ 293 params->stack_format = STACK_FORMAT_TRUNCATE; 294 295 argc = parse_options(argc, (const char **)argv, 296 timerlat_top_options, timerlat_top_usage, 297 common_parse_options_flags); 298 if (argc < 0) 299 return NULL; 300 301 if (cb_data.trace_output) 302 actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output); 303 304 if (geteuid() && !in_unit_test) 305 fatal("rtla needs root permission"); 306 307 /* 308 * Auto analysis only happens if stop tracing, thus: 309 */ 310 if (!params->common.stop_us && !params->common.stop_total_us) 311 params->no_aa = 1; 312 313 if (params->no_aa && params->common.aa_only) 314 fatal("--no-aa and --aa-only are mutually exclusive!"); 315 316 if (params->common.kernel_workload && params->common.user_workload) 317 fatal("--kernel-threads and --user-threads are mutually exclusive!"); 318 319 /* 320 * If auto-analysis or trace output is enabled, switch from BPF mode to 321 * mixed mode 322 */ 323 if (params->mode == TRACING_MODE_BPF && 324 (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || 325 params->common.end_actions.present[ACTION_TRACE_OUTPUT] || 326 !params->no_aa)) 327 params->mode = TRACING_MODE_MIXED; 328 329 return ¶ms->common; 330 } 331 332 struct common_params *timerlat_hist_parse_args(int argc, char **argv) 333 { 334 struct timerlat_params *params; 335 struct timerlat_cb_data cb_data; 336 337 params = calloc_fatal(1, sizeof(*params)); 338 339 cb_data.params = params; 340 cb_data.trace_output = NULL; 341 342 const struct option timerlat_hist_options[] = { 343 OPT_GROUP("Tracing Options:"), 344 TIMERLAT_OPT_PERIOD, 345 RTLA_OPT_STOP('i', "irq", "irq latency"), 346 RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"), 347 TIMERLAT_OPT_STACK, 348 RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb), 349 350 OPT_GROUP("Event Configuration:"), 351 RTLA_OPT_EVENT, 352 RTLA_OPT_FILTER, 353 RTLA_OPT_TRIGGER, 354 355 OPT_GROUP("CPU Configuration:"), 356 RTLA_OPT_CPUS, 357 RTLA_OPT_HOUSEKEEPING, 358 359 OPT_GROUP("Thread Configuration:"), 360 RTLA_OPT_PRIORITY, 361 RTLA_OPT_CGROUP, 362 RTLA_OPT_USER_THREADS, 363 RTLA_OPT_KERNEL_THREADS, 364 RTLA_OPT_USER_LOAD, 365 366 OPT_GROUP("Histogram Options:"), 367 HIST_OPT_BUCKET_SIZE, 368 HIST_OPT_ENTRIES, 369 HIST_OPT_NO_IRQ, 370 HIST_OPT_NO_THREAD, 371 HIST_OPT_NO_HEADER, 372 HIST_OPT_NO_SUMMARY, 373 HIST_OPT_NO_INDEX, 374 HIST_OPT_WITH_ZEROS, 375 376 OPT_GROUP("Output:"), 377 TIMERLAT_OPT_NANO, 378 379 OPT_GROUP("System Tuning:"), 380 TIMERLAT_OPT_DMA_LATENCY, 381 TIMERLAT_OPT_DEEPEST_IDLE_STATE, 382 RTLA_OPT_TRACE_BUFFER_SIZE, 383 RTLA_OPT_WARM_UP, 384 385 OPT_GROUP("Auto Analysis and Actions:"), 386 RTLA_OPT_AUTO(opt_timerlat_auto_cb), 387 TIMERLAT_OPT_NO_AA, 388 TIMERLAT_OPT_DUMPS_TASKS, 389 RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb), 390 RTLA_OPT_ON_END(opt_timerlat_on_end_cb), 391 TIMERLAT_OPT_BPF_ACTION, 392 TIMERLAT_OPT_STACK_FORMAT, 393 394 OPT_GROUP("General:"), 395 RTLA_OPT_DURATION, 396 RTLA_OPT_DEBUG, 397 398 OPT_END(), 399 }; 400 401 actions_init(¶ms->common.threshold_actions); 402 actions_init(¶ms->common.end_actions); 403 404 /* disabled by default */ 405 params->dma_latency = -1; 406 407 /* disabled by default */ 408 params->deepest_idle_state = -2; 409 410 /* display data in microseconds */ 411 params->common.output_divisor = 1000; 412 params->common.hist.bucket_size = 1; 413 params->common.hist.entries = 256; 414 415 /* default to BPF mode */ 416 params->mode = TRACING_MODE_BPF; 417 418 /* default to truncate stack format */ 419 params->stack_format = STACK_FORMAT_TRUNCATE; 420 421 argc = parse_options(argc, (const char **)argv, 422 timerlat_hist_options, timerlat_hist_usage, 423 common_parse_options_flags); 424 if (argc < 0) 425 return NULL; 426 427 if (cb_data.trace_output) 428 actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output); 429 430 if (geteuid() && !in_unit_test) 431 fatal("rtla needs root permission"); 432 433 if (params->common.hist.no_irq && params->common.hist.no_thread) 434 fatal("no-irq and no-thread set, there is nothing to do here"); 435 436 if (params->common.hist.no_index && !params->common.hist.with_zeros) 437 fatal("no-index set with with-zeros is not set - it does not make sense"); 438 439 /* 440 * Auto analysis only happens if stop tracing, thus: 441 */ 442 if (!params->common.stop_us && !params->common.stop_total_us) 443 params->no_aa = 1; 444 445 if (params->common.kernel_workload && params->common.user_workload) 446 fatal("--kernel-threads and --user-threads are mutually exclusive!"); 447 448 /* 449 * If auto-analysis or trace output is enabled, switch from BPF mode to 450 * mixed mode 451 */ 452 if (params->mode == TRACING_MODE_BPF && 453 (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || 454 params->common.end_actions.present[ACTION_TRACE_OUTPUT] || 455 !params->no_aa)) 456 params->mode = TRACING_MODE_MIXED; 457 458 return ¶ms->common; 459 } 460 461 /* 462 * rtla_usage - print rtla usage 463 */ 464 __noreturn static void rtla_usage(int err) 465 { 466 int i; 467 468 static const char * const msg[] = { 469 "", 470 "rtla version " VERSION, 471 "", 472 " usage: rtla COMMAND ...", 473 "", 474 " commands:", 475 " osnoise - gives information about the operating system noise (osnoise)", 476 " hwnoise - gives information about hardware-related noise", 477 " timerlat - measures the timer irq and thread latency", 478 "", 479 NULL, 480 }; 481 482 for (i = 0; msg[i]; i++) 483 fprintf(stderr, "%s\n", msg[i]); 484 exit(err); 485 } 486 487 /* 488 * run_tool_command - try to run a rtla tool command 489 * 490 * It returns 0 if it fails. The tool's main will generally not 491 * return as they should call exit(). 492 */ 493 int run_tool_command(int argc, char **argv, int start_position) 494 { 495 if (strcmp(argv[start_position], "osnoise") == 0) { 496 osnoise_main(argc-start_position, &argv[start_position]); 497 goto ran; 498 } else if (strcmp(argv[start_position], "hwnoise") == 0) { 499 hwnoise_main(argc-start_position, &argv[start_position]); 500 goto ran; 501 } else if (strcmp(argv[start_position], "timerlat") == 0) { 502 timerlat_main(argc-start_position, &argv[start_position]); 503 goto ran; 504 } 505 506 return 0; 507 ran: 508 return 1; 509 } 510 511 /* Set main as weak to allow overriding it for building unit test binary */ 512 #pragma weak main 513 514 int main(int argc, char *argv[]) 515 { 516 int retval; 517 518 /* is it an alias? */ 519 retval = run_tool_command(argc, argv, 0); 520 if (retval) 521 exit(0); 522 523 if (argc < 2) 524 goto usage; 525 526 if (strcmp(argv[1], "-h") == 0) 527 rtla_usage(129); 528 else if (strcmp(argv[1], "--help") == 0) 529 rtla_usage(129); 530 531 retval = run_tool_command(argc, argv, 1); 532 if (retval) 533 exit(0); 534 535 usage: 536 rtla_usage(129); 537 } 538