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