xref: /linux/tools/tracing/rtla/src/cli.c (revision 5daa3c4fa49474fc8935722b3bbc7181aefe7169)
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 	/* display data in microseconds */
196 	params->common.output_divisor = 1000;
197 	params->common.hist.bucket_size = 1;
198 	params->common.hist.entries = 256;
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 	/* disabled by default */
284 	params->dma_latency = -1;
285 	params->deepest_idle_state = -2;
286 
287 	/* display data in microseconds */
288 	params->common.output_divisor = 1000;
289 
290 	/* default to BPF mode */
291 	params->mode = TRACING_MODE_BPF;
292 
293 	/* default to truncate stack format */
294 	params->stack_format = STACK_FORMAT_TRUNCATE;
295 
296 	argc = parse_options(argc, (const char **)argv,
297 			     timerlat_top_options, timerlat_top_usage,
298 			     common_parse_options_flags);
299 	if (argc < 0)
300 		return NULL;
301 
302 	if (cb_data.trace_output)
303 		actions_add_trace_output(&params->common.threshold_actions, cb_data.trace_output);
304 
305 	if (geteuid() && !in_unit_test)
306 		fatal("rtla needs root permission");
307 
308 	/*
309 	 * Auto analysis only happens if stop tracing, thus:
310 	 */
311 	if (!params->common.stop_us && !params->common.stop_total_us)
312 		params->no_aa = 1;
313 
314 	if (params->no_aa && params->common.aa_only)
315 		fatal("--no-aa and --aa-only are mutually exclusive!");
316 
317 	if (params->common.kernel_workload && params->common.user_workload)
318 		fatal("--kernel-threads and --user-threads are mutually exclusive!");
319 
320 	/*
321 	 * If auto-analysis or trace output is enabled, switch from BPF mode to
322 	 * mixed mode
323 	 */
324 	if (params->mode == TRACING_MODE_BPF &&
325 		(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
326 		params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
327 		!params->no_aa))
328 		params->mode = TRACING_MODE_MIXED;
329 
330 	return &params->common;
331 }
332 
333 struct common_params *timerlat_hist_parse_args(int argc, char **argv)
334 {
335 	struct timerlat_params *params;
336 	struct timerlat_cb_data cb_data;
337 
338 	params = calloc_fatal(1, sizeof(*params));
339 
340 	cb_data.params = params;
341 	cb_data.trace_output = NULL;
342 
343 	const struct option timerlat_hist_options[] = {
344 	OPT_GROUP("Tracing Options:"),
345 		TIMERLAT_OPT_PERIOD,
346 		RTLA_OPT_STOP('i', "irq", "irq latency"),
347 		RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"),
348 		TIMERLAT_OPT_STACK,
349 		RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb),
350 
351 	OPT_GROUP("Event Configuration:"),
352 		RTLA_OPT_EVENT,
353 		RTLA_OPT_FILTER,
354 		RTLA_OPT_TRIGGER,
355 
356 	OPT_GROUP("CPU Configuration:"),
357 		RTLA_OPT_CPUS,
358 		RTLA_OPT_HOUSEKEEPING,
359 
360 	OPT_GROUP("Thread Configuration:"),
361 		RTLA_OPT_PRIORITY,
362 		RTLA_OPT_CGROUP,
363 		RTLA_OPT_USER_THREADS,
364 		RTLA_OPT_KERNEL_THREADS,
365 		RTLA_OPT_USER_LOAD,
366 		TIMERLAT_OPT_ALIGNED,
367 
368 	OPT_GROUP("Histogram Options:"),
369 		HIST_OPT_BUCKET_SIZE,
370 		HIST_OPT_ENTRIES,
371 		HIST_OPT_NO_IRQ,
372 		HIST_OPT_NO_THREAD,
373 		HIST_OPT_NO_HEADER,
374 		HIST_OPT_NO_SUMMARY,
375 		HIST_OPT_NO_INDEX,
376 		HIST_OPT_WITH_ZEROS,
377 
378 	OPT_GROUP("Output:"),
379 		TIMERLAT_OPT_NANO,
380 
381 	OPT_GROUP("System Tuning:"),
382 		TIMERLAT_OPT_DMA_LATENCY,
383 		TIMERLAT_OPT_DEEPEST_IDLE_STATE,
384 		RTLA_OPT_TRACE_BUFFER_SIZE,
385 		RTLA_OPT_WARM_UP,
386 
387 	OPT_GROUP("Auto Analysis and Actions:"),
388 		RTLA_OPT_AUTO(opt_timerlat_auto_cb),
389 		TIMERLAT_OPT_NO_AA,
390 		TIMERLAT_OPT_DUMPS_TASKS,
391 		RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb),
392 		RTLA_OPT_ON_END(opt_timerlat_on_end_cb),
393 		TIMERLAT_OPT_BPF_ACTION,
394 		TIMERLAT_OPT_STACK_FORMAT,
395 
396 	OPT_GROUP("General:"),
397 		RTLA_OPT_DURATION,
398 		RTLA_OPT_DEBUG,
399 
400 	OPT_END(),
401 	};
402 
403 	actions_init(&params->common.threshold_actions);
404 	actions_init(&params->common.end_actions);
405 
406 	/* disabled by default */
407 	params->dma_latency = -1;
408 
409 	/* disabled by default */
410 	params->deepest_idle_state = -2;
411 
412 	/* display data in microseconds */
413 	params->common.output_divisor = 1000;
414 	params->common.hist.bucket_size = 1;
415 	params->common.hist.entries = 256;
416 
417 	/* default to BPF mode */
418 	params->mode = TRACING_MODE_BPF;
419 
420 	/* default to truncate stack format */
421 	params->stack_format = STACK_FORMAT_TRUNCATE;
422 
423 	argc = parse_options(argc, (const char **)argv,
424 			     timerlat_hist_options, timerlat_hist_usage,
425 			     common_parse_options_flags);
426 	if (argc < 0)
427 		return NULL;
428 
429 	if (cb_data.trace_output)
430 		actions_add_trace_output(&params->common.threshold_actions, cb_data.trace_output);
431 
432 	if (geteuid() && !in_unit_test)
433 		fatal("rtla needs root permission");
434 
435 	if (params->common.hist.no_irq && params->common.hist.no_thread)
436 		fatal("no-irq and no-thread set, there is nothing to do here");
437 
438 	if (params->common.hist.no_index && !params->common.hist.with_zeros)
439 		fatal("no-index set with with-zeros is not set - it does not make sense");
440 
441 	/*
442 	 * Auto analysis only happens if stop tracing, thus:
443 	 */
444 	if (!params->common.stop_us && !params->common.stop_total_us)
445 		params->no_aa = 1;
446 
447 	if (params->common.kernel_workload && params->common.user_workload)
448 		fatal("--kernel-threads and --user-threads are mutually exclusive!");
449 
450 	/*
451 	 * If auto-analysis or trace output is enabled, switch from BPF mode to
452 	 * mixed mode
453 	 */
454 	if (params->mode == TRACING_MODE_BPF &&
455 		(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
456 		params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
457 		!params->no_aa))
458 		params->mode = TRACING_MODE_MIXED;
459 
460 	return &params->common;
461 }
462 
463 /*
464  * rtla_usage - print rtla usage
465  */
466 __noreturn static void rtla_usage(int err)
467 {
468 	int i;
469 
470 	static const char * const msg[] = {
471 		"",
472 		"rtla version " VERSION,
473 		"",
474 		"  usage: rtla COMMAND ...",
475 		"",
476 		"  commands:",
477 		"     osnoise  - gives information about the operating system noise (osnoise)",
478 		"     hwnoise  - gives information about hardware-related noise",
479 		"     timerlat - measures the timer irq and thread latency",
480 		"",
481 		NULL,
482 	};
483 
484 	for (i = 0; msg[i]; i++)
485 		fprintf(stderr, "%s\n", msg[i]);
486 	exit(err);
487 }
488 
489 /*
490  * run_tool_command - try to run a rtla tool command
491  *
492  * It returns 0 if it fails. The tool's main will generally not
493  * return as they should call exit().
494  */
495 int run_tool_command(int argc, char **argv, int start_position)
496 {
497 	if (strcmp(argv[start_position], "osnoise") == 0) {
498 		osnoise_main(argc-start_position, &argv[start_position]);
499 		goto ran;
500 	} else if (strcmp(argv[start_position], "hwnoise") == 0) {
501 		hwnoise_main(argc-start_position, &argv[start_position]);
502 		goto ran;
503 	} else if (strcmp(argv[start_position], "timerlat") == 0) {
504 		timerlat_main(argc-start_position, &argv[start_position]);
505 		goto ran;
506 	}
507 
508 	return 0;
509 ran:
510 	return 1;
511 }
512 
513 /* Set main as weak to allow overriding it for building unit test binary */
514 #pragma weak main
515 
516 int main(int argc, char *argv[])
517 {
518 	int retval;
519 
520 	/* is it an alias? */
521 	retval = run_tool_command(argc, argv, 0);
522 	if (retval)
523 		exit(0);
524 
525 	if (argc < 2)
526 		goto usage;
527 
528 	if (strcmp(argv[1], "-h") == 0)
529 		rtla_usage(129);
530 	else if (strcmp(argv[1], "--help") == 0)
531 		rtla_usage(129);
532 
533 	retval = run_tool_command(argc, argv, 1);
534 	if (retval)
535 		exit(0);
536 
537 usage:
538 	rtla_usage(129);
539 }
540