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(¶ms->common.threshold_actions); 115*5d9af63eSTomas Glozar actions_init(¶ms->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(¶ms->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 ¶ms->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(¶ms->common.threshold_actions); 193*5d9af63eSTomas Glozar actions_init(¶ms->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(¶ms->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 ¶ms->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(¶ms->common.threshold_actions); 280*5d9af63eSTomas Glozar actions_init(¶ms->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(¶ms->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 ¶ms->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(¶ms->common.threshold_actions); 402*5d9af63eSTomas Glozar actions_init(¶ms->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(¶ms->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 ¶ms->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