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