xref: /linux/tools/tracing/rtla/src/cli_p.h (revision 0ad45018ace734e3a21c8b15280df65b429135d1)
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 	&params->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 	&params->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", &params->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", &params->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 	&params->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", &params->common.user_data, \
183 	"enable timerlat for user-defined user-space workload")
184 
185 #define RTLA_OPT_DURATION OPT_CALLBACK('d', "duration", &params->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", &params->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", &params->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", &params->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", &params->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", &params->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", &params->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 	&params->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", &params->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 	&params->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", &params->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(&params->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, &params->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(&params->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, &params->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(&params->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, &params->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", &params->period, "us", \
490 	"osnoise period in us", \
491 	LLONG_RANGE(1, 10000000))
492 
493 #define OSNOISE_OPT_RUNTIME RTLA_OPT_LLONG_DATA('r', "runtime", &params->runtime, "us", \
494 	"osnoise runtime in us", \
495 	LLONG_RANGE(100, LLONG_MAX))
496 
497 #define OSNOISE_OPT_THRESHOLD RTLA_OPT_LLONG('T', "threshold", &params->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", &params->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", &params->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 	&params->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 	&params->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", &params->no_aa, \
615 	"disable auto-analysis, reducing rtla timerlat cpu usage")
616 
617 #define TIMERLAT_OPT_DUMPS_TASKS OPT_BOOLEAN(0, "dump-tasks", &params->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", &params->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", &params->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 	&params->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 	&params->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", &params->common.hist.no_irq, \
838 	"ignore IRQ latencies", PARSE_OPT_NOAUTONEG)
839 
840 #define HIST_OPT_NO_THREAD OPT_BOOLEAN_FLAG(0, "no-thread", &params->common.hist.no_thread, \
841 	"ignore thread latencies", PARSE_OPT_NOAUTONEG)
842 
843 #define HIST_OPT_NO_HEADER OPT_BOOLEAN(0, "no-header", &params->common.hist.no_header, \
844 	"do not print header")
845 
846 #define HIST_OPT_NO_SUMMARY OPT_BOOLEAN(0, "no-summary", &params->common.hist.no_summary, \
847 	"do not print summary")
848 
849 #define HIST_OPT_NO_INDEX OPT_BOOLEAN(0, "no-index", &params->common.hist.no_index, \
850 	"do not print index")
851 
852 #define HIST_OPT_WITH_ZEROS OPT_BOOLEAN(0, "with-zeros", &params->common.hist.with_zeros, \
853 	"print zero only entries")
854 
855