xref: /linux/tools/tracing/rtla/src/cli_p.h (revision 92a33d5bad7485b39c7403ad1741b3b2b35a0131)
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 	&params->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 	&params->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", &params->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", &params->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 	&params->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", &params->common.user_data, \
182 	"enable timerlat for user-defined user-space workload")
183 
184 #define RTLA_OPT_DURATION OPT_CALLBACK('d', "duration", &params->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", &params->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", &params->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", &params->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", &params->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", &params->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", &params->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 	&params->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", &params->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 	&params->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", &params->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(&params->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, &params->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(&params->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, &params->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(&params->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, &params->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", &params->period, "us", \
441 	"osnoise period in us", \
442 	LLONG_RANGE(1, 10000000))
443 
444 #define OSNOISE_OPT_RUNTIME RTLA_OPT_LLONG_DATA('r', "runtime", &params->runtime, "us", \
445 	"osnoise runtime in us", \
446 	LLONG_RANGE(100, LLONG_MAX))
447 
448 #define OSNOISE_OPT_THRESHOLD RTLA_OPT_LLONG('T', "threshold", &params->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", &params->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", &params->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 	&params->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 	&params->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", &params->no_aa, \
561 	"disable auto-analysis, reducing rtla timerlat cpu usage")
562 
563 #define TIMERLAT_OPT_DUMPS_TASKS OPT_BOOLEAN(0, "dump-tasks", &params->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", &params->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", &params->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 	&params->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 	&params->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", &params->common.hist.no_irq, \
772 	"ignore IRQ latencies", PARSE_OPT_NOAUTONEG)
773 
774 #define HIST_OPT_NO_THREAD OPT_BOOLEAN_FLAG(0, "no-thread", &params->common.hist.no_thread, \
775 	"ignore thread latencies", PARSE_OPT_NOAUTONEG)
776 
777 #define HIST_OPT_NO_HEADER OPT_BOOLEAN(0, "no-header", &params->common.hist.no_header, \
778 	"do not print header")
779 
780 #define HIST_OPT_NO_SUMMARY OPT_BOOLEAN(0, "no-summary", &params->common.hist.no_summary, \
781 	"do not print summary")
782 
783 #define HIST_OPT_NO_INDEX OPT_BOOLEAN(0, "no-index", &params->common.hist.no_index, \
784 	"do not print index")
785 
786 #define HIST_OPT_WITH_ZEROS OPT_BOOLEAN(0, "with-zeros", &params->common.hist.with_zeros, \
787 	"print zero only entries")
788 
789