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