xref: /linux/tools/tracing/rtla/src/cli.c (revision deaec85cd8bad3841412ff8cefec463f2688806b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
4  */
5 
6 #define _GNU_SOURCE
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 
13 #include <linux/compiler.h>
14 
15 #define RTLA_ALLOW_CLI_P_H
16 #include "cli_p.h"
17 
18 static const char * const osnoise_top_usage[] = {
19 	"rtla osnoise [top] [<options>] [-h|--help]",
20 	NULL,
21 };
22 
23 static const char * const osnoise_hist_usage[] = {
24 	"rtla osnoise hist [<options>] [-h|--help]",
25 	NULL,
26 };
27 
28 static const char * const timerlat_top_usage[] = {
29 	"rtla timerlat [top] [<options>] [-h|--help]",
30 	NULL,
31 };
32 
33 static const char * const timerlat_hist_usage[] = {
34 	"rtla timerlat hist [<options>] [-h|--help]",
35 	NULL,
36 };
37 
38 static const char * const hwnoise_usage[] = {
39 	"rtla hwnoise [<options>] [-h|--help]",
40 	NULL,
41 };
42 
43 static const int common_parse_options_flags = PARSE_OPT_OPTARG_ALLOW_NEXT;
44 
45 bool in_unit_test;
46 
47 /*
48  * osnoise_top_parse_args - allocs, parse and fill the cmd line parameters
49  */
50 struct common_params *osnoise_top_parse_args(int argc, char **argv)
51 {
52 	struct osnoise_params *params;
53 	struct osnoise_cb_data cb_data;
54 	const char * const *usage;
55 
56 	params = calloc_fatal(1, sizeof(*params));
57 
58 	cb_data.params = params;
59 	cb_data.trace_output = NULL;
60 
61 	if (strcmp(argv[0], "hwnoise") == 0) {
62 		params->mode = MODE_HWNOISE;
63 		/*
64 		 * Reduce CPU usage for 75% to avoid killing the system.
65 		 */
66 		params->runtime = 750000;
67 		params->period = 1000000;
68 		usage = hwnoise_usage;
69 	} else {
70 		usage = osnoise_top_usage;
71 	}
72 
73 	const struct option osnoise_top_options[] = {
74 	OPT_GROUP("Tracing Options:"),
75 		OSNOISE_OPT_PERIOD,
76 		OSNOISE_OPT_RUNTIME,
77 		RTLA_OPT_STOP('s', "stop", "single sample"),
78 		RTLA_OPT_STOP_TOTAL('S', "stop-total", "total sample"),
79 		OSNOISE_OPT_THRESHOLD,
80 		RTLA_OPT_TRACE_OUTPUT("osnoise", opt_osnoise_trace_output_cb),
81 
82 	OPT_GROUP("Event Configuration:"),
83 		RTLA_OPT_EVENT,
84 		RTLA_OPT_FILTER,
85 		RTLA_OPT_TRIGGER,
86 
87 	OPT_GROUP("CPU Configuration:"),
88 		RTLA_OPT_CPUS,
89 		RTLA_OPT_HOUSEKEEPING,
90 
91 	OPT_GROUP("Thread Configuration:"),
92 		RTLA_OPT_PRIORITY,
93 		RTLA_OPT_CGROUP,
94 
95 	OPT_GROUP("Output:"),
96 		RTLA_OPT_QUIET,
97 
98 	OPT_GROUP("System Tuning:"),
99 		RTLA_OPT_TRACE_BUFFER_SIZE,
100 		RTLA_OPT_WARM_UP,
101 
102 	OPT_GROUP("Auto Analysis and Actions:"),
103 		RTLA_OPT_AUTO(opt_osnoise_auto_cb),
104 		RTLA_OPT_ON_THRESHOLD("stop-total", opt_osnoise_on_threshold_cb),
105 		RTLA_OPT_ON_END(opt_osnoise_on_end_cb),
106 
107 	OPT_GROUP("General:"),
108 		RTLA_OPT_DURATION,
109 		RTLA_OPT_DEBUG,
110 
111 	OPT_END(),
112 	};
113 
114 	actions_init(&params->common.threshold_actions);
115 	actions_init(&params->common.end_actions);
116 
117 	argc = parse_options(argc, (const char **)argv,
118 			     osnoise_top_options,
119 			     usage,
120 			     common_parse_options_flags);
121 	if (argc < 0)
122 		return NULL;
123 
124 	if (cb_data.trace_output)
125 		actions_add_trace_output(&params->common.threshold_actions, cb_data.trace_output);
126 
127 	if (geteuid() && !in_unit_test)
128 		fatal("osnoise needs root permission");
129 
130 	return &params->common;
131 }
132 
133 /*
134  * osnoise_hist_parse_args - allocs, parse and fill the cmd line parameters
135  */
136 struct common_params *osnoise_hist_parse_args(int argc, char **argv)
137 {
138 	struct osnoise_params *params;
139 	struct osnoise_cb_data cb_data;
140 
141 	params = calloc_fatal(1, sizeof(*params));
142 
143 	cb_data.params = params;
144 	cb_data.trace_output = NULL;
145 
146 	const struct option osnoise_hist_options[] = {
147 	OPT_GROUP("Tracing Options:"),
148 		OSNOISE_OPT_PERIOD,
149 		OSNOISE_OPT_RUNTIME,
150 		RTLA_OPT_STOP('s', "stop", "single sample"),
151 		RTLA_OPT_STOP_TOTAL('S', "stop-total", "total sample"),
152 		OSNOISE_OPT_THRESHOLD,
153 		RTLA_OPT_TRACE_OUTPUT("osnoise", opt_osnoise_trace_output_cb),
154 
155 	OPT_GROUP("Event Configuration:"),
156 		RTLA_OPT_EVENT,
157 		RTLA_OPT_FILTER,
158 		RTLA_OPT_TRIGGER,
159 
160 	OPT_GROUP("CPU Configuration:"),
161 		RTLA_OPT_CPUS,
162 		RTLA_OPT_HOUSEKEEPING,
163 
164 	OPT_GROUP("Thread Configuration:"),
165 		RTLA_OPT_PRIORITY,
166 		RTLA_OPT_CGROUP,
167 
168 	OPT_GROUP("Histogram Options:"),
169 		HIST_OPT_BUCKET_SIZE,
170 		HIST_OPT_ENTRIES,
171 		HIST_OPT_NO_HEADER,
172 		HIST_OPT_NO_SUMMARY,
173 		HIST_OPT_NO_INDEX,
174 		HIST_OPT_WITH_ZEROS,
175 
176 	OPT_GROUP("System Tuning:"),
177 		RTLA_OPT_TRACE_BUFFER_SIZE,
178 		RTLA_OPT_WARM_UP,
179 
180 	OPT_GROUP("Auto Analysis and Actions:"),
181 		RTLA_OPT_AUTO(opt_osnoise_auto_cb),
182 		RTLA_OPT_ON_THRESHOLD("stop-total", opt_osnoise_on_threshold_cb),
183 		RTLA_OPT_ON_END(opt_osnoise_on_end_cb),
184 
185 	OPT_GROUP("General:"),
186 		RTLA_OPT_DURATION,
187 		RTLA_OPT_DEBUG,
188 
189 	OPT_END(),
190 	};
191 
192 	actions_init(&params->common.threshold_actions);
193 	actions_init(&params->common.end_actions);
194 
195 	/* set default values */
196 	params->common.output_divisor = default_output_divisor;
197 	params->common.hist.bucket_size = default_bucket_size;
198 	params->common.hist.entries = default_entries;
199 
200 	argc = parse_options(argc, (const char **)argv,
201 			     osnoise_hist_options, osnoise_hist_usage,
202 			     common_parse_options_flags);
203 	if (argc < 0)
204 		return NULL;
205 
206 	if (cb_data.trace_output)
207 		actions_add_trace_output(&params->common.threshold_actions, cb_data.trace_output);
208 
209 	if (geteuid() && !in_unit_test)
210 		fatal("rtla needs root permission");
211 
212 	if (params->common.hist.no_index && !params->common.hist.with_zeros)
213 		fatal("no-index set and with-zeros not set - it does not make sense");
214 
215 	return &params->common;
216 }
217 
218 struct common_params *timerlat_top_parse_args(int argc, char **argv)
219 {
220 	struct timerlat_params *params;
221 	struct timerlat_cb_data cb_data;
222 
223 	params = calloc_fatal(1, sizeof(*params));
224 
225 	cb_data.params = params;
226 	cb_data.trace_output = NULL;
227 
228 	const struct option timerlat_top_options[] = {
229 	OPT_GROUP("Tracing Options:"),
230 		TIMERLAT_OPT_PERIOD,
231 		RTLA_OPT_STOP('i', "irq", "irq latency"),
232 		RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"),
233 		TIMERLAT_OPT_STACK,
234 		RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb),
235 
236 	OPT_GROUP("Event Configuration:"),
237 		RTLA_OPT_EVENT,
238 		RTLA_OPT_FILTER,
239 		RTLA_OPT_TRIGGER,
240 
241 	OPT_GROUP("CPU Configuration:"),
242 		RTLA_OPT_CPUS,
243 		RTLA_OPT_HOUSEKEEPING,
244 
245 	OPT_GROUP("Thread Configuration:"),
246 		RTLA_OPT_PRIORITY,
247 		RTLA_OPT_CGROUP,
248 		RTLA_OPT_USER_THREADS,
249 		RTLA_OPT_KERNEL_THREADS,
250 		RTLA_OPT_USER_LOAD,
251 		TIMERLAT_OPT_ALIGNED,
252 
253 	OPT_GROUP("Output:"),
254 		TIMERLAT_OPT_NANO,
255 		RTLA_OPT_QUIET,
256 
257 	OPT_GROUP("System Tuning:"),
258 		TIMERLAT_OPT_DMA_LATENCY,
259 		TIMERLAT_OPT_DEEPEST_IDLE_STATE,
260 		RTLA_OPT_TRACE_BUFFER_SIZE,
261 		RTLA_OPT_WARM_UP,
262 
263 	OPT_GROUP("Auto Analysis and Actions:"),
264 		RTLA_OPT_AUTO(opt_timerlat_auto_cb),
265 		TIMERLAT_OPT_AA_ONLY,
266 		TIMERLAT_OPT_NO_AA,
267 		TIMERLAT_OPT_DUMPS_TASKS,
268 		RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb),
269 		RTLA_OPT_ON_END(opt_timerlat_on_end_cb),
270 		TIMERLAT_OPT_BPF_ACTION,
271 		TIMERLAT_OPT_STACK_FORMAT,
272 
273 	OPT_GROUP("General:"),
274 		RTLA_OPT_DURATION,
275 		RTLA_OPT_DEBUG,
276 
277 	OPT_END(),
278 	};
279 
280 	actions_init(&params->common.threshold_actions);
281 	actions_init(&params->common.end_actions);
282 
283 	/* set default values */
284 	params->dma_latency = default_dma_latency;
285 	params->deepest_idle_state = default_deepest_idle_state;
286 	params->common.output_divisor = default_output_divisor;
287 	params->stack_format = default_stack_format;
288 
289 	/* default to BPF mode */
290 	params->mode = TRACING_MODE_BPF;
291 
292 	argc = parse_options(argc, (const char **)argv,
293 			     timerlat_top_options, timerlat_top_usage,
294 			     common_parse_options_flags);
295 	if (argc < 0)
296 		return NULL;
297 
298 	if (cb_data.trace_output)
299 		actions_add_trace_output(&params->common.threshold_actions, cb_data.trace_output);
300 
301 	if (geteuid() && !in_unit_test)
302 		fatal("rtla needs root permission");
303 
304 	/*
305 	 * Auto analysis only happens if stop tracing, thus:
306 	 */
307 	if (!params->common.stop_us && !params->common.stop_total_us)
308 		params->no_aa = 1;
309 
310 	if (params->no_aa && params->common.aa_only)
311 		fatal("--no-aa and --aa-only are mutually exclusive!");
312 
313 	if (params->common.kernel_workload && params->common.user_workload)
314 		fatal("--kernel-threads and --user-threads are mutually exclusive!");
315 
316 	/*
317 	 * If auto-analysis or trace output is enabled, switch from BPF mode to
318 	 * mixed mode
319 	 */
320 	if (params->mode == TRACING_MODE_BPF &&
321 		(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
322 		params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
323 		!params->no_aa))
324 		params->mode = TRACING_MODE_MIXED;
325 
326 	return &params->common;
327 }
328 
329 struct common_params *timerlat_hist_parse_args(int argc, char **argv)
330 {
331 	struct timerlat_params *params;
332 	struct timerlat_cb_data cb_data;
333 
334 	params = calloc_fatal(1, sizeof(*params));
335 
336 	cb_data.params = params;
337 	cb_data.trace_output = NULL;
338 
339 	const struct option timerlat_hist_options[] = {
340 	OPT_GROUP("Tracing Options:"),
341 		TIMERLAT_OPT_PERIOD,
342 		RTLA_OPT_STOP('i', "irq", "irq latency"),
343 		RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"),
344 		TIMERLAT_OPT_STACK,
345 		RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb),
346 
347 	OPT_GROUP("Event Configuration:"),
348 		RTLA_OPT_EVENT,
349 		RTLA_OPT_FILTER,
350 		RTLA_OPT_TRIGGER,
351 
352 	OPT_GROUP("CPU Configuration:"),
353 		RTLA_OPT_CPUS,
354 		RTLA_OPT_HOUSEKEEPING,
355 
356 	OPT_GROUP("Thread Configuration:"),
357 		RTLA_OPT_PRIORITY,
358 		RTLA_OPT_CGROUP,
359 		RTLA_OPT_USER_THREADS,
360 		RTLA_OPT_KERNEL_THREADS,
361 		RTLA_OPT_USER_LOAD,
362 		TIMERLAT_OPT_ALIGNED,
363 
364 	OPT_GROUP("Histogram Options:"),
365 		HIST_OPT_BUCKET_SIZE,
366 		HIST_OPT_ENTRIES,
367 		HIST_OPT_NO_IRQ,
368 		HIST_OPT_NO_THREAD,
369 		HIST_OPT_NO_HEADER,
370 		HIST_OPT_NO_SUMMARY,
371 		HIST_OPT_NO_INDEX,
372 		HIST_OPT_WITH_ZEROS,
373 
374 	OPT_GROUP("Output:"),
375 		TIMERLAT_OPT_NANO,
376 
377 	OPT_GROUP("System Tuning:"),
378 		TIMERLAT_OPT_DMA_LATENCY,
379 		TIMERLAT_OPT_DEEPEST_IDLE_STATE,
380 		RTLA_OPT_TRACE_BUFFER_SIZE,
381 		RTLA_OPT_WARM_UP,
382 
383 	OPT_GROUP("Auto Analysis and Actions:"),
384 		RTLA_OPT_AUTO(opt_timerlat_auto_cb),
385 		TIMERLAT_OPT_NO_AA,
386 		TIMERLAT_OPT_DUMPS_TASKS,
387 		RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb),
388 		RTLA_OPT_ON_END(opt_timerlat_on_end_cb),
389 		TIMERLAT_OPT_BPF_ACTION,
390 		TIMERLAT_OPT_STACK_FORMAT,
391 
392 	OPT_GROUP("General:"),
393 		RTLA_OPT_DURATION,
394 		RTLA_OPT_DEBUG,
395 
396 	OPT_END(),
397 	};
398 
399 	actions_init(&params->common.threshold_actions);
400 	actions_init(&params->common.end_actions);
401 
402 	/* set default values */
403 	params->dma_latency = default_dma_latency;
404 	params->deepest_idle_state = default_deepest_idle_state;
405 	params->common.output_divisor = default_output_divisor;
406 	params->common.hist.bucket_size = default_bucket_size;
407 	params->common.hist.entries = default_entries;
408 	params->stack_format = default_stack_format;
409 
410 	/* default to BPF mode */
411 	params->mode = TRACING_MODE_BPF;
412 
413 	argc = parse_options(argc, (const char **)argv,
414 			     timerlat_hist_options, timerlat_hist_usage,
415 			     common_parse_options_flags);
416 	if (argc < 0)
417 		return NULL;
418 
419 	if (cb_data.trace_output)
420 		actions_add_trace_output(&params->common.threshold_actions, cb_data.trace_output);
421 
422 	if (geteuid() && !in_unit_test)
423 		fatal("rtla needs root permission");
424 
425 	if (params->common.hist.no_irq && params->common.hist.no_thread)
426 		fatal("no-irq and no-thread set, there is nothing to do here");
427 
428 	if (params->common.hist.no_index && !params->common.hist.with_zeros)
429 		fatal("no-index set with with-zeros is not set - it does not make sense");
430 
431 	/*
432 	 * Auto analysis only happens if stop tracing, thus:
433 	 */
434 	if (!params->common.stop_us && !params->common.stop_total_us)
435 		params->no_aa = 1;
436 
437 	if (params->common.kernel_workload && params->common.user_workload)
438 		fatal("--kernel-threads and --user-threads are mutually exclusive!");
439 
440 	/*
441 	 * If auto-analysis or trace output is enabled, switch from BPF mode to
442 	 * mixed mode
443 	 */
444 	if (params->mode == TRACING_MODE_BPF &&
445 		(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
446 		params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
447 		!params->no_aa))
448 		params->mode = TRACING_MODE_MIXED;
449 
450 	return &params->common;
451 }
452 
453 /*
454  * rtla_usage - print rtla usage
455  */
456 __noreturn static void rtla_usage(int err)
457 {
458 	int i;
459 
460 	static const char * const msg[] = {
461 		"",
462 		"rtla version " VERSION,
463 		"",
464 		"  usage: rtla COMMAND ...",
465 		"",
466 		"  commands:",
467 		"     osnoise  - gives information about the operating system noise (osnoise)",
468 		"     hwnoise  - gives information about hardware-related noise",
469 		"     timerlat - measures the timer irq and thread latency",
470 		"",
471 		NULL,
472 	};
473 
474 	for (i = 0; msg[i]; i++)
475 		fprintf(stderr, "%s\n", msg[i]);
476 	exit(err);
477 }
478 
479 /*
480  * run_tool_command - try to run a rtla tool command
481  *
482  * It returns 0 if it fails. The tool's main will generally not
483  * return as they should call exit().
484  */
485 int run_tool_command(int argc, char **argv, int start_position)
486 {
487 	if (strcmp(argv[start_position], "osnoise") == 0) {
488 		osnoise_main(argc-start_position, &argv[start_position]);
489 		goto ran;
490 	} else if (strcmp(argv[start_position], "hwnoise") == 0) {
491 		hwnoise_main(argc-start_position, &argv[start_position]);
492 		goto ran;
493 	} else if (strcmp(argv[start_position], "timerlat") == 0) {
494 		timerlat_main(argc-start_position, &argv[start_position]);
495 		goto ran;
496 	}
497 
498 	return 0;
499 ran:
500 	return 1;
501 }
502 
503 /* Set main as weak to allow overriding it for building unit test binary */
504 #pragma weak main
505 
506 int main(int argc, char *argv[])
507 {
508 	int retval;
509 
510 	/* is it an alias? */
511 	retval = run_tool_command(argc, argv, 0);
512 	if (retval)
513 		exit(0);
514 
515 	if (argc < 2)
516 		goto usage;
517 
518 	if (strcmp(argv[1], "-h") == 0)
519 		rtla_usage(129);
520 	else if (strcmp(argv[1], "--help") == 0)
521 		rtla_usage(129);
522 
523 	retval = run_tool_command(argc, argv, 1);
524 	if (retval)
525 		exit(0);
526 
527 usage:
528 	rtla_usage(129);
529 }
530