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