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