projects/linux·blob master · refs

529 lines · 13.0 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <[email protected]>
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
18static const char * const osnoise_top_usage[] = {
19 "rtla osnoise [top] [<options>] [-h|--help]",
20 NULL,
21};
22
23static const char * const osnoise_hist_usage[] = {
24 "rtla osnoise hist [<options>] [-h|--help]",
25 NULL,
26};
27
28static const char * const timerlat_top_usage[] = {
29 "rtla timerlat [top] [<options>] [-h|--help]",
30 NULL,
31};
32
33static const char * const timerlat_hist_usage[] = {
34 "rtla timerlat hist [<options>] [-h|--help]",
35 NULL,
36};
37
38static const char * const hwnoise_usage[] = {
39 "rtla hwnoise [<options>] [-h|--help]",
40 NULL,
41};
42
43static const int common_parse_options_flags = PARSE_OPT_OPTARG_ALLOW_NEXT;
44
45bool in_unit_test;
46
47/*
48 * osnoise_top_parse_args - allocs, parse and fill the cmd line parameters
49 */
50struct 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 */
136struct 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
218struct 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
329struct 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 */
485int 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;
499ran:
500 return 1;
501}
502
503/* Set main as weak to allow overriding it for building unit test binary */
504#pragma weak main
505
506int 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
527usage:
528 rtla_usage(129);
529}