1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #pragma once 3 4 #ifndef RTLA_ALLOW_CLI_P_H 5 #error "Private header file included outside of cli.c module" 6 #endif 7 8 #include <limits.h> 9 #include <linux/kernel.h> 10 #include <subcmd/parse-options.h> 11 12 #include "cli.h" 13 #include "osnoise.h" 14 #include "timerlat.h" 15 16 struct osnoise_cb_data { 17 struct osnoise_params *params; 18 char *trace_output; 19 }; 20 21 struct timerlat_cb_data { 22 struct timerlat_params *params; 23 char *trace_output; 24 }; 25 26 /* 27 * Non-zero default values for parameters 28 */ 29 static const int default_dma_latency = -1; /* -1 = unset */ 30 static const int default_deepest_idle_state = -2; /* -1 = disable all, -2 = unset */ 31 static const int default_output_divisor = 1000; 32 static const int default_bucket_size = 1; 33 static const int default_entries = 256; 34 static const enum stack_format default_stack_format = STACK_FORMAT_TRUNCATE; 35 36 /* 37 * Range checking for long long and int option callbacks. 38 * 39 * Pass a pointer to a const struct as opt->data to enable range checking. 40 * If opt->data is NULL, no range check is performed. 41 */ 42 struct llong_range { 43 long long min; 44 long long max; 45 }; 46 47 struct int_range { 48 int min; 49 int max; 50 }; 51 52 #define LLONG_RANGE(lo, hi) \ 53 (&(const struct llong_range){ .min = (lo), .max = (hi) }) 54 55 #define INT_RANGE(lo, hi) \ 56 (&(const struct int_range){ .min = (lo), .max = (hi) }) 57 58 static int check_llong_range(const struct option *opt, long long value) 59 { 60 const struct llong_range *range = opt->data; 61 62 if (!range) 63 return 0; 64 if (value < range->min || value > range->max) { 65 fprintf(stderr, " Error: --%s value %lld is out of range [%lld, %lld]\n", 66 opt->long_name, value, range->min, range->max); 67 return -1; 68 } 69 return 0; 70 } 71 72 static int check_int_range(const struct option *opt, int value) 73 { 74 const struct int_range *range = opt->data; 75 76 if (!range) 77 return 0; 78 if (value < range->min || value > range->max) { 79 fprintf(stderr, " Error: --%s value %d is out of range [%d, %d]\n", 80 opt->long_name, value, range->min, range->max); 81 return -1; 82 } 83 return 0; 84 } 85 86 /* 87 * OPT_CALLBACK variant that populates .data (for range checking). 88 */ 89 #define RTLA_OPT_CALLBACK_DATA(s, l, v, a, h, f, d) \ 90 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \ 91 .value = (v), .argh = (a), .help = (h), .callback = (f), \ 92 .data = (void *)(d) } 93 94 #define RTLA_OPT_CALLBACK_DATA_DEFVAL(s, l, v, a, h, f, d, dv) \ 95 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \ 96 .value = (v), .argh = (a), .help = (h), .callback = (f), \ 97 .data = (void *)(d), .defval = (intptr_t)(dv) } 98 99 /* 100 * Shorthand macros for integer/long long command line options using 101 * opt_int_callback/opt_llong_callback, with variants that set defval 102 * and/or data (for range checking). 103 * 104 * Note: defval's type is intptr_t. opt_int_callback interprets it directly as 105 * an int, opt_llong_callback interprets it as a pointer to a long long, as 106 * long long does not fit into intptr_t on 32-bit architectures. 107 */ 108 #define RTLA_OPT_LLONG(s, l, v, a, h) \ 109 OPT_CALLBACK(s, l, v, a, h, opt_llong_callback) 110 111 #define RTLA_OPT_LLONG_DEFVAL(s, l, v, a, h, d) { .type = OPTION_CALLBACK, \ 112 .short_name = (s), .long_name = (l), .value = (v), .argh = (a), \ 113 .help = (h), .callback = opt_llong_callback, .defval = (intptr_t)(d) } 114 115 #define RTLA_OPT_LLONG_DATA(s, l, v, a, h, d) { .type = OPTION_CALLBACK, \ 116 .short_name = (s), .long_name = (l), .value = (v), .argh = (a), \ 117 .help = (h), .callback = opt_llong_callback, .data = (void *)(d) } 118 119 #define RTLA_OPT_INT(s, l, v, a, h) \ 120 OPT_CALLBACK(s, l, v, a, h, opt_int_callback) 121 122 #define RTLA_OPT_INT_DEFVAL(s, l, v, a, h, d) { .type = OPTION_CALLBACK, \ 123 .short_name = (s), .long_name = (l), .value = (v), .argh = (a), \ 124 .help = (h), .callback = opt_int_callback, .defval = (intptr_t)(d) } 125 126 #define RTLA_OPT_INT_DATA_DEFVAL(s, l, v, a, h, d, dv) { .type = OPTION_CALLBACK, \ 127 .short_name = (s), .long_name = (l), .value = (v), .argh = (a), \ 128 .help = (h), .callback = opt_int_callback, \ 129 .data = (void *)(d), .defval = (intptr_t)(dv) } 130 131 /* 132 * Macros for command line options common to all tools 133 * 134 * Note: Some of the options are common to both timerlat and osnoise, but 135 * have a slightly different meaning. Such options take additional arguments 136 * that have to be provided by the *_parse_args() function of the corresponding 137 * tool. 138 * 139 * All macros defined here assume the presence of a params variable of 140 * the corresponding tool type (i.e struct timerlat_params or struct osnoise_params) 141 * and a cb_data variable of the matching type. 142 */ 143 144 #define RTLA_OPT_STOP(short, long, name) OPT_CALLBACK_FLAG(short, long, \ 145 ¶ms->common.stop_us, \ 146 "us", \ 147 "stop trace if " name " is higher than the argument in us", \ 148 opt_llong_callback, PARSE_OPT_NOAUTONEG) 149 150 #define RTLA_OPT_STOP_TOTAL(short, long, name) OPT_CALLBACK_FLAG(short, long, \ 151 ¶ms->common.stop_total_us, \ 152 "us", \ 153 "stop trace if " name " is higher than the argument in us", \ 154 opt_llong_callback, PARSE_OPT_NOAUTONEG) 155 156 #define RTLA_OPT_TRACE_OUTPUT(tracer, cb) OPT_CALLBACK_OPTARG('t', "trace", \ 157 (const char **)&cb_data.trace_output, \ 158 tracer "_trace.txt", \ 159 "[file]", \ 160 "save the stopped trace to [file|" tracer "_trace.txt]", \ 161 cb) 162 163 #define RTLA_OPT_CPUS OPT_CALLBACK('c', "cpus", ¶ms->common, \ 164 "cpu-list", \ 165 "run the tracer only on the given cpus", \ 166 opt_cpus_cb) 167 168 #define RTLA_OPT_CGROUP OPT_CALLBACK_OPTARG('C', "cgroup", ¶ms->common, \ 169 "[cgroup_name]", NULL, \ 170 "set cgroup, no argument means rtla's cgroup will be inherited", \ 171 opt_cgroup_cb) 172 173 #define RTLA_OPT_USER_THREADS OPT_CALLBACK_NOOPT('u', "user-threads", params, NULL, \ 174 "use rtla user-space threads instead of kernel-space timerlat threads", \ 175 opt_user_threads_cb) 176 177 #define RTLA_OPT_KERNEL_THREADS OPT_BOOLEAN('k', "kernel-threads", \ 178 ¶ms->common.kernel_workload, \ 179 "use timerlat kernel-space threads instead of rtla user-space threads") 180 181 #define RTLA_OPT_USER_LOAD OPT_BOOLEAN('U', "user-load", ¶ms->common.user_data, \ 182 "enable timerlat for user-defined user-space workload") 183 184 #define RTLA_OPT_DURATION OPT_CALLBACK('d', "duration", ¶ms->common, \ 185 "time[s|m|h|d]", \ 186 "set the duration of the session", \ 187 opt_duration_cb) 188 189 #define RTLA_OPT_EVENT OPT_CALLBACK('e', "event", ¶ms->common.events, \ 190 "sys:event", \ 191 "enable the <sys:event> in the trace instance, multiple -e are allowed", \ 192 opt_event_cb) 193 194 #define RTLA_OPT_HOUSEKEEPING OPT_CALLBACK('H', "house-keeping", ¶ms->common, \ 195 "cpu-list", \ 196 "run rtla control threads only on the given cpus", \ 197 opt_housekeeping_cb) 198 199 #define RTLA_OPT_PRIORITY OPT_CALLBACK('P', "priority", ¶ms->common, \ 200 "o:prio|r:prio|f:prio|d:runtime:period", \ 201 "set scheduling parameters", \ 202 opt_priority_cb) 203 204 #define RTLA_OPT_TRIGGER OPT_CALLBACK(0, "trigger", ¶ms->common.events, \ 205 "trigger", \ 206 "enable a trace event trigger to the previous -e event", \ 207 opt_trigger_cb) 208 209 #define RTLA_OPT_FILTER OPT_CALLBACK(0, "filter", ¶ms->common.events, \ 210 "filter", \ 211 "enable a trace event filter to the previous -e event", \ 212 opt_filter_cb) 213 214 #define RTLA_OPT_QUIET OPT_BOOLEAN('q', "quiet", ¶ms->common.quiet, \ 215 "print only a summary at the end") 216 217 #define RTLA_OPT_TRACE_BUFFER_SIZE RTLA_OPT_INT(0, "trace-buffer-size", \ 218 ¶ms->common.buffer_size, "kB", \ 219 "set the per-cpu trace buffer size in kB") 220 221 #define RTLA_OPT_WARM_UP RTLA_OPT_INT(0, "warm-up", ¶ms->common.warmup, "s", \ 222 "let the workload run for s seconds before collecting data") 223 224 #define RTLA_OPT_AUTO(cb) OPT_CALLBACK('a', "auto", &cb_data, "us", \ 225 "set automatic trace mode, stopping the session if argument in us sample is hit", \ 226 cb) 227 228 #define RTLA_OPT_ON_THRESHOLD(threshold, cb) OPT_CALLBACK(0, "on-threshold", \ 229 ¶ms->common.threshold_actions, \ 230 "action", \ 231 "define action to be executed at " threshold " threshold, multiple are allowed", \ 232 cb) 233 234 #define RTLA_OPT_ON_END(cb) OPT_CALLBACK(0, "on-end", ¶ms->common.end_actions, \ 235 "action", \ 236 "define action to be executed at measurement end, multiple are allowed", \ 237 cb) 238 239 #define RTLA_OPT_DEBUG OPT_BOOLEAN('D', "debug", &config_debug, \ 240 "print debug info") 241 242 /* 243 * Common callback functions for command line options 244 */ 245 246 static int opt_llong_callback(const struct option *opt, const char *arg, int unset) 247 { 248 long long *value = opt->value; 249 250 if (unset) { 251 *value = opt->defval ? *(long long *)opt->defval : 0; 252 return 0; 253 } 254 255 if (!arg) 256 return -1; 257 258 *value = get_llong_from_str((char *)arg); 259 if (check_llong_range(opt, *value)) 260 return -1; 261 return 0; 262 } 263 264 static int opt_int_callback(const struct option *opt, const char *arg, int unset) 265 { 266 int *value = opt->value; 267 268 if (unset) { 269 *value = (int)opt->defval; 270 return 0; 271 } 272 273 if (!arg) 274 return -1; 275 276 if (strtoi(arg, value)) 277 return -1; 278 if (check_int_range(opt, *value)) 279 return -1; 280 281 return 0; 282 } 283 284 static int opt_cpus_cb(const struct option *opt, const char *arg, int unset) 285 { 286 struct common_params *params = opt->value; 287 int retval; 288 289 if (unset) { 290 CPU_ZERO(¶ms->monitored_cpus); 291 params->cpus = NULL; 292 return 0; 293 } 294 295 if (!arg) 296 return -1; 297 298 retval = parse_cpu_set((char *)arg, ¶ms->monitored_cpus); 299 if (retval) 300 fatal("Invalid -c cpu list"); 301 params->cpus = (char *)arg; 302 303 return 0; 304 } 305 306 static int opt_cgroup_cb(const struct option *opt, const char *arg, int unset) 307 { 308 struct common_params *params = opt->value; 309 310 if (unset) { 311 params->cgroup = 0; 312 params->cgroup_name = NULL; 313 return 0; 314 } 315 316 params->cgroup = 1; 317 params->cgroup_name = (char *)arg; 318 if (params->cgroup_name && params->cgroup_name[0] == '=') 319 /* Allow -C=<cgroup_name> next to -C[ ]<cgroup_name> */ 320 ++params->cgroup_name; 321 322 return 0; 323 } 324 325 static int opt_duration_cb(const struct option *opt, const char *arg, int unset) 326 { 327 struct common_params *params = opt->value; 328 329 if (unset) { 330 params->duration = 0; 331 return 0; 332 } 333 334 if (!arg) 335 return -1; 336 337 params->duration = parse_seconds_duration((char *)arg); 338 if (!params->duration) 339 fatal("Invalid -d duration"); 340 341 return 0; 342 } 343 344 static int opt_event_cb(const struct option *opt, const char *arg, int unset) 345 { 346 struct trace_events **events = opt->value; 347 struct trace_events *tevent; 348 349 if (unset || !arg) 350 return -1; 351 352 tevent = trace_event_alloc((char *)arg); 353 if (!tevent) 354 fatal("Error alloc trace event"); 355 356 if (*events) 357 tevent->next = *events; 358 *events = tevent; 359 360 return 0; 361 } 362 363 static int opt_housekeeping_cb(const struct option *opt, const char *arg, int unset) 364 { 365 struct common_params *params = opt->value; 366 int retval; 367 368 if (unset) { 369 params->hk_cpus = 0; 370 CPU_ZERO(¶ms->hk_cpu_set); 371 return 0; 372 } 373 374 if (!arg) 375 return -1; 376 377 params->hk_cpus = 1; 378 retval = parse_cpu_set((char *)arg, ¶ms->hk_cpu_set); 379 if (retval) 380 fatal("Error parsing house keeping CPUs"); 381 382 return 0; 383 } 384 385 static int opt_priority_cb(const struct option *opt, const char *arg, int unset) 386 { 387 struct common_params *params = opt->value; 388 int retval; 389 390 if (unset) { 391 memset(¶ms->sched_param, 0, sizeof(params->sched_param)); 392 params->set_sched = 0; 393 return 0; 394 } 395 396 if (!arg) 397 return -1; 398 399 retval = parse_prio((char *)arg, ¶ms->sched_param); 400 if (retval == -1) 401 fatal("Invalid -P priority"); 402 params->set_sched = 1; 403 404 return 0; 405 } 406 407 static int opt_trigger_cb(const struct option *opt, const char *arg, int unset) 408 { 409 struct trace_events **events = opt->value; 410 411 if (unset || !arg) 412 return -1; 413 414 if (!*events) 415 fatal("--trigger requires a previous -e"); 416 417 trace_event_add_trigger(*events, (char *)arg); 418 419 return 0; 420 } 421 422 static int opt_filter_cb(const struct option *opt, const char *arg, int unset) 423 { 424 struct trace_events **events = opt->value; 425 426 if (unset || !arg) 427 return -1; 428 429 if (!*events) 430 fatal("--filter requires a previous -e"); 431 432 trace_event_add_filter(*events, (char *)arg); 433 434 return 0; 435 } 436 437 /* 438 * Macros for command line options specific to osnoise 439 */ 440 #define OSNOISE_OPT_PERIOD RTLA_OPT_LLONG_DATA('p', "period", ¶ms->period, "us", \ 441 "osnoise period in us", \ 442 LLONG_RANGE(1, 10000000)) 443 444 #define OSNOISE_OPT_RUNTIME RTLA_OPT_LLONG_DATA('r', "runtime", ¶ms->runtime, "us", \ 445 "osnoise runtime in us", \ 446 LLONG_RANGE(100, LLONG_MAX)) 447 448 #define OSNOISE_OPT_THRESHOLD RTLA_OPT_LLONG('T', "threshold", ¶ms->threshold, "us", \ 449 "the minimum delta to be considered a noise") 450 451 /* 452 * Callback functions for command line options for osnoise tools 453 */ 454 455 static int opt_osnoise_auto_cb(const struct option *opt, const char *arg, int unset) 456 { 457 struct osnoise_cb_data *cb_data = opt->value; 458 struct osnoise_params *params = cb_data->params; 459 long long auto_thresh; 460 461 if (unset) { 462 params->common.stop_us = 0; 463 params->threshold = 0; 464 cb_data->trace_output = NULL; 465 return 0; 466 } 467 468 if (!arg) 469 return -1; 470 471 auto_thresh = get_llong_from_str((char *)arg); 472 params->common.stop_us = auto_thresh; 473 params->threshold = 1; 474 475 if (!cb_data->trace_output) 476 cb_data->trace_output = "osnoise_trace.txt"; 477 478 return 0; 479 } 480 481 static int opt_osnoise_trace_output_cb(const struct option *opt, const char *arg, int unset) 482 { 483 const char **trace_output = opt->value; 484 485 if (unset) { 486 *trace_output = NULL; 487 return 0; 488 } 489 490 if (!arg) { 491 *trace_output = "osnoise_trace.txt"; 492 } else { 493 *trace_output = (char *)arg; 494 if (*trace_output && (*trace_output)[0] == '=') 495 /* Allow -t=<trace_output> next to -t[ ]<trace_output> */ 496 ++*trace_output; 497 } 498 499 return 0; 500 } 501 502 static int opt_osnoise_on_threshold_cb(const struct option *opt, const char *arg, int unset) 503 { 504 struct actions *actions = opt->value; 505 int retval; 506 507 if (unset || !arg) 508 return -1; 509 510 retval = actions_parse(actions, (char *)arg, "osnoise_trace.txt"); 511 if (retval) 512 fatal("Invalid action %s", arg); 513 514 return 0; 515 } 516 517 static int opt_osnoise_on_end_cb(const struct option *opt, const char *arg, int unset) 518 { 519 struct actions *actions = opt->value; 520 int retval; 521 522 if (unset || !arg) 523 return -1; 524 525 retval = actions_parse(actions, (char *)arg, "osnoise_trace.txt"); 526 if (retval) 527 fatal("Invalid action %s", arg); 528 529 return 0; 530 } 531 532 /* 533 * Macros for command line options specific to timerlat 534 */ 535 #define TIMERLAT_OPT_PERIOD RTLA_OPT_LLONG_DATA('p', "period", ¶ms->timerlat_period_us, "us", \ 536 "timerlat period in us", \ 537 LLONG_RANGE(100, 1000000)) 538 539 #define TIMERLAT_OPT_STACK RTLA_OPT_LLONG('s', "stack", ¶ms->print_stack, "us", \ 540 "save the stack trace at the IRQ if a thread latency is higher than the argument in us") 541 542 #define TIMERLAT_OPT_NANO OPT_CALLBACK_NOOPT('n', "nano", params, NULL, \ 543 "display data in nanoseconds", \ 544 opt_nano_cb) 545 546 #define TIMERLAT_OPT_DMA_LATENCY RTLA_OPT_INT_DATA_DEFVAL(0, "dma-latency", \ 547 ¶ms->dma_latency, "us", \ 548 "set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency", \ 549 INT_RANGE(0, 10000), default_dma_latency) 550 551 #define TIMERLAT_OPT_DEEPEST_IDLE_STATE RTLA_OPT_INT_DATA_DEFVAL(0, "deepest-idle-state", \ 552 ¶ms->deepest_idle_state, "n", \ 553 "only go down to idle state n on cpus used by timerlat to reduce exit from idle latency", \ 554 INT_RANGE(-1, INT_MAX), default_deepest_idle_state) 555 556 #define TIMERLAT_OPT_AA_ONLY OPT_CALLBACK(0, "aa-only", params, "us", \ 557 "stop if <us> latency is hit, only printing the auto analysis (reduces CPU usage)", \ 558 opt_aa_only_cb) 559 560 #define TIMERLAT_OPT_NO_AA OPT_BOOLEAN(0, "no-aa", ¶ms->no_aa, \ 561 "disable auto-analysis, reducing rtla timerlat cpu usage") 562 563 #define TIMERLAT_OPT_DUMPS_TASKS OPT_BOOLEAN(0, "dump-tasks", ¶ms->dump_tasks, \ 564 "prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)") 565 566 #define TIMERLAT_OPT_BPF_ACTION OPT_STRING(0, "bpf-action", ¶ms->bpf_action_program, \ 567 "program", \ 568 "load and execute BPF program when latency threshold is exceeded") 569 570 #define TIMERLAT_OPT_STACK_FORMAT OPT_CALLBACK(0, "stack-format", ¶ms->stack_format, "format", \ 571 "set the stack format (truncate, skip, full)", \ 572 opt_stack_format_cb) 573 574 #define TIMERLAT_OPT_ALIGNED RTLA_OPT_CALLBACK_DATA('A', "aligned", params, "us", \ 575 "align thread wakeups to a specific offset", \ 576 opt_timerlat_align_cb, LLONG_RANGE(0, LLONG_MAX)) 577 578 /* 579 * Callback functions for command line options for timerlat tools 580 */ 581 582 static int opt_timerlat_auto_cb(const struct option *opt, const char *arg, int unset) 583 { 584 struct timerlat_cb_data *cb_data = opt->value; 585 struct timerlat_params *params = cb_data->params; 586 long long auto_thresh; 587 588 if (unset) { 589 params->common.stop_total_us = 0; 590 params->common.stop_us = 0; 591 params->print_stack = 0; 592 cb_data->trace_output = NULL; 593 return 0; 594 } 595 596 if (!arg) 597 return -1; 598 599 auto_thresh = get_llong_from_str((char *)arg); 600 params->common.stop_total_us = auto_thresh; 601 params->common.stop_us = auto_thresh; 602 params->print_stack = auto_thresh; 603 604 if (!cb_data->trace_output) 605 cb_data->trace_output = "timerlat_trace.txt"; 606 607 return 0; 608 } 609 610 static int opt_aa_only_cb(const struct option *opt, const char *arg, int unset) 611 { 612 struct timerlat_params *params = opt->value; 613 long long auto_thresh; 614 615 if (unset) { 616 params->common.stop_total_us = 0; 617 params->common.stop_us = 0; 618 params->print_stack = 0; 619 params->common.aa_only = 0; 620 return 0; 621 } 622 623 if (!arg) 624 return -1; 625 626 auto_thresh = get_llong_from_str((char *)arg); 627 params->common.stop_total_us = auto_thresh; 628 params->common.stop_us = auto_thresh; 629 params->print_stack = auto_thresh; 630 params->common.aa_only = 1; 631 632 return 0; 633 } 634 635 static int opt_timerlat_trace_output_cb(const struct option *opt, const char *arg, int unset) 636 { 637 const char **trace_output = opt->value; 638 639 if (unset) { 640 *trace_output = NULL; 641 return 0; 642 } 643 644 if (!arg) { 645 *trace_output = "timerlat_trace.txt"; 646 } else { 647 *trace_output = (char *)arg; 648 if (*trace_output && (*trace_output)[0] == '=') 649 /* Allow -t=<trace_output> next to -t[ ]<trace_output> */ 650 ++*trace_output; 651 } 652 653 return 0; 654 } 655 656 static int opt_timerlat_on_threshold_cb(const struct option *opt, const char *arg, int unset) 657 { 658 struct actions *actions = opt->value; 659 int retval; 660 661 if (unset || !arg) 662 return -1; 663 664 retval = actions_parse(actions, (char *)arg, "timerlat_trace.txt"); 665 if (retval) 666 fatal("Invalid action %s", arg); 667 668 return 0; 669 } 670 671 static int opt_timerlat_on_end_cb(const struct option *opt, const char *arg, int unset) 672 { 673 struct actions *actions = opt->value; 674 int retval; 675 676 if (unset || !arg) 677 return -1; 678 679 retval = actions_parse(actions, (char *)arg, "timerlat_trace.txt"); 680 if (retval) 681 fatal("Invalid action %s", arg); 682 683 return 0; 684 } 685 686 static int opt_user_threads_cb(const struct option *opt, const char *arg, int unset) 687 { 688 struct timerlat_params *params = opt->value; 689 690 if (unset) { 691 params->common.user_workload = false; 692 params->common.user_data = false; 693 return 0; 694 } 695 696 params->common.user_workload = true; 697 params->common.user_data = true; 698 699 return 0; 700 } 701 702 static int opt_nano_cb(const struct option *opt, const char *arg, int unset) 703 { 704 struct timerlat_params *params = opt->value; 705 706 if (unset) { 707 params->common.output_divisor = default_output_divisor; 708 return 0; 709 } 710 711 params->common.output_divisor = 1; 712 713 return 0; 714 } 715 716 static int opt_stack_format_cb(const struct option *opt, const char *arg, int unset) 717 { 718 int *format = opt->value; 719 720 if (unset) { 721 *format = default_stack_format; 722 return 0; 723 } 724 725 if (!arg) 726 return -1; 727 728 *format = parse_stack_format((char *)arg); 729 730 if (*format == -1) 731 fatal("Invalid --stack-format option"); 732 733 return 0; 734 } 735 736 static int opt_timerlat_align_cb(const struct option *opt, const char *arg, int unset) 737 { 738 struct timerlat_params *params = opt->value; 739 740 if (unset) { 741 params->timerlat_align = false; 742 params->timerlat_align_us = 0; 743 return 0; 744 } 745 746 if (!arg) 747 return -1; 748 749 params->timerlat_align = true; 750 params->timerlat_align_us = get_llong_from_str((char *)arg); 751 if (check_llong_range(opt, params->timerlat_align_us)) 752 return -1; 753 754 return 0; 755 } 756 757 /* 758 * Macros for command line options specific to histogram-based tools 759 */ 760 761 #define HIST_OPT_BUCKET_SIZE RTLA_OPT_INT_DATA_DEFVAL('b', "bucket-size", \ 762 ¶ms->common.hist.bucket_size, "N", \ 763 "set the histogram bucket size (default 1)", \ 764 INT_RANGE(1, 999999), default_bucket_size) 765 766 #define HIST_OPT_ENTRIES RTLA_OPT_INT_DATA_DEFVAL('E', "entries", \ 767 ¶ms->common.hist.entries, "N", \ 768 "set the number of entries of the histogram (default 256)", \ 769 INT_RANGE(10, 9999999), default_entries) 770 771 #define HIST_OPT_NO_IRQ OPT_BOOLEAN_FLAG(0, "no-irq", ¶ms->common.hist.no_irq, \ 772 "ignore IRQ latencies", PARSE_OPT_NOAUTONEG) 773 774 #define HIST_OPT_NO_THREAD OPT_BOOLEAN_FLAG(0, "no-thread", ¶ms->common.hist.no_thread, \ 775 "ignore thread latencies", PARSE_OPT_NOAUTONEG) 776 777 #define HIST_OPT_NO_HEADER OPT_BOOLEAN(0, "no-header", ¶ms->common.hist.no_header, \ 778 "do not print header") 779 780 #define HIST_OPT_NO_SUMMARY OPT_BOOLEAN(0, "no-summary", ¶ms->common.hist.no_summary, \ 781 "do not print summary") 782 783 #define HIST_OPT_NO_INDEX OPT_BOOLEAN(0, "no-index", ¶ms->common.hist.no_index, \ 784 "do not print index") 785 786 #define HIST_OPT_WITH_ZEROS OPT_BOOLEAN(0, "with-zeros", ¶ms->common.hist.with_zeros, \ 787 "print zero only entries") 788 789