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