Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'trace-tools-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing tools updates from Steven Rostedt

- This is mostly just consolidating code between osnoise/timerlat and
top/hist for easier maintenance and less future divergence

* tag 'trace-tools-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
tools/rtla: Add remaining support for osnoise actions
tools/rtla: Add test engine support for unexpected output
tools/rtla: Fix -A option name in test comment
tools/rtla: Consolidate code between osnoise/timerlat and hist/top
tools/rtla: Create common_apply_config()
tools/rtla: Move top/hist params into common struct
tools/rtla: Consolidate common parameters into shared structure

+1404 -1720
+61
Documentation/tools/rtla/common_options.rst
··· 53 53 **--trace-buffer-size** *kB* 54 54 Set the per-cpu trace buffer size in kB for the tracing output. 55 55 56 + **--on-threshold** *action* 57 + 58 + Defines an action to be executed when tracing is stopped on a latency threshold 59 + specified by |threshold|. 60 + 61 + Multiple --on-threshold actions may be specified, and they will be executed in 62 + the order they are provided. If any action fails, subsequent actions in the list 63 + will not be executed. 64 + 65 + Supported actions are: 66 + 67 + - *trace[,file=<filename>]* 68 + 69 + Saves trace output, optionally taking a filename. Alternative to -t/--trace. 70 + Note that nlike -t/--trace, specifying this multiple times will result in 71 + the trace being saved multiple times. 72 + 73 + - *signal,num=<sig>,pid=<pid>* 74 + 75 + Sends signal to process. "parent" might be specified in place of pid to target 76 + the parent process of rtla. 77 + 78 + - *shell,command=<command>* 79 + 80 + Execute shell command. 81 + 82 + - *continue* 83 + 84 + Continue tracing after actions are executed instead of stopping. 85 + 86 + Example: 87 + 88 + $ rtla |tool| |thresharg| 20 --on-threshold trace 89 + --on-threshold shell,command="grep ipi_send |tracer|\_trace.txt" 90 + --on-threshold signal,num=2,pid=parent 91 + 92 + This will save a trace with the default filename "|tracer|\_trace.txt", print its 93 + lines that contain the text "ipi_send" on standard output, and send signal 2 94 + (SIGINT) to the parent process. 95 + 96 + Performance Considerations: 97 + 98 + |actionsperf| 99 + 100 + **--on-end** *action* 101 + 102 + Defines an action to be executed at the end of tracing. 103 + 104 + Multiple --on-end actions can be specified, and they will be executed in the order 105 + they are provided. If any action fails, subsequent actions in the list will not be 106 + executed. 107 + 108 + See the documentation for **--on-threshold** for the list of supported actions, with 109 + the exception that *continue* has no effect. 110 + 111 + Example: 112 + 113 + $ rtla |tool| -d 5s --on-end trace 114 + 115 + This runs rtla with the default options, and saves trace output at the end. 116 + 56 117 **-h**, **--help** 57 118 58 119 Print help menu.
+8
Documentation/tools/rtla/common_osnoise_options.rst
··· 1 + .. |threshold| replace:: **-a/--auto**, **-s/--stop**, or **-S/--stop-total** 2 + .. |thresharg| replace:: -s 3 + .. |tracer| replace:: osnoise 4 + 5 + .. |actionsperf| replace:: 6 + Due to implementational limitations, actions might be delayed 7 + up to one second after tracing is stopped. 8 + 1 9 **-a**, **--auto** *us* 2 10 3 11 Set the automatic trace mode. This mode sets some commonly used options
+10 -64
Documentation/tools/rtla/common_timerlat_options.rst
··· 1 + .. |threshold| replace:: **-a/--auto**, **-i/--irq**, or **-T/--thread** 2 + .. |thresharg| replace:: -T 3 + .. |tracer| replace:: timerlat 4 + 5 + .. |actionsperf| replace:: 6 + For time-sensitive actions, it is recommended to run **rtla timerlat** with BPF 7 + support and RT priority. Note that due to implementational limitations, actions 8 + might be delayed up to one second after tracing is stopped if BPF mode is not 9 + available or disabled. 10 + 1 11 **-a**, **--auto** *us* 2 12 3 13 Set the automatic trace mode. This mode sets some commonly used options ··· 65 55 Set timerlat to run without workload, waiting for the user to dispatch a per-cpu 66 56 task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd. 67 57 See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code. 68 - 69 - **--on-threshold** *action* 70 - 71 - Defines an action to be executed when tracing is stopped on a latency threshold 72 - specified by **-i/--irq** or **-T/--thread**. 73 - 74 - Multiple --on-threshold actions may be specified, and they will be executed in 75 - the order they are provided. If any action fails, subsequent actions in the list 76 - will not be executed. 77 - 78 - Supported actions are: 79 - 80 - - *trace[,file=<filename>]* 81 - 82 - Saves trace output, optionally taking a filename. Alternative to -t/--trace. 83 - Note that nlike -t/--trace, specifying this multiple times will result in 84 - the trace being saved multiple times. 85 - 86 - - *signal,num=<sig>,pid=<pid>* 87 - 88 - Sends signal to process. "parent" might be specified in place of pid to target 89 - the parent process of rtla. 90 - 91 - - *shell,command=<command>* 92 - 93 - Execute shell command. 94 - 95 - - *continue* 96 - 97 - Continue tracing after actions are executed instead of stopping. 98 - 99 - Example: 100 - 101 - $ rtla timerlat -T 20 --on-threshold trace 102 - --on-threshold shell,command="grep ipi_send timerlat_trace.txt" 103 - --on-threshold signal,num=2,pid=parent 104 - 105 - This will save a trace with the default filename "timerlat_trace.txt", print its 106 - lines that contain the text "ipi_send" on standard output, and send signal 2 107 - (SIGINT) to the parent process. 108 - 109 - Performance Considerations: 110 - 111 - For time-sensitive actions, it is recommended to run **rtla timerlat** with BPF 112 - support and RT priority. Note that due to implementational limitations, actions 113 - might be delayed up to one second after tracing is stopped if BPF mode is not 114 - available or disabled. 115 - 116 - **--on-end** *action* 117 - 118 - Defines an action to be executed at the end of **rtla timerlat** tracing. 119 - 120 - Multiple --on-end actions can be specified, and they will be executed in the order 121 - they are provided. If any action fails, subsequent actions in the list will not be 122 - executed. 123 - 124 - See the documentation for **--on-threshold** for the list of supported actions, with 125 - the exception that *continue* has no effect. 126 - 127 - Example: 128 - 129 - $ rtla timerlat -d 5s --on-end trace 130 - 131 - This runs rtla timerlat with default options and save trace output at the end.
+2
Documentation/tools/rtla/rtla-hwnoise.rst
··· 1 1 .. SPDX-License-Identifier: GPL-2.0 2 2 3 + .. |tool| replace:: hwnoise 4 + 3 5 ============ 4 6 rtla-hwnoise 5 7 ============
+2
Documentation/tools/rtla/rtla-osnoise-hist.rst
··· 1 + .. |tool| replace:: osnoise hist 2 + 1 3 =================== 2 4 rtla-osnoise-hist 3 5 ===================
+2
Documentation/tools/rtla/rtla-osnoise-top.rst
··· 1 + .. |tool| replace:: osnoise top 2 + 1 3 =================== 2 4 rtla-osnoise-top 3 5 ===================
+2
Documentation/tools/rtla/rtla-timerlat-hist.rst
··· 1 + .. |tool| replace:: timerlat hist 2 + 1 3 ===================== 2 4 rtla-timerlat-hist 3 5 =====================
+2
Documentation/tools/rtla/rtla-timerlat-top.rst
··· 1 + .. |tool| replace:: timerlat top 2 + 1 3 ==================== 2 4 rtla-timerlat-top 3 5 ====================
+1
tools/tracing/rtla/src/Build
··· 1 1 rtla-y += trace.o 2 2 rtla-y += utils.o 3 3 rtla-y += actions.o 4 + rtla-y += common.o 4 5 rtla-y += osnoise.o 5 6 rtla-y += osnoise_top.o 6 7 rtla-y += osnoise_hist.o
+4 -4
tools/tracing/rtla/src/actions.c
··· 127 127 * actions_parse - add an action based on text specification 128 128 */ 129 129 int 130 - actions_parse(struct actions *self, const char *trigger) 130 + actions_parse(struct actions *self, const char *trigger, const char *tracefn) 131 131 { 132 132 enum action_type type = ACTION_NONE; 133 - char *token; 133 + const char *token; 134 134 char trigger_c[strlen(trigger) + 1]; 135 135 136 136 /* For ACTION_SIGNAL */ 137 137 int signal = 0, pid = 0; 138 138 139 139 /* For ACTION_TRACE_OUTPUT */ 140 - char *trace_output; 140 + const char *trace_output; 141 141 142 142 strcpy(trigger_c, trigger); 143 143 token = strtok(trigger_c, ","); ··· 160 160 case ACTION_TRACE_OUTPUT: 161 161 /* Takes no argument */ 162 162 if (token == NULL) 163 - trace_output = "timerlat_trace.txt"; 163 + trace_output = tracefn; 164 164 else { 165 165 if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) { 166 166 trace_output = token + 5;
+1 -1
tools/tracing/rtla/src/actions.h
··· 48 48 int actions_add_signal(struct actions *self, int signal, int pid); 49 49 int actions_add_shell(struct actions *self, const char *command); 50 50 int actions_add_continue(struct actions *self); 51 - int actions_parse(struct actions *self, const char *trigger); 51 + int actions_parse(struct actions *self, const char *trigger, const char *tracefn); 52 52 int actions_perform(struct actions *self);
+344
tools/tracing/rtla/src/common.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #define _GNU_SOURCE 3 + 4 + #include <pthread.h> 5 + #include <signal.h> 6 + #include <stdlib.h> 7 + #include <unistd.h> 8 + #include "common.h" 9 + 10 + struct trace_instance *trace_inst; 11 + int stop_tracing; 12 + 13 + static void stop_trace(int sig) 14 + { 15 + if (stop_tracing) { 16 + /* 17 + * Stop requested twice in a row; abort event processing and 18 + * exit immediately 19 + */ 20 + tracefs_iterate_stop(trace_inst->inst); 21 + return; 22 + } 23 + stop_tracing = 1; 24 + if (trace_inst) 25 + trace_instance_stop(trace_inst); 26 + } 27 + 28 + /* 29 + * set_signals - handles the signal to stop the tool 30 + */ 31 + static void set_signals(struct common_params *params) 32 + { 33 + signal(SIGINT, stop_trace); 34 + if (params->duration) { 35 + signal(SIGALRM, stop_trace); 36 + alarm(params->duration); 37 + } 38 + } 39 + 40 + /* 41 + * common_apply_config - apply common configs to the initialized tool 42 + */ 43 + int 44 + common_apply_config(struct osnoise_tool *tool, struct common_params *params) 45 + { 46 + int retval, i; 47 + 48 + if (!params->sleep_time) 49 + params->sleep_time = 1; 50 + 51 + retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); 52 + if (retval) { 53 + err_msg("Failed to apply CPUs config\n"); 54 + goto out_err; 55 + } 56 + 57 + if (!params->cpus) { 58 + for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) 59 + CPU_SET(i, &params->monitored_cpus); 60 + } 61 + 62 + if (params->hk_cpus) { 63 + retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), 64 + &params->hk_cpu_set); 65 + if (retval == -1) { 66 + err_msg("Failed to set rtla to the house keeping CPUs\n"); 67 + goto out_err; 68 + } 69 + } else if (params->cpus) { 70 + /* 71 + * Even if the user do not set a house-keeping CPU, try to 72 + * move rtla to a CPU set different to the one where the user 73 + * set the workload to run. 74 + * 75 + * No need to check results as this is an automatic attempt. 76 + */ 77 + auto_house_keeping(&params->monitored_cpus); 78 + } 79 + 80 + /* 81 + * Set workload according to type of thread if the kernel supports it. 82 + * On kernels without support, user threads will have already failed 83 + * on missing fd, and kernel threads do not need it. 84 + */ 85 + retval = osnoise_set_workload(tool->context, params->kernel_workload); 86 + if (retval < -1) { 87 + err_msg("Failed to set OSNOISE_WORKLOAD option\n"); 88 + goto out_err; 89 + } 90 + 91 + return 0; 92 + 93 + out_err: 94 + return -1; 95 + } 96 + 97 + 98 + int run_tool(struct tool_ops *ops, int argc, char *argv[]) 99 + { 100 + struct common_params *params; 101 + enum result return_value = ERROR; 102 + struct osnoise_tool *tool; 103 + bool stopped; 104 + int retval; 105 + 106 + params = ops->parse_args(argc, argv); 107 + if (!params) 108 + exit(1); 109 + 110 + tool = ops->init_tool(params); 111 + if (!tool) { 112 + err_msg("Could not init osnoise tool\n"); 113 + goto out_exit; 114 + } 115 + tool->ops = ops; 116 + tool->params = params; 117 + 118 + /* 119 + * Save trace instance into global variable so that SIGINT can stop 120 + * the timerlat tracer. 121 + * Otherwise, rtla could loop indefinitely when overloaded. 122 + */ 123 + trace_inst = &tool->trace; 124 + 125 + retval = ops->apply_config(tool); 126 + if (retval) { 127 + err_msg("Could not apply config\n"); 128 + goto out_free; 129 + } 130 + 131 + retval = enable_tracer_by_name(trace_inst->inst, ops->tracer); 132 + if (retval) { 133 + err_msg("Failed to enable %s tracer\n", ops->tracer); 134 + goto out_free; 135 + } 136 + 137 + if (params->set_sched) { 138 + retval = set_comm_sched_attr(ops->comm_prefix, &params->sched_param); 139 + if (retval) { 140 + err_msg("Failed to set sched parameters\n"); 141 + goto out_free; 142 + } 143 + } 144 + 145 + if (params->cgroup && !params->user_data) { 146 + retval = set_comm_cgroup(ops->comm_prefix, params->cgroup_name); 147 + if (!retval) { 148 + err_msg("Failed to move threads to cgroup\n"); 149 + goto out_free; 150 + } 151 + } 152 + 153 + 154 + if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || 155 + params->end_actions.present[ACTION_TRACE_OUTPUT]) { 156 + tool->record = osnoise_init_trace_tool(ops->tracer); 157 + if (!tool->record) { 158 + err_msg("Failed to enable the trace instance\n"); 159 + goto out_free; 160 + } 161 + params->threshold_actions.trace_output_inst = tool->record->trace.inst; 162 + params->end_actions.trace_output_inst = tool->record->trace.inst; 163 + 164 + if (params->events) { 165 + retval = trace_events_enable(&tool->record->trace, params->events); 166 + if (retval) 167 + goto out_trace; 168 + } 169 + 170 + if (params->buffer_size > 0) { 171 + retval = trace_set_buffer_size(&tool->record->trace, params->buffer_size); 172 + if (retval) 173 + goto out_trace; 174 + } 175 + } 176 + 177 + if (params->user_workload) { 178 + pthread_t user_thread; 179 + 180 + /* rtla asked to stop */ 181 + params->user.should_run = 1; 182 + /* all threads left */ 183 + params->user.stopped_running = 0; 184 + 185 + params->user.set = &params->monitored_cpus; 186 + if (params->set_sched) 187 + params->user.sched_param = &params->sched_param; 188 + else 189 + params->user.sched_param = NULL; 190 + 191 + params->user.cgroup_name = params->cgroup_name; 192 + 193 + retval = pthread_create(&user_thread, NULL, timerlat_u_dispatcher, &params->user); 194 + if (retval) 195 + err_msg("Error creating timerlat user-space threads\n"); 196 + } 197 + 198 + retval = ops->enable(tool); 199 + if (retval) 200 + goto out_trace; 201 + 202 + tool->start_time = time(NULL); 203 + set_signals(params); 204 + 205 + retval = ops->main(tool); 206 + if (retval) 207 + goto out_trace; 208 + 209 + if (params->user_workload && !params->user.stopped_running) { 210 + params->user.should_run = 0; 211 + sleep(1); 212 + } 213 + 214 + ops->print_stats(tool); 215 + 216 + actions_perform(&params->end_actions); 217 + 218 + return_value = PASSED; 219 + 220 + stopped = osnoise_trace_is_off(tool, tool->record) && !stop_tracing; 221 + if (stopped) { 222 + printf("%s hit stop tracing\n", ops->tracer); 223 + return_value = FAILED; 224 + } 225 + 226 + if (ops->analyze) 227 + ops->analyze(tool, stopped); 228 + 229 + out_trace: 230 + trace_events_destroy(&tool->record->trace, params->events); 231 + params->events = NULL; 232 + out_free: 233 + ops->free(tool); 234 + osnoise_destroy_tool(tool->record); 235 + osnoise_destroy_tool(tool); 236 + actions_destroy(&params->threshold_actions); 237 + actions_destroy(&params->end_actions); 238 + free(params); 239 + out_exit: 240 + exit(return_value); 241 + } 242 + 243 + int top_main_loop(struct osnoise_tool *tool) 244 + { 245 + struct common_params *params = tool->params; 246 + struct trace_instance *trace = &tool->trace; 247 + struct osnoise_tool *record = tool->record; 248 + int retval; 249 + 250 + while (!stop_tracing) { 251 + sleep(params->sleep_time); 252 + 253 + if (params->aa_only && !osnoise_trace_is_off(tool, record)) 254 + continue; 255 + 256 + retval = tracefs_iterate_raw_events(trace->tep, 257 + trace->inst, 258 + NULL, 259 + 0, 260 + collect_registered_events, 261 + trace); 262 + if (retval < 0) { 263 + err_msg("Error iterating on events\n"); 264 + return retval; 265 + } 266 + 267 + if (!params->quiet) 268 + tool->ops->print_stats(tool); 269 + 270 + if (osnoise_trace_is_off(tool, record)) { 271 + actions_perform(&params->threshold_actions); 272 + 273 + if (!params->threshold_actions.continue_flag) 274 + /* continue flag not set, break */ 275 + return 0; 276 + 277 + /* continue action reached, re-enable tracing */ 278 + if (record) 279 + trace_instance_start(&record->trace); 280 + if (tool->aa) 281 + trace_instance_start(&tool->aa->trace); 282 + trace_instance_start(trace); 283 + } 284 + 285 + /* is there still any user-threads ? */ 286 + if (params->user_workload) { 287 + if (params->user.stopped_running) { 288 + debug_msg("timerlat user space threads stopped!\n"); 289 + break; 290 + } 291 + } 292 + } 293 + 294 + return 0; 295 + } 296 + 297 + int hist_main_loop(struct osnoise_tool *tool) 298 + { 299 + struct common_params *params = tool->params; 300 + struct trace_instance *trace = &tool->trace; 301 + int retval = 0; 302 + 303 + while (!stop_tracing) { 304 + sleep(params->sleep_time); 305 + 306 + retval = tracefs_iterate_raw_events(trace->tep, 307 + trace->inst, 308 + NULL, 309 + 0, 310 + collect_registered_events, 311 + trace); 312 + if (retval < 0) { 313 + err_msg("Error iterating on events\n"); 314 + break; 315 + } 316 + 317 + if (osnoise_trace_is_off(tool, tool->record)) { 318 + actions_perform(&params->threshold_actions); 319 + 320 + if (!params->threshold_actions.continue_flag) { 321 + /* continue flag not set, break */ 322 + break; 323 + 324 + /* continue action reached, re-enable tracing */ 325 + if (tool->record) 326 + trace_instance_start(&tool->record->trace); 327 + if (tool->aa) 328 + trace_instance_start(&tool->aa->trace); 329 + trace_instance_start(&tool->trace); 330 + } 331 + break; 332 + } 333 + 334 + /* is there still any user-threads ? */ 335 + if (params->user_workload) { 336 + if (params->user.stopped_running) { 337 + debug_msg("user-space threads stopped!\n"); 338 + break; 339 + } 340 + } 341 + } 342 + 343 + return retval; 344 + }
+154
tools/tracing/rtla/src/common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #pragma once 3 + 4 + #include "actions.h" 5 + #include "timerlat_u.h" 6 + #include "trace.h" 7 + #include "utils.h" 8 + 9 + /* 10 + * osnoise_context - read, store, write, restore osnoise configs. 11 + */ 12 + struct osnoise_context { 13 + int flags; 14 + int ref; 15 + 16 + char *curr_cpus; 17 + char *orig_cpus; 18 + 19 + /* 0 as init value */ 20 + unsigned long long orig_runtime_us; 21 + unsigned long long runtime_us; 22 + 23 + /* 0 as init value */ 24 + unsigned long long orig_period_us; 25 + unsigned long long period_us; 26 + 27 + /* 0 as init value */ 28 + long long orig_timerlat_period_us; 29 + long long timerlat_period_us; 30 + 31 + /* 0 as init value */ 32 + long long orig_tracing_thresh; 33 + long long tracing_thresh; 34 + 35 + /* -1 as init value because 0 is disabled */ 36 + long long orig_stop_us; 37 + long long stop_us; 38 + 39 + /* -1 as init value because 0 is disabled */ 40 + long long orig_stop_total_us; 41 + long long stop_total_us; 42 + 43 + /* -1 as init value because 0 is disabled */ 44 + long long orig_print_stack; 45 + long long print_stack; 46 + 47 + /* -1 as init value because 0 is off */ 48 + int orig_opt_irq_disable; 49 + int opt_irq_disable; 50 + 51 + /* -1 as init value because 0 is off */ 52 + int orig_opt_workload; 53 + int opt_workload; 54 + }; 55 + 56 + extern struct trace_instance *trace_inst; 57 + extern int stop_tracing; 58 + 59 + struct hist_params { 60 + char no_irq; 61 + char no_thread; 62 + char no_header; 63 + char no_summary; 64 + char no_index; 65 + char with_zeros; 66 + int bucket_size; 67 + int entries; 68 + }; 69 + 70 + /* 71 + * common_params - Parameters shared between timerlat_params and osnoise_params 72 + */ 73 + struct common_params { 74 + /* trace configuration */ 75 + char *cpus; 76 + cpu_set_t monitored_cpus; 77 + struct trace_events *events; 78 + int buffer_size; 79 + 80 + /* Timing parameters */ 81 + int warmup; 82 + long long stop_us; 83 + long long stop_total_us; 84 + int sleep_time; 85 + int duration; 86 + 87 + /* Scheduling parameters */ 88 + int set_sched; 89 + struct sched_attr sched_param; 90 + int cgroup; 91 + char *cgroup_name; 92 + int hk_cpus; 93 + cpu_set_t hk_cpu_set; 94 + 95 + /* Other parameters */ 96 + struct hist_params hist; 97 + int output_divisor; 98 + int pretty_output; 99 + int quiet; 100 + int user_workload; 101 + int kernel_workload; 102 + int user_data; 103 + int aa_only; 104 + 105 + struct actions threshold_actions; 106 + struct actions end_actions; 107 + struct timerlat_u_params user; 108 + }; 109 + 110 + struct tool_ops; 111 + 112 + /* 113 + * osnoise_tool - osnoise based tool definition. 114 + * 115 + * Only the "trace" and "context" fields are used for 116 + * the additional trace instances (record and aa). 117 + */ 118 + struct osnoise_tool { 119 + struct tool_ops *ops; 120 + struct trace_instance trace; 121 + struct osnoise_context *context; 122 + void *data; 123 + struct common_params *params; 124 + time_t start_time; 125 + struct osnoise_tool *record; 126 + struct osnoise_tool *aa; 127 + }; 128 + 129 + struct tool_ops { 130 + const char *tracer; 131 + const char *comm_prefix; 132 + struct common_params *(*parse_args)(int argc, char *argv[]); 133 + struct osnoise_tool *(*init_tool)(struct common_params *params); 134 + int (*apply_config)(struct osnoise_tool *tool); 135 + int (*enable)(struct osnoise_tool *tool); 136 + int (*main)(struct osnoise_tool *tool); 137 + void (*print_stats)(struct osnoise_tool *tool); 138 + void (*analyze)(struct osnoise_tool *tool, bool stopped); 139 + void (*free)(struct osnoise_tool *tool); 140 + }; 141 + 142 + int osnoise_set_cpus(struct osnoise_context *context, char *cpus); 143 + void osnoise_restore_cpus(struct osnoise_context *context); 144 + 145 + int osnoise_set_workload(struct osnoise_context *context, bool onoff); 146 + 147 + void osnoise_destroy_tool(struct osnoise_tool *top); 148 + struct osnoise_tool *osnoise_init_tool(char *tool_name); 149 + struct osnoise_tool *osnoise_init_trace_tool(const char *tracer); 150 + bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record); 151 + 152 + int common_apply_config(struct osnoise_tool *tool, struct common_params *params); 153 + int top_main_loop(struct osnoise_tool *tool); 154 + int hist_main_loop(struct osnoise_tool *tool);
+49 -58
tools/tracing/rtla/src/osnoise.c
··· 906 906 context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL; 907 907 } 908 908 909 - /* 910 - * enable_osnoise - enable osnoise tracer in the trace_instance 911 - */ 912 - int enable_osnoise(struct trace_instance *trace) 913 - { 914 - return enable_tracer_by_name(trace->inst, "osnoise"); 915 - } 916 - 917 - /* 918 - * enable_timerlat - enable timerlat tracer in the trace_instance 919 - */ 920 - int enable_timerlat(struct trace_instance *trace) 921 - { 922 - return enable_tracer_by_name(trace->inst, "timerlat"); 923 - } 924 - 925 909 enum { 926 910 FLAG_CONTEXT_NEWLY_CREATED = (1 << 0), 927 911 FLAG_CONTEXT_DELETED = (1 << 1), ··· 1040 1056 /* 1041 1057 * osnoise_init_trace_tool - init a tracer instance to trace osnoise events 1042 1058 */ 1043 - struct osnoise_tool *osnoise_init_trace_tool(char *tracer) 1059 + struct osnoise_tool *osnoise_init_trace_tool(const char *tracer) 1044 1060 { 1045 1061 struct osnoise_tool *trace; 1046 1062 int retval; ··· 1104 1120 } 1105 1121 1106 1122 /* 1107 - * osnoise_apply_config - apply common configs to the initialized tool 1123 + * osnoise_apply_config - apply osnoise configs to the initialized tool 1108 1124 */ 1109 1125 int 1110 1126 osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) 1111 1127 { 1112 1128 int retval; 1113 1129 1114 - if (!params->sleep_time) 1115 - params->sleep_time = 1; 1116 - 1117 - retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); 1118 - if (retval) { 1119 - err_msg("Failed to apply CPUs config\n"); 1120 - goto out_err; 1121 - } 1130 + params->common.kernel_workload = true; 1122 1131 1123 1132 if (params->runtime || params->period) { 1124 1133 retval = osnoise_set_runtime_period(tool->context, ··· 1128 1151 goto out_err; 1129 1152 } 1130 1153 1131 - retval = osnoise_set_stop_us(tool->context, params->stop_us); 1154 + retval = osnoise_set_stop_us(tool->context, params->common.stop_us); 1132 1155 if (retval) { 1133 1156 err_msg("Failed to set stop us\n"); 1134 1157 goto out_err; 1135 1158 } 1136 1159 1137 - retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); 1160 + retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us); 1138 1161 if (retval) { 1139 1162 err_msg("Failed to set stop total us\n"); 1140 1163 goto out_err; ··· 1146 1169 goto out_err; 1147 1170 } 1148 1171 1149 - if (params->hk_cpus) { 1150 - retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), 1151 - &params->hk_cpu_set); 1152 - if (retval == -1) { 1153 - err_msg("Failed to set rtla to the house keeping CPUs\n"); 1154 - goto out_err; 1155 - } 1156 - } else if (params->cpus) { 1157 - /* 1158 - * Even if the user do not set a house-keeping CPU, try to 1159 - * move rtla to a CPU set different to the one where the user 1160 - * set the workload to run. 1161 - * 1162 - * No need to check results as this is an automatic attempt. 1163 - */ 1164 - auto_house_keeping(&params->monitored_cpus); 1165 - } 1166 - 1167 - retval = osnoise_set_workload(tool->context, true); 1168 - if (retval < -1) { 1169 - err_msg("Failed to set OSNOISE_WORKLOAD option\n"); 1170 - goto out_err; 1171 - } 1172 - 1173 - return 0; 1172 + return common_apply_config(tool, &params->common); 1174 1173 1175 1174 out_err: 1176 1175 return -1; 1176 + } 1177 + 1178 + int osnoise_enable(struct osnoise_tool *tool) 1179 + { 1180 + struct osnoise_params *params = to_osnoise_params(tool->params); 1181 + int retval; 1182 + 1183 + /* 1184 + * Start the tracer here, after having set all instances. 1185 + * 1186 + * Let the trace instance start first for the case of hitting a stop 1187 + * tracing while enabling other instances. The trace instance is the 1188 + * one with most valuable information. 1189 + */ 1190 + if (tool->record) 1191 + trace_instance_start(&tool->record->trace); 1192 + trace_instance_start(&tool->trace); 1193 + 1194 + if (params->common.warmup > 0) { 1195 + debug_msg("Warming up for %d seconds\n", params->common.warmup); 1196 + sleep(params->common.warmup); 1197 + if (stop_tracing) 1198 + return -1; 1199 + 1200 + /* 1201 + * Clean up the buffer. The osnoise workload do not run 1202 + * with tracing off to avoid creating a performance penalty 1203 + * when not needed. 1204 + */ 1205 + retval = tracefs_instance_file_write(tool->trace.inst, "trace", ""); 1206 + if (retval < 0) { 1207 + debug_msg("Error cleaning up the buffer"); 1208 + return retval; 1209 + } 1210 + 1211 + } 1212 + 1213 + return 0; 1177 1214 } 1178 1215 1179 1216 static void osnoise_usage(int err) ··· 1223 1232 * default cmdline. 1224 1233 */ 1225 1234 if (argc == 1) { 1226 - osnoise_top_main(argc, argv); 1235 + run_tool(&osnoise_top_ops, argc, argv); 1227 1236 exit(0); 1228 1237 } 1229 1238 ··· 1231 1240 osnoise_usage(0); 1232 1241 } else if (strncmp(argv[1], "-", 1) == 0) { 1233 1242 /* the user skipped the tool, call the default one */ 1234 - osnoise_top_main(argc, argv); 1243 + run_tool(&osnoise_top_ops, argc, argv); 1235 1244 exit(0); 1236 1245 } else if (strcmp(argv[1], "top") == 0) { 1237 - osnoise_top_main(argc-1, &argv[1]); 1246 + run_tool(&osnoise_top_ops, argc-1, &argv[1]); 1238 1247 exit(0); 1239 1248 } else if (strcmp(argv[1], "hist") == 0) { 1240 - osnoise_hist_main(argc-1, &argv[1]); 1249 + run_tool(&osnoise_hist_ops, argc-1, &argv[1]); 1241 1250 exit(0); 1242 1251 } 1243 1252 ··· 1248 1257 1249 1258 int hwnoise_main(int argc, char *argv[]) 1250 1259 { 1251 - osnoise_top_main(argc, argv); 1260 + run_tool(&osnoise_top_ops, argc, argv); 1252 1261 exit(0); 1253 1262 }
+11 -103
tools/tracing/rtla/src/osnoise.h
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #pragma once 3 3 4 - #include "utils.h" 5 - #include "trace.h" 4 + #include "common.h" 6 5 7 6 enum osnoise_mode { 8 7 MODE_OSNOISE = 0, ··· 9 10 }; 10 11 11 12 struct osnoise_params { 12 - /* Common params */ 13 - char *cpus; 14 - cpu_set_t monitored_cpus; 15 - char *trace_output; 16 - char *cgroup_name; 13 + struct common_params common; 17 14 unsigned long long runtime; 18 15 unsigned long long period; 19 16 long long threshold; 20 - long long stop_us; 21 - long long stop_total_us; 22 - int sleep_time; 23 - int duration; 24 - int set_sched; 25 - int cgroup; 26 - int hk_cpus; 27 - cpu_set_t hk_cpu_set; 28 - struct sched_attr sched_param; 29 - struct trace_events *events; 30 - int warmup; 31 - int buffer_size; 32 - union { 33 - struct { 34 - /* top only */ 35 - int quiet; 36 - int pretty_output; 37 - enum osnoise_mode mode; 38 - }; 39 - struct { 40 - /* hist only */ 41 - int output_divisor; 42 - char no_header; 43 - char no_summary; 44 - char no_index; 45 - char with_zeros; 46 - int bucket_size; 47 - int entries; 48 - }; 49 - }; 17 + enum osnoise_mode mode; 50 18 }; 51 19 52 - /* 53 - * osnoise_context - read, store, write, restore osnoise configs. 54 - */ 55 - struct osnoise_context { 56 - int flags; 57 - int ref; 58 - 59 - char *curr_cpus; 60 - char *orig_cpus; 61 - 62 - /* 0 as init value */ 63 - unsigned long long orig_runtime_us; 64 - unsigned long long runtime_us; 65 - 66 - /* 0 as init value */ 67 - unsigned long long orig_period_us; 68 - unsigned long long period_us; 69 - 70 - /* 0 as init value */ 71 - long long orig_timerlat_period_us; 72 - long long timerlat_period_us; 73 - 74 - /* 0 as init value */ 75 - long long orig_tracing_thresh; 76 - long long tracing_thresh; 77 - 78 - /* -1 as init value because 0 is disabled */ 79 - long long orig_stop_us; 80 - long long stop_us; 81 - 82 - /* -1 as init value because 0 is disabled */ 83 - long long orig_stop_total_us; 84 - long long stop_total_us; 85 - 86 - /* -1 as init value because 0 is disabled */ 87 - long long orig_print_stack; 88 - long long print_stack; 89 - 90 - /* -1 as init value because 0 is off */ 91 - int orig_opt_irq_disable; 92 - int opt_irq_disable; 93 - 94 - /* -1 as init value because 0 is off */ 95 - int orig_opt_workload; 96 - int opt_workload; 97 - }; 20 + #define to_osnoise_params(ptr) container_of(ptr, struct osnoise_params, common) 98 21 99 22 /* 100 23 * *_INIT_VALs are also invalid values, they are used to ··· 28 107 struct osnoise_context *osnoise_context_alloc(void); 29 108 int osnoise_get_context(struct osnoise_context *context); 30 109 void osnoise_put_context(struct osnoise_context *context); 31 - 32 - int osnoise_set_cpus(struct osnoise_context *context, char *cpus); 33 - void osnoise_restore_cpus(struct osnoise_context *context); 34 110 35 111 int osnoise_set_runtime_period(struct osnoise_context *context, 36 112 unsigned long long runtime, ··· 55 137 long long print_stack); 56 138 57 139 int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff); 58 - int osnoise_set_workload(struct osnoise_context *context, bool onoff); 59 - 60 - /* 61 - * osnoise_tool - osnoise based tool definition. 62 - */ 63 - struct osnoise_tool { 64 - struct trace_instance trace; 65 - struct osnoise_context *context; 66 - void *data; 67 - void *params; 68 - time_t start_time; 69 - }; 70 - 71 - void osnoise_destroy_tool(struct osnoise_tool *top); 72 - struct osnoise_tool *osnoise_init_tool(char *tool_name); 73 - struct osnoise_tool *osnoise_init_trace_tool(char *tracer); 74 140 void osnoise_report_missed_events(struct osnoise_tool *tool); 75 - bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record); 76 141 int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params); 77 142 78 143 int osnoise_hist_main(int argc, char *argv[]); 79 144 int osnoise_top_main(int argc, char **argv); 145 + int osnoise_enable(struct osnoise_tool *tool); 80 146 int osnoise_main(int argc, char **argv); 81 147 int hwnoise_main(int argc, char **argv); 148 + 149 + extern struct tool_ops timerlat_top_ops, timerlat_hist_ops; 150 + extern struct tool_ops osnoise_top_ops, osnoise_hist_ops; 151 + 152 + int run_tool(struct tool_ops *ops, int argc, char *argv[]); 153 + int hist_main_loop(struct osnoise_tool *tool);
+129 -240
tools/tracing/rtla/src/osnoise_hist.c
··· 54 54 free(data); 55 55 } 56 56 57 + static void osnoise_free_hist_tool(struct osnoise_tool *tool) 58 + { 59 + osnoise_free_histogram(tool->data); 60 + } 61 + 57 62 /* 58 63 * osnoise_alloc_histogram - alloc runtime data 59 64 */ ··· 100 95 static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu, 101 96 unsigned long long duration, int count) 102 97 { 103 - struct osnoise_params *params = tool->params; 98 + struct osnoise_params *params = to_osnoise_params(tool->params); 104 99 struct osnoise_hist_data *data = tool->data; 105 100 unsigned long long total_duration; 106 101 int entries = data->entries; 107 102 int bucket; 108 103 int *hist; 109 104 110 - if (params->output_divisor) 111 - duration = duration / params->output_divisor; 105 + if (params->common.output_divisor) 106 + duration = duration / params->common.output_divisor; 112 107 113 108 bucket = duration / data->bucket_size; 114 109 ··· 142 137 */ 143 138 static int osnoise_init_trace_hist(struct osnoise_tool *tool) 144 139 { 145 - struct osnoise_params *params = tool->params; 140 + struct osnoise_params *params = to_osnoise_params(tool->params); 146 141 struct osnoise_hist_data *data = tool->data; 147 142 int bucket_size; 148 143 char buff[128]; ··· 151 146 /* 152 147 * Set the size of the bucket. 153 148 */ 154 - bucket_size = params->output_divisor * params->bucket_size; 149 + bucket_size = params->common.output_divisor * params->common.hist.bucket_size; 155 150 snprintf(buff, sizeof(buff), "duration.buckets=%d", bucket_size); 156 151 157 152 data->trace_hist = tracefs_hist_alloc(tool->trace.tep, "osnoise", "sample_threshold", ··· 227 222 */ 228 223 static void osnoise_hist_header(struct osnoise_tool *tool) 229 224 { 230 - struct osnoise_params *params = tool->params; 225 + struct osnoise_params *params = to_osnoise_params(tool->params); 231 226 struct osnoise_hist_data *data = tool->data; 232 227 struct trace_seq *s = tool->trace.seq; 233 228 char duration[26]; 234 229 int cpu; 235 230 236 - if (params->no_header) 231 + if (params->common.hist.no_header) 237 232 return; 238 233 239 234 get_duration(tool->start_time, duration, sizeof(duration)); 240 235 trace_seq_printf(s, "# RTLA osnoise histogram\n"); 241 236 trace_seq_printf(s, "# Time unit is %s (%s)\n", 242 - params->output_divisor == 1 ? "nanoseconds" : "microseconds", 243 - params->output_divisor == 1 ? "ns" : "us"); 237 + params->common.output_divisor == 1 ? "nanoseconds" : "microseconds", 238 + params->common.output_divisor == 1 ? "ns" : "us"); 244 239 245 240 trace_seq_printf(s, "# Duration: %s\n", duration); 246 241 247 - if (!params->no_index) 242 + if (!params->common.hist.no_index) 248 243 trace_seq_printf(s, "Index"); 249 244 250 245 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 251 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 246 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 252 247 continue; 253 248 254 249 if (!data->hist[cpu].count) ··· 272 267 { 273 268 int cpu; 274 269 275 - if (params->no_summary) 270 + if (params->common.hist.no_summary) 276 271 return; 277 272 278 - if (!params->no_index) 273 + if (!params->common.hist.no_index) 279 274 trace_seq_printf(trace->seq, "count:"); 280 275 281 276 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 282 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 277 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 283 278 continue; 284 279 285 280 if (!data->hist[cpu].count) ··· 289 284 } 290 285 trace_seq_printf(trace->seq, "\n"); 291 286 292 - if (!params->no_index) 287 + if (!params->common.hist.no_index) 293 288 trace_seq_printf(trace->seq, "min: "); 294 289 295 290 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 296 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 291 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 297 292 continue; 298 293 299 294 if (!data->hist[cpu].count) ··· 304 299 } 305 300 trace_seq_printf(trace->seq, "\n"); 306 301 307 - if (!params->no_index) 302 + if (!params->common.hist.no_index) 308 303 trace_seq_printf(trace->seq, "avg: "); 309 304 310 305 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 311 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 306 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 312 307 continue; 313 308 314 309 if (!data->hist[cpu].count) ··· 322 317 } 323 318 trace_seq_printf(trace->seq, "\n"); 324 319 325 - if (!params->no_index) 320 + if (!params->common.hist.no_index) 326 321 trace_seq_printf(trace->seq, "max: "); 327 322 328 323 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 329 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 324 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 330 325 continue; 331 326 332 327 if (!data->hist[cpu].count) ··· 344 339 * osnoise_print_stats - print data for all CPUs 345 340 */ 346 341 static void 347 - osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *tool) 342 + osnoise_print_stats(struct osnoise_tool *tool) 348 343 { 344 + struct osnoise_params *params = to_osnoise_params(tool->params); 349 345 struct osnoise_hist_data *data = tool->data; 350 346 struct trace_instance *trace = &tool->trace; 351 347 int has_samples = 0; ··· 358 352 for (bucket = 0; bucket < data->entries; bucket++) { 359 353 total = 0; 360 354 361 - if (!params->no_index) 355 + if (!params->common.hist.no_index) 362 356 trace_seq_printf(trace->seq, "%-6d", 363 357 bucket * data->bucket_size); 364 358 365 359 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 366 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 360 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 367 361 continue; 368 362 369 363 if (!data->hist[cpu].count) ··· 373 367 trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].samples[bucket]); 374 368 } 375 369 376 - if (total == 0 && !params->with_zeros) { 370 + if (total == 0 && !params->common.hist.with_zeros) { 377 371 trace_seq_reset(trace->seq); 378 372 continue; 379 373 } ··· 397 391 return; 398 392 } 399 393 400 - if (!params->no_index) 394 + if (!params->common.hist.no_index) 401 395 trace_seq_printf(trace->seq, "over: "); 402 396 403 397 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 404 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 398 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 405 399 continue; 406 400 407 401 if (!data->hist[cpu].count) ··· 462 456 " in nanoseconds", 463 457 " --warm-up: let the workload run for s seconds before collecting data", 464 458 " --trace-buffer-size kB: set the per-cpu trace buffer size in kB", 459 + " --on-threshold <action>: define action to be executed at stop-total threshold, multiple are allowed", 460 + " --on-end <action>: define action to be executed at measurement end, multiple are allowed", 465 461 NULL, 466 462 }; 467 463 ··· 485 477 /* 486 478 * osnoise_hist_parse_args - allocs, parse and fill the cmd line parameters 487 479 */ 488 - static struct osnoise_params 480 + static struct common_params 489 481 *osnoise_hist_parse_args(int argc, char *argv[]) 490 482 { 491 483 struct osnoise_params *params; 492 484 struct trace_events *tevent; 493 485 int retval; 494 486 int c; 487 + char *trace_output = NULL; 495 488 496 489 params = calloc(1, sizeof(*params)); 497 490 if (!params) 498 491 exit(1); 499 492 493 + actions_init(&params->common.threshold_actions); 494 + actions_init(&params->common.end_actions); 495 + 500 496 /* display data in microseconds */ 501 - params->output_divisor = 1000; 502 - params->bucket_size = 1; 503 - params->entries = 256; 497 + params->common.output_divisor = 1000; 498 + params->common.hist.bucket_size = 1; 499 + params->common.hist.entries = 256; 504 500 505 501 while (1) { 506 502 static struct option long_options[] = { ··· 533 521 {"filter", required_argument, 0, '5'}, 534 522 {"warm-up", required_argument, 0, '6'}, 535 523 {"trace-buffer-size", required_argument, 0, '7'}, 524 + {"on-threshold", required_argument, 0, '8'}, 525 + {"on-end", required_argument, 0, '9'}, 536 526 {0, 0, 0, 0} 537 527 }; 538 528 ··· 551 537 switch (c) { 552 538 case 'a': 553 539 /* set sample stop to auto_thresh */ 554 - params->stop_us = get_llong_from_str(optarg); 540 + params->common.stop_us = get_llong_from_str(optarg); 555 541 556 542 /* set sample threshold to 1 */ 557 543 params->threshold = 1; 558 544 559 545 /* set trace */ 560 - params->trace_output = "osnoise_trace.txt"; 546 + trace_output = "osnoise_trace.txt"; 561 547 562 548 break; 563 549 case 'b': 564 - params->bucket_size = get_llong_from_str(optarg); 565 - if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) 550 + params->common.hist.bucket_size = get_llong_from_str(optarg); 551 + if (params->common.hist.bucket_size == 0 || 552 + params->common.hist.bucket_size >= 1000000) 566 553 osnoise_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); 567 554 break; 568 555 case 'c': 569 - retval = parse_cpu_set(optarg, &params->monitored_cpus); 556 + retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 570 557 if (retval) 571 558 osnoise_hist_usage("\nInvalid -c cpu list\n"); 572 - params->cpus = optarg; 559 + params->common.cpus = optarg; 573 560 break; 574 561 case 'C': 575 - params->cgroup = 1; 562 + params->common.cgroup = 1; 576 563 if (!optarg) { 577 564 /* will inherit this cgroup */ 578 - params->cgroup_name = NULL; 565 + params->common.cgroup_name = NULL; 579 566 } else if (*optarg == '=') { 580 567 /* skip the = */ 581 - params->cgroup_name = ++optarg; 568 + params->common.cgroup_name = ++optarg; 582 569 } 583 570 break; 584 571 case 'D': 585 572 config_debug = 1; 586 573 break; 587 574 case 'd': 588 - params->duration = parse_seconds_duration(optarg); 589 - if (!params->duration) 575 + params->common.duration = parse_seconds_duration(optarg); 576 + if (!params->common.duration) 590 577 osnoise_hist_usage("Invalid -D duration\n"); 591 578 break; 592 579 case 'e': ··· 597 582 exit(EXIT_FAILURE); 598 583 } 599 584 600 - if (params->events) 601 - tevent->next = params->events; 585 + if (params->common.events) 586 + tevent->next = params->common.events; 602 587 603 - params->events = tevent; 588 + params->common.events = tevent; 604 589 break; 605 590 case 'E': 606 - params->entries = get_llong_from_str(optarg); 607 - if ((params->entries < 10) || (params->entries > 9999999)) 591 + params->common.hist.entries = get_llong_from_str(optarg); 592 + if (params->common.hist.entries < 10 || 593 + params->common.hist.entries > 9999999) 608 594 osnoise_hist_usage("Entries must be > 10 and < 9999999\n"); 609 595 break; 610 596 case 'h': ··· 613 597 osnoise_hist_usage(NULL); 614 598 break; 615 599 case 'H': 616 - params->hk_cpus = 1; 617 - retval = parse_cpu_set(optarg, &params->hk_cpu_set); 600 + params->common.hk_cpus = 1; 601 + retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 618 602 if (retval) { 619 603 err_msg("Error parsing house keeping CPUs\n"); 620 604 exit(EXIT_FAILURE); ··· 626 610 osnoise_hist_usage("Period longer than 10 s\n"); 627 611 break; 628 612 case 'P': 629 - retval = parse_prio(optarg, &params->sched_param); 613 + retval = parse_prio(optarg, &params->common.sched_param); 630 614 if (retval == -1) 631 615 osnoise_hist_usage("Invalid -P priority"); 632 - params->set_sched = 1; 616 + params->common.set_sched = 1; 633 617 break; 634 618 case 'r': 635 619 params->runtime = get_llong_from_str(optarg); ··· 637 621 osnoise_hist_usage("Runtime shorter than 100 us\n"); 638 622 break; 639 623 case 's': 640 - params->stop_us = get_llong_from_str(optarg); 624 + params->common.stop_us = get_llong_from_str(optarg); 641 625 break; 642 626 case 'S': 643 - params->stop_total_us = get_llong_from_str(optarg); 627 + params->common.stop_total_us = get_llong_from_str(optarg); 644 628 break; 645 629 case 'T': 646 630 params->threshold = get_llong_from_str(optarg); ··· 648 632 case 't': 649 633 if (optarg) { 650 634 if (optarg[0] == '=') 651 - params->trace_output = &optarg[1]; 635 + trace_output = &optarg[1]; 652 636 else 653 - params->trace_output = &optarg[0]; 637 + trace_output = &optarg[0]; 654 638 } else if (optind < argc && argv[optind][0] != '0') 655 - params->trace_output = argv[optind]; 639 + trace_output = argv[optind]; 656 640 else 657 - params->trace_output = "osnoise_trace.txt"; 641 + trace_output = "osnoise_trace.txt"; 658 642 break; 659 643 case '0': /* no header */ 660 - params->no_header = 1; 644 + params->common.hist.no_header = 1; 661 645 break; 662 646 case '1': /* no summary */ 663 - params->no_summary = 1; 647 + params->common.hist.no_summary = 1; 664 648 break; 665 649 case '2': /* no index */ 666 - params->no_index = 1; 650 + params->common.hist.no_index = 1; 667 651 break; 668 652 case '3': /* with zeros */ 669 - params->with_zeros = 1; 653 + params->common.hist.with_zeros = 1; 670 654 break; 671 655 case '4': /* trigger */ 672 - if (params->events) { 673 - retval = trace_event_add_trigger(params->events, optarg); 656 + if (params->common.events) { 657 + retval = trace_event_add_trigger(params->common.events, optarg); 674 658 if (retval) { 675 659 err_msg("Error adding trigger %s\n", optarg); 676 660 exit(EXIT_FAILURE); ··· 680 664 } 681 665 break; 682 666 case '5': /* filter */ 683 - if (params->events) { 684 - retval = trace_event_add_filter(params->events, optarg); 667 + if (params->common.events) { 668 + retval = trace_event_add_filter(params->common.events, optarg); 685 669 if (retval) { 686 670 err_msg("Error adding filter %s\n", optarg); 687 671 exit(EXIT_FAILURE); ··· 691 675 } 692 676 break; 693 677 case '6': 694 - params->warmup = get_llong_from_str(optarg); 678 + params->common.warmup = get_llong_from_str(optarg); 695 679 break; 696 680 case '7': 697 - params->buffer_size = get_llong_from_str(optarg); 681 + params->common.buffer_size = get_llong_from_str(optarg); 682 + break; 683 + case '8': 684 + retval = actions_parse(&params->common.threshold_actions, optarg, 685 + "osnoise_trace.txt"); 686 + if (retval) { 687 + err_msg("Invalid action %s\n", optarg); 688 + exit(EXIT_FAILURE); 689 + } 690 + break; 691 + case '9': 692 + retval = actions_parse(&params->common.end_actions, optarg, 693 + "osnoise_trace.txt"); 694 + if (retval) { 695 + err_msg("Invalid action %s\n", optarg); 696 + exit(EXIT_FAILURE); 697 + } 698 698 break; 699 699 default: 700 700 osnoise_hist_usage("Invalid option"); 701 701 } 702 702 } 703 703 704 + if (trace_output) 705 + actions_add_trace_output(&params->common.threshold_actions, trace_output); 706 + 704 707 if (geteuid()) { 705 708 err_msg("rtla needs root permission\n"); 706 709 exit(EXIT_FAILURE); 707 710 } 708 711 709 - if (params->no_index && !params->with_zeros) 712 + if (params->common.hist.no_index && !params->common.hist.with_zeros) 710 713 osnoise_hist_usage("no-index set and with-zeros not set - it does not make sense"); 711 714 712 - return params; 715 + return &params->common; 713 716 } 714 717 715 718 /* 716 719 * osnoise_hist_apply_config - apply the hist configs to the initialized tool 717 720 */ 718 721 static int 719 - osnoise_hist_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) 722 + osnoise_hist_apply_config(struct osnoise_tool *tool) 720 723 { 721 - int retval; 722 - 723 - retval = osnoise_apply_config(tool, params); 724 - if (retval) 725 - goto out_err; 726 - 727 - return 0; 728 - 729 - out_err: 730 - return -1; 724 + return osnoise_apply_config(tool, to_osnoise_params(tool->params)); 731 725 } 732 726 733 727 /* 734 728 * osnoise_init_hist - initialize a osnoise hist tool with parameters 735 729 */ 736 730 static struct osnoise_tool 737 - *osnoise_init_hist(struct osnoise_params *params) 731 + *osnoise_init_hist(struct common_params *params) 738 732 { 739 733 struct osnoise_tool *tool; 740 734 int nr_cpus; ··· 755 729 if (!tool) 756 730 return NULL; 757 731 758 - tool->data = osnoise_alloc_histogram(nr_cpus, params->entries, params->bucket_size); 732 + tool->data = osnoise_alloc_histogram(nr_cpus, params->hist.entries, 733 + params->hist.bucket_size); 759 734 if (!tool->data) 760 735 goto out_err; 761 - 762 - tool->params = params; 763 736 764 737 return tool; 765 738 ··· 767 742 return NULL; 768 743 } 769 744 770 - static int stop_tracing; 771 - static void stop_hist(int sig) 745 + static int osnoise_hist_enable(struct osnoise_tool *tool) 772 746 { 773 - stop_tracing = 1; 774 - } 775 - 776 - /* 777 - * osnoise_hist_set_signals - handles the signal to stop the tool 778 - */ 779 - static void 780 - osnoise_hist_set_signals(struct osnoise_params *params) 781 - { 782 - signal(SIGINT, stop_hist); 783 - if (params->duration) { 784 - signal(SIGALRM, stop_hist); 785 - alarm(params->duration); 786 - } 787 - } 788 - 789 - int osnoise_hist_main(int argc, char *argv[]) 790 - { 791 - struct osnoise_params *params; 792 - struct osnoise_tool *record = NULL; 793 - struct osnoise_tool *tool = NULL; 794 - enum result return_value = ERROR; 795 - struct trace_instance *trace; 796 747 int retval; 797 - 798 - params = osnoise_hist_parse_args(argc, argv); 799 - if (!params) 800 - exit(1); 801 - 802 - tool = osnoise_init_hist(params); 803 - if (!tool) { 804 - err_msg("Could not init osnoise hist\n"); 805 - goto out_exit; 806 - } 807 - 808 - retval = osnoise_hist_apply_config(tool, params); 809 - if (retval) { 810 - err_msg("Could not apply config\n"); 811 - goto out_destroy; 812 - } 813 - 814 - trace = &tool->trace; 815 - 816 - retval = enable_osnoise(trace); 817 - if (retval) { 818 - err_msg("Failed to enable osnoise tracer\n"); 819 - goto out_destroy; 820 - } 821 748 822 749 retval = osnoise_init_trace_hist(tool); 823 750 if (retval) 824 - goto out_destroy; 751 + return retval; 825 752 826 - if (params->set_sched) { 827 - retval = set_comm_sched_attr("osnoise/", &params->sched_param); 828 - if (retval) { 829 - err_msg("Failed to set sched parameters\n"); 830 - goto out_free; 831 - } 832 - } 753 + return osnoise_enable(tool); 754 + } 833 755 834 - if (params->cgroup) { 835 - retval = set_comm_cgroup("timerlat/", params->cgroup_name); 836 - if (!retval) { 837 - err_msg("Failed to move threads to cgroup\n"); 838 - goto out_free; 839 - } 840 - } 756 + static int osnoise_hist_main_loop(struct osnoise_tool *tool) 757 + { 758 + int retval; 841 759 842 - if (params->trace_output) { 843 - record = osnoise_init_trace_tool("osnoise"); 844 - if (!record) { 845 - err_msg("Failed to enable the trace instance\n"); 846 - goto out_free; 847 - } 848 - 849 - if (params->events) { 850 - retval = trace_events_enable(&record->trace, params->events); 851 - if (retval) 852 - goto out_hist; 853 - } 854 - 855 - if (params->buffer_size > 0) { 856 - retval = trace_set_buffer_size(&record->trace, params->buffer_size); 857 - if (retval) 858 - goto out_hist; 859 - } 860 - } 861 - 862 - /* 863 - * Start the tracer here, after having set all instances. 864 - * 865 - * Let the trace instance start first for the case of hitting a stop 866 - * tracing while enabling other instances. The trace instance is the 867 - * one with most valuable information. 868 - */ 869 - if (params->trace_output) 870 - trace_instance_start(&record->trace); 871 - trace_instance_start(trace); 872 - 873 - if (params->warmup > 0) { 874 - debug_msg("Warming up for %d seconds\n", params->warmup); 875 - sleep(params->warmup); 876 - if (stop_tracing) 877 - goto out_hist; 878 - 879 - /* 880 - * Clean up the buffer. The osnoise workload do not run 881 - * with tracing off to avoid creating a performance penalty 882 - * when not needed. 883 - */ 884 - retval = tracefs_instance_file_write(trace->inst, "trace", ""); 885 - if (retval < 0) { 886 - debug_msg("Error cleaning up the buffer"); 887 - goto out_hist; 888 - } 889 - 890 - } 891 - 892 - tool->start_time = time(NULL); 893 - osnoise_hist_set_signals(params); 894 - 895 - while (!stop_tracing) { 896 - sleep(params->sleep_time); 897 - 898 - retval = tracefs_iterate_raw_events(trace->tep, 899 - trace->inst, 900 - NULL, 901 - 0, 902 - collect_registered_events, 903 - trace); 904 - if (retval < 0) { 905 - err_msg("Error iterating on events\n"); 906 - goto out_hist; 907 - } 908 - 909 - if (osnoise_trace_is_off(tool, record)) 910 - break; 911 - } 912 - 760 + retval = hist_main_loop(tool); 913 761 osnoise_read_trace_hist(tool); 914 762 915 - osnoise_print_stats(params, tool); 916 - 917 - return_value = PASSED; 918 - 919 - if (osnoise_trace_is_off(tool, record)) { 920 - printf("rtla osnoise hit stop tracing\n"); 921 - save_trace_to_file(record ? record->trace.inst : NULL, 922 - params->trace_output); 923 - return_value = FAILED; 924 - } 925 - 926 - out_hist: 927 - trace_events_destroy(&record->trace, params->events); 928 - params->events = NULL; 929 - out_free: 930 - osnoise_free_histogram(tool->data); 931 - out_destroy: 932 - osnoise_destroy_tool(record); 933 - osnoise_destroy_tool(tool); 934 - free(params); 935 - out_exit: 936 - exit(return_value); 763 + return retval; 937 764 } 765 + 766 + struct tool_ops osnoise_hist_ops = { 767 + .tracer = "osnoise", 768 + .comm_prefix = "osnoise/", 769 + .parse_args = osnoise_hist_parse_args, 770 + .init_tool = osnoise_init_hist, 771 + .apply_config = osnoise_hist_apply_config, 772 + .enable = osnoise_hist_enable, 773 + .main = osnoise_hist_main_loop, 774 + .print_stats = osnoise_print_stats, 775 + .free = osnoise_free_hist_tool, 776 + };
+91 -212
tools/tracing/rtla/src/osnoise_top.c
··· 37 37 /* 38 38 * osnoise_free_top - free runtime data 39 39 */ 40 - static void 41 - osnoise_free_top(struct osnoise_top_data *data) 40 + static void osnoise_free_top(struct osnoise_top_data *data) 42 41 { 43 42 free(data->cpu_data); 44 43 free(data); 44 + } 45 + 46 + static void osnoise_free_top_tool(struct osnoise_tool *tool) 47 + { 48 + osnoise_free_top(tool->data); 45 49 } 46 50 47 51 /* ··· 127 123 */ 128 124 static void osnoise_top_header(struct osnoise_tool *top) 129 125 { 130 - struct osnoise_params *params = top->params; 126 + struct osnoise_params *params = to_osnoise_params(top->params); 131 127 struct trace_seq *s = top->trace.seq; 128 + bool pretty = params->common.pretty_output; 132 129 char duration[26]; 133 130 134 131 get_duration(top->start_time, duration, sizeof(duration)); 135 132 136 - if (params->pretty_output) 133 + if (pretty) 137 134 trace_seq_printf(s, "\033[2;37;40m"); 138 135 139 136 trace_seq_printf(s, " "); ··· 148 143 149 144 trace_seq_printf(s, " "); 150 145 151 - if (params->pretty_output) 146 + if (pretty) 152 147 trace_seq_printf(s, "\033[0;0;0m"); 153 148 trace_seq_printf(s, "\n"); 154 149 155 150 trace_seq_printf(s, "duration: %9s | time is in us\n", duration); 156 151 157 - if (params->pretty_output) 152 + if (pretty) 158 153 trace_seq_printf(s, "\033[2;30;47m"); 159 154 160 155 trace_seq_printf(s, "CPU Period Runtime "); ··· 169 164 trace_seq_printf(s, " IRQ Softirq Thread"); 170 165 171 166 eol: 172 - if (params->pretty_output) 167 + if (pretty) 173 168 trace_seq_printf(s, "\033[0;0;0m"); 174 169 trace_seq_printf(s, "\n"); 175 170 } ··· 188 183 */ 189 184 static void osnoise_top_print(struct osnoise_tool *tool, int cpu) 190 185 { 191 - struct osnoise_params *params = tool->params; 186 + struct osnoise_params *params = to_osnoise_params(tool->params); 192 187 struct trace_seq *s = tool->trace.seq; 193 188 struct osnoise_top_cpu *cpu_data; 194 189 struct osnoise_top_data *data; ··· 228 223 * osnoise_print_stats - print data for all cpus 229 224 */ 230 225 static void 231 - osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *top) 226 + osnoise_print_stats(struct osnoise_tool *top) 232 227 { 228 + struct osnoise_params *params = to_osnoise_params(top->params); 233 229 struct trace_instance *trace = &top->trace; 234 230 static int nr_cpus = -1; 235 231 int i; ··· 238 232 if (nr_cpus == -1) 239 233 nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 240 234 241 - if (!params->quiet) 235 + if (!params->common.quiet) 242 236 clear_terminal(trace->seq); 243 237 244 238 osnoise_top_header(top); 245 239 246 240 for (i = 0; i < nr_cpus; i++) { 247 - if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus)) 241 + if (params->common.cpus && !CPU_ISSET(i, &params->common.monitored_cpus)) 248 242 continue; 249 243 osnoise_top_print(top, i); 250 244 } ··· 291 285 " in nanoseconds", 292 286 " --warm-up s: let the workload run for s seconds before collecting data", 293 287 " --trace-buffer-size kB: set the per-cpu trace buffer size in kB", 288 + " --on-threshold <action>: define action to be executed at stop-total threshold, multiple are allowed", 289 + " --on-end: define action to be executed at measurement end, multiple are allowed", 294 290 NULL, 295 291 }; 296 292 ··· 327 319 /* 328 320 * osnoise_top_parse_args - allocs, parse and fill the cmd line parameters 329 321 */ 330 - struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) 322 + struct common_params *osnoise_top_parse_args(int argc, char **argv) 331 323 { 332 324 struct osnoise_params *params; 333 325 struct trace_events *tevent; 334 326 int retval; 335 327 int c; 328 + char *trace_output = NULL; 336 329 337 330 params = calloc(1, sizeof(*params)); 338 331 if (!params) 339 332 exit(1); 333 + 334 + actions_init(&params->common.threshold_actions); 335 + actions_init(&params->common.end_actions); 340 336 341 337 if (strcmp(argv[0], "hwnoise") == 0) { 342 338 params->mode = MODE_HWNOISE; ··· 373 361 {"filter", required_argument, 0, '1'}, 374 362 {"warm-up", required_argument, 0, '2'}, 375 363 {"trace-buffer-size", required_argument, 0, '3'}, 364 + {"on-threshold", required_argument, 0, '4'}, 365 + {"on-end", required_argument, 0, '5'}, 376 366 {0, 0, 0, 0} 377 367 }; 378 368 ··· 391 377 switch (c) { 392 378 case 'a': 393 379 /* set sample stop to auto_thresh */ 394 - params->stop_us = get_llong_from_str(optarg); 380 + params->common.stop_us = get_llong_from_str(optarg); 395 381 396 382 /* set sample threshold to 1 */ 397 383 params->threshold = 1; 398 384 399 385 /* set trace */ 400 - params->trace_output = "osnoise_trace.txt"; 386 + trace_output = "osnoise_trace.txt"; 401 387 402 388 break; 403 389 case 'c': 404 - retval = parse_cpu_set(optarg, &params->monitored_cpus); 390 + retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 405 391 if (retval) 406 392 osnoise_top_usage(params, "\nInvalid -c cpu list\n"); 407 - params->cpus = optarg; 393 + params->common.cpus = optarg; 408 394 break; 409 395 case 'C': 410 - params->cgroup = 1; 396 + params->common.cgroup = 1; 411 397 if (!optarg) { 412 398 /* will inherit this cgroup */ 413 - params->cgroup_name = NULL; 399 + params->common.cgroup_name = NULL; 414 400 } else if (*optarg == '=') { 415 401 /* skip the = */ 416 - params->cgroup_name = ++optarg; 402 + params->common.cgroup_name = ++optarg; 417 403 } 418 404 break; 419 405 case 'D': 420 406 config_debug = 1; 421 407 break; 422 408 case 'd': 423 - params->duration = parse_seconds_duration(optarg); 424 - if (!params->duration) 409 + params->common.duration = parse_seconds_duration(optarg); 410 + if (!params->common.duration) 425 411 osnoise_top_usage(params, "Invalid -d duration\n"); 426 412 break; 427 413 case 'e': ··· 431 417 exit(EXIT_FAILURE); 432 418 } 433 419 434 - if (params->events) 435 - tevent->next = params->events; 436 - params->events = tevent; 420 + if (params->common.events) 421 + tevent->next = params->common.events; 422 + params->common.events = tevent; 437 423 438 424 break; 439 425 case 'h': ··· 441 427 osnoise_top_usage(params, NULL); 442 428 break; 443 429 case 'H': 444 - params->hk_cpus = 1; 445 - retval = parse_cpu_set(optarg, &params->hk_cpu_set); 430 + params->common.hk_cpus = 1; 431 + retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 446 432 if (retval) { 447 433 err_msg("Error parsing house keeping CPUs\n"); 448 434 exit(EXIT_FAILURE); ··· 454 440 osnoise_top_usage(params, "Period longer than 10 s\n"); 455 441 break; 456 442 case 'P': 457 - retval = parse_prio(optarg, &params->sched_param); 443 + retval = parse_prio(optarg, &params->common.sched_param); 458 444 if (retval == -1) 459 445 osnoise_top_usage(params, "Invalid -P priority"); 460 - params->set_sched = 1; 446 + params->common.set_sched = 1; 461 447 break; 462 448 case 'q': 463 - params->quiet = 1; 449 + params->common.quiet = 1; 464 450 break; 465 451 case 'r': 466 452 params->runtime = get_llong_from_str(optarg); ··· 468 454 osnoise_top_usage(params, "Runtime shorter than 100 us\n"); 469 455 break; 470 456 case 's': 471 - params->stop_us = get_llong_from_str(optarg); 457 + params->common.stop_us = get_llong_from_str(optarg); 472 458 break; 473 459 case 'S': 474 - params->stop_total_us = get_llong_from_str(optarg); 460 + params->common.stop_total_us = get_llong_from_str(optarg); 475 461 break; 476 462 case 't': 477 463 if (optarg) { 478 464 if (optarg[0] == '=') 479 - params->trace_output = &optarg[1]; 465 + trace_output = &optarg[1]; 480 466 else 481 - params->trace_output = &optarg[0]; 467 + trace_output = &optarg[0]; 482 468 } else if (optind < argc && argv[optind][0] != '-') 483 - params->trace_output = argv[optind]; 469 + trace_output = argv[optind]; 484 470 else 485 - params->trace_output = "osnoise_trace.txt"; 471 + trace_output = "osnoise_trace.txt"; 486 472 break; 487 473 case 'T': 488 474 params->threshold = get_llong_from_str(optarg); 489 475 break; 490 476 case '0': /* trigger */ 491 - if (params->events) { 492 - retval = trace_event_add_trigger(params->events, optarg); 477 + if (params->common.events) { 478 + retval = trace_event_add_trigger(params->common.events, optarg); 493 479 if (retval) { 494 480 err_msg("Error adding trigger %s\n", optarg); 495 481 exit(EXIT_FAILURE); ··· 499 485 } 500 486 break; 501 487 case '1': /* filter */ 502 - if (params->events) { 503 - retval = trace_event_add_filter(params->events, optarg); 488 + if (params->common.events) { 489 + retval = trace_event_add_filter(params->common.events, optarg); 504 490 if (retval) { 505 491 err_msg("Error adding filter %s\n", optarg); 506 492 exit(EXIT_FAILURE); ··· 510 496 } 511 497 break; 512 498 case '2': 513 - params->warmup = get_llong_from_str(optarg); 499 + params->common.warmup = get_llong_from_str(optarg); 514 500 break; 515 501 case '3': 516 - params->buffer_size = get_llong_from_str(optarg); 502 + params->common.buffer_size = get_llong_from_str(optarg); 503 + break; 504 + case '4': 505 + retval = actions_parse(&params->common.threshold_actions, optarg, 506 + "osnoise_trace.txt"); 507 + if (retval) { 508 + err_msg("Invalid action %s\n", optarg); 509 + exit(EXIT_FAILURE); 510 + } 511 + break; 512 + case '5': 513 + retval = actions_parse(&params->common.end_actions, optarg, 514 + "osnoise_trace.txt"); 515 + if (retval) { 516 + err_msg("Invalid action %s\n", optarg); 517 + exit(EXIT_FAILURE); 518 + } 517 519 break; 518 520 default: 519 521 osnoise_top_usage(params, "Invalid option"); 520 522 } 521 523 } 522 524 525 + if (trace_output) 526 + actions_add_trace_output(&params->common.threshold_actions, trace_output); 527 + 523 528 if (geteuid()) { 524 529 err_msg("osnoise needs root permission\n"); 525 530 exit(EXIT_FAILURE); 526 531 } 527 532 528 - return params; 533 + return &params->common; 529 534 } 530 535 531 536 /* 532 537 * osnoise_top_apply_config - apply the top configs to the initialized tool 533 538 */ 534 539 static int 535 - osnoise_top_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) 540 + osnoise_top_apply_config(struct osnoise_tool *tool) 536 541 { 542 + struct osnoise_params *params = to_osnoise_params(tool->params); 537 543 int retval; 538 544 539 545 retval = osnoise_apply_config(tool, params); ··· 568 534 } 569 535 } 570 536 571 - if (isatty(STDOUT_FILENO) && !params->quiet) 572 - params->pretty_output = 1; 537 + if (isatty(STDOUT_FILENO) && !params->common.quiet) 538 + params->common.pretty_output = 1; 573 539 574 540 return 0; 575 541 ··· 580 546 /* 581 547 * osnoise_init_top - initialize a osnoise top tool with parameters 582 548 */ 583 - struct osnoise_tool *osnoise_init_top(struct osnoise_params *params) 549 + struct osnoise_tool *osnoise_init_top(struct common_params *params) 584 550 { 585 551 struct osnoise_tool *tool; 586 552 int nr_cpus; ··· 597 563 return NULL; 598 564 } 599 565 600 - tool->params = params; 601 - 602 566 tep_register_event_handler(tool->trace.tep, -1, "ftrace", "osnoise", 603 567 osnoise_top_handler, NULL); 604 568 605 569 return tool; 606 570 } 607 571 608 - static int stop_tracing; 609 - static void stop_top(int sig) 610 - { 611 - stop_tracing = 1; 612 - } 613 - 614 - /* 615 - * osnoise_top_set_signals - handles the signal to stop the tool 616 - */ 617 - static void osnoise_top_set_signals(struct osnoise_params *params) 618 - { 619 - signal(SIGINT, stop_top); 620 - if (params->duration) { 621 - signal(SIGALRM, stop_top); 622 - alarm(params->duration); 623 - } 624 - } 625 - 626 - int osnoise_top_main(int argc, char **argv) 627 - { 628 - struct osnoise_params *params; 629 - struct osnoise_tool *record = NULL; 630 - struct osnoise_tool *tool = NULL; 631 - enum result return_value = ERROR; 632 - struct trace_instance *trace; 633 - int retval; 634 - 635 - params = osnoise_top_parse_args(argc, argv); 636 - if (!params) 637 - exit(1); 638 - 639 - tool = osnoise_init_top(params); 640 - if (!tool) { 641 - err_msg("Could not init osnoise top\n"); 642 - goto out_exit; 643 - } 644 - 645 - retval = osnoise_top_apply_config(tool, params); 646 - if (retval) { 647 - err_msg("Could not apply config\n"); 648 - goto out_free; 649 - } 650 - 651 - trace = &tool->trace; 652 - 653 - retval = enable_osnoise(trace); 654 - if (retval) { 655 - err_msg("Failed to enable osnoise tracer\n"); 656 - goto out_free; 657 - } 658 - 659 - if (params->set_sched) { 660 - retval = set_comm_sched_attr("osnoise/", &params->sched_param); 661 - if (retval) { 662 - err_msg("Failed to set sched parameters\n"); 663 - goto out_free; 664 - } 665 - } 666 - 667 - if (params->cgroup) { 668 - retval = set_comm_cgroup("osnoise/", params->cgroup_name); 669 - if (!retval) { 670 - err_msg("Failed to move threads to cgroup\n"); 671 - goto out_free; 672 - } 673 - } 674 - 675 - if (params->trace_output) { 676 - record = osnoise_init_trace_tool("osnoise"); 677 - if (!record) { 678 - err_msg("Failed to enable the trace instance\n"); 679 - goto out_free; 680 - } 681 - 682 - if (params->events) { 683 - retval = trace_events_enable(&record->trace, params->events); 684 - if (retval) 685 - goto out_top; 686 - } 687 - 688 - if (params->buffer_size > 0) { 689 - retval = trace_set_buffer_size(&record->trace, params->buffer_size); 690 - if (retval) 691 - goto out_top; 692 - } 693 - } 694 - 695 - /* 696 - * Start the tracer here, after having set all instances. 697 - * 698 - * Let the trace instance start first for the case of hitting a stop 699 - * tracing while enabling other instances. The trace instance is the 700 - * one with most valuable information. 701 - */ 702 - if (params->trace_output) 703 - trace_instance_start(&record->trace); 704 - trace_instance_start(trace); 705 - 706 - if (params->warmup > 0) { 707 - debug_msg("Warming up for %d seconds\n", params->warmup); 708 - sleep(params->warmup); 709 - if (stop_tracing) 710 - goto out_top; 711 - 712 - /* 713 - * Clean up the buffer. The osnoise workload do not run 714 - * with tracing off to avoid creating a performance penalty 715 - * when not needed. 716 - */ 717 - retval = tracefs_instance_file_write(trace->inst, "trace", ""); 718 - if (retval < 0) { 719 - debug_msg("Error cleaning up the buffer"); 720 - goto out_top; 721 - } 722 - 723 - } 724 - 725 - tool->start_time = time(NULL); 726 - osnoise_top_set_signals(params); 727 - 728 - while (!stop_tracing) { 729 - sleep(params->sleep_time); 730 - 731 - retval = tracefs_iterate_raw_events(trace->tep, 732 - trace->inst, 733 - NULL, 734 - 0, 735 - collect_registered_events, 736 - trace); 737 - if (retval < 0) { 738 - err_msg("Error iterating on events\n"); 739 - goto out_top; 740 - } 741 - 742 - if (!params->quiet) 743 - osnoise_print_stats(params, tool); 744 - 745 - if (osnoise_trace_is_off(tool, record)) 746 - break; 747 - 748 - } 749 - 750 - osnoise_print_stats(params, tool); 751 - 752 - return_value = PASSED; 753 - 754 - if (osnoise_trace_is_off(tool, record)) { 755 - printf("osnoise hit stop tracing\n"); 756 - save_trace_to_file(record ? record->trace.inst : NULL, 757 - params->trace_output); 758 - return_value = FAILED; 759 - } 760 - 761 - out_top: 762 - trace_events_destroy(&record->trace, params->events); 763 - params->events = NULL; 764 - out_free: 765 - osnoise_free_top(tool->data); 766 - osnoise_destroy_tool(record); 767 - osnoise_destroy_tool(tool); 768 - free(params); 769 - out_exit: 770 - exit(return_value); 771 - } 572 + struct tool_ops osnoise_top_ops = { 573 + .tracer = "osnoise", 574 + .comm_prefix = "osnoise/", 575 + .parse_args = osnoise_top_parse_args, 576 + .init_tool = osnoise_init_top, 577 + .apply_config = osnoise_top_apply_config, 578 + .enable = osnoise_enable, 579 + .main = top_main_loop, 580 + .print_stats = osnoise_print_stats, 581 + .free = osnoise_free_top_tool, 582 + };
+163 -53
tools/tracing/rtla/src/timerlat.c
··· 15 15 #include <sched.h> 16 16 17 17 #include "timerlat.h" 18 + #include "timerlat_aa.h" 19 + #include "timerlat_bpf.h" 18 20 19 21 #define DEFAULT_TIMERLAT_PERIOD 1000 /* 1ms */ 22 + 23 + static int dma_latency_fd = -1; 20 24 21 25 /* 22 26 * timerlat_apply_config - apply common configs to the initialized tool ··· 28 24 int 29 25 timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) 30 26 { 31 - int retval, i; 27 + int retval; 32 28 33 - if (!params->sleep_time) 34 - params->sleep_time = 1; 35 - 36 - retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); 37 - if (retval) { 38 - err_msg("Failed to apply CPUs config\n"); 39 - goto out_err; 40 - } 41 - 42 - if (!params->cpus) { 43 - for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) 44 - CPU_SET(i, &params->monitored_cpus); 29 + /* 30 + * Try to enable BPF, unless disabled explicitly. 31 + * If BPF enablement fails, fall back to tracefs mode. 32 + */ 33 + if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { 34 + debug_msg("RTLA_NO_BPF set, disabling BPF\n"); 35 + params->mode = TRACING_MODE_TRACEFS; 36 + } else if (!tep_find_event_by_name(tool->trace.tep, "osnoise", "timerlat_sample")) { 37 + debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); 38 + params->mode = TRACING_MODE_TRACEFS; 39 + } else { 40 + retval = timerlat_bpf_init(params); 41 + if (retval) { 42 + debug_msg("Could not enable BPF\n"); 43 + params->mode = TRACING_MODE_TRACEFS; 44 + } 45 45 } 46 46 47 47 if (params->mode != TRACING_MODE_BPF) { ··· 53 45 * In tracefs and mixed mode, timerlat tracer handles stopping 54 46 * on threshold 55 47 */ 56 - retval = osnoise_set_stop_us(tool->context, params->stop_us); 48 + retval = osnoise_set_stop_us(tool->context, params->common.stop_us); 57 49 if (retval) { 58 50 err_msg("Failed to set stop us\n"); 59 51 goto out_err; 60 52 } 61 53 62 - retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); 54 + retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us); 63 55 if (retval) { 64 56 err_msg("Failed to set stop total us\n"); 65 57 goto out_err; ··· 83 75 goto out_err; 84 76 } 85 77 86 - if (params->hk_cpus) { 87 - retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), 88 - &params->hk_cpu_set); 89 - if (retval == -1) { 90 - err_msg("Failed to set rtla to the house keeping CPUs\n"); 91 - goto out_err; 92 - } 93 - } else if (params->cpus) { 94 - /* 95 - * Even if the user do not set a house-keeping CPU, try to 96 - * move rtla to a CPU set different to the one where the user 97 - * set the workload to run. 98 - * 99 - * No need to check results as this is an automatic attempt. 100 - */ 101 - auto_house_keeping(&params->monitored_cpus); 102 - } 103 - 104 78 /* 105 79 * If the user did not specify a type of thread, try user-threads first. 106 80 * Fall back to kernel threads otherwise. 107 81 */ 108 - if (!params->kernel_workload && !params->user_data) { 82 + if (!params->common.kernel_workload && !params->common.user_data) { 109 83 retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd"); 110 84 if (retval) { 111 85 debug_msg("User-space interface detected, setting user-threads\n"); 112 - params->user_workload = 1; 113 - params->user_data = 1; 86 + params->common.user_workload = 1; 87 + params->common.user_data = 1; 114 88 } else { 115 89 debug_msg("User-space interface not detected, setting kernel-threads\n"); 116 - params->kernel_workload = 1; 90 + params->common.kernel_workload = 1; 117 91 } 118 92 } 119 93 120 - /* 121 - * Set workload according to type of thread if the kernel supports it. 122 - * On kernels without support, user threads will have already failed 123 - * on missing timerlat_fd, and kernel threads do not need it. 124 - */ 125 - retval = osnoise_set_workload(tool->context, params->kernel_workload); 126 - if (retval < -1) { 127 - err_msg("Failed to set OSNOISE_WORKLOAD option\n"); 128 - goto out_err; 129 - } 130 - 131 - return 0; 94 + return common_apply_config(tool, &params->common); 132 95 133 96 out_err: 134 97 return -1; 98 + } 99 + 100 + int timerlat_enable(struct osnoise_tool *tool) 101 + { 102 + struct timerlat_params *params = to_timerlat_params(tool->params); 103 + int retval, nr_cpus, i; 104 + 105 + if (params->dma_latency >= 0) { 106 + dma_latency_fd = set_cpu_dma_latency(params->dma_latency); 107 + if (dma_latency_fd < 0) { 108 + err_msg("Could not set /dev/cpu_dma_latency.\n"); 109 + return -1; 110 + } 111 + } 112 + 113 + if (params->deepest_idle_state >= -1) { 114 + if (!have_libcpupower_support()) { 115 + err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n"); 116 + return -1; 117 + } 118 + 119 + nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 120 + 121 + for (i = 0; i < nr_cpus; i++) { 122 + if (params->common.cpus && !CPU_ISSET(i, &params->common.monitored_cpus)) 123 + continue; 124 + if (save_cpu_idle_disable_state(i) < 0) { 125 + err_msg("Could not save cpu idle state.\n"); 126 + return -1; 127 + } 128 + if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) { 129 + err_msg("Could not set deepest cpu idle state.\n"); 130 + return -1; 131 + } 132 + } 133 + } 134 + 135 + if (!params->no_aa) { 136 + tool->aa = osnoise_init_tool("timerlat_aa"); 137 + if (!tool->aa) 138 + return -1; 139 + 140 + retval = timerlat_aa_init(tool->aa, params->dump_tasks); 141 + if (retval) { 142 + err_msg("Failed to enable the auto analysis instance\n"); 143 + return retval; 144 + } 145 + 146 + retval = enable_tracer_by_name(tool->aa->trace.inst, "timerlat"); 147 + if (retval) { 148 + err_msg("Failed to enable aa tracer\n"); 149 + return retval; 150 + } 151 + } 152 + 153 + if (params->common.warmup > 0) { 154 + debug_msg("Warming up for %d seconds\n", params->common.warmup); 155 + sleep(params->common.warmup); 156 + if (stop_tracing) 157 + return -1; 158 + } 159 + 160 + /* 161 + * Start the tracers here, after having set all instances. 162 + * 163 + * Let the trace instance start first for the case of hitting a stop 164 + * tracing while enabling other instances. The trace instance is the 165 + * one with most valuable information. 166 + */ 167 + if (tool->record) 168 + trace_instance_start(&tool->record->trace); 169 + if (!params->no_aa) 170 + trace_instance_start(&tool->aa->trace); 171 + if (params->mode == TRACING_MODE_TRACEFS) { 172 + trace_instance_start(&tool->trace); 173 + } else { 174 + retval = timerlat_bpf_attach(); 175 + if (retval) { 176 + err_msg("Error attaching BPF program\n"); 177 + return retval; 178 + } 179 + } 180 + 181 + return 0; 182 + } 183 + 184 + void timerlat_analyze(struct osnoise_tool *tool, bool stopped) 185 + { 186 + struct timerlat_params *params = to_timerlat_params(tool->params); 187 + 188 + if (stopped) { 189 + if (!params->no_aa) 190 + timerlat_auto_analysis(params->common.stop_us, 191 + params->common.stop_total_us); 192 + } else if (params->common.aa_only) { 193 + char *max_lat; 194 + 195 + /* 196 + * If the trace did not stop with --aa-only, at least print 197 + * the max known latency. 198 + */ 199 + max_lat = tracefs_instance_file_read(trace_inst->inst, "tracing_max_latency", NULL); 200 + if (max_lat) { 201 + printf(" Max latency was %s\n", max_lat); 202 + free(max_lat); 203 + } 204 + } 205 + } 206 + 207 + void timerlat_free(struct osnoise_tool *tool) 208 + { 209 + struct timerlat_params *params = to_timerlat_params(tool->params); 210 + int nr_cpus, i; 211 + 212 + timerlat_aa_destroy(); 213 + if (dma_latency_fd >= 0) 214 + close(dma_latency_fd); 215 + if (params->deepest_idle_state >= -1) { 216 + for (i = 0; i < nr_cpus; i++) { 217 + if (params->common.cpus && 218 + !CPU_ISSET(i, &params->common.monitored_cpus)) 219 + continue; 220 + restore_cpu_idle_disable_state(i); 221 + } 222 + } 223 + 224 + osnoise_destroy_tool(tool->aa); 225 + 226 + if (params->mode != TRACING_MODE_TRACEFS) 227 + timerlat_bpf_destroy(); 228 + free_cpu_idle_disable_states(); 135 229 } 136 230 137 231 static void timerlat_usage(int err) ··· 269 159 * default cmdline. 270 160 */ 271 161 if (argc == 1) { 272 - timerlat_top_main(argc, argv); 162 + run_tool(&timerlat_top_ops, argc, argv); 273 163 exit(0); 274 164 } 275 165 ··· 277 167 timerlat_usage(0); 278 168 } else if (strncmp(argv[1], "-", 1) == 0) { 279 169 /* the user skipped the tool, call the default one */ 280 - timerlat_top_main(argc, argv); 170 + run_tool(&timerlat_top_ops, argc, argv); 281 171 exit(0); 282 172 } else if (strcmp(argv[1], "top") == 0) { 283 - timerlat_top_main(argc-1, &argv[1]); 173 + run_tool(&timerlat_top_ops, argc-1, &argv[1]); 284 174 exit(0); 285 175 } else if (strcmp(argv[1], "hist") == 0) { 286 - timerlat_hist_main(argc-1, &argv[1]); 176 + run_tool(&timerlat_hist_ops, argc-1, &argv[1]); 287 177 exit(0); 288 178 } 289 179
+7 -48
tools/tracing/rtla/src/timerlat.h
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - #include "actions.h" 3 2 #include "osnoise.h" 4 3 5 4 /* ··· 19 20 }; 20 21 21 22 struct timerlat_params { 22 - /* Common params */ 23 - char *cpus; 24 - cpu_set_t monitored_cpus; 25 - char *cgroup_name; 26 - unsigned long long runtime; 27 - long long stop_us; 28 - long long stop_total_us; 23 + struct common_params common; 29 24 long long timerlat_period_us; 30 25 long long print_stack; 31 - int sleep_time; 32 - int output_divisor; 33 - int duration; 34 - int set_sched; 35 26 int dma_latency; 36 27 int no_aa; 37 28 int dump_tasks; 38 - int cgroup; 39 - int hk_cpus; 40 - int user_workload; 41 - int kernel_workload; 42 - int user_data; 43 - int warmup; 44 - int buffer_size; 45 29 int deepest_idle_state; 46 - cpu_set_t hk_cpu_set; 47 - struct sched_attr sched_param; 48 - struct trace_events *events; 49 30 enum timerlat_tracing_mode mode; 50 - 51 - struct actions threshold_actions; 52 - struct actions end_actions; 53 - 54 - union { 55 - struct { 56 - /* top only */ 57 - int quiet; 58 - int aa_only; 59 - int pretty_output; 60 - }; 61 - struct { 62 - /* hist only */ 63 - char no_irq; 64 - char no_thread; 65 - char no_header; 66 - char no_summary; 67 - char no_index; 68 - char with_zeros; 69 - int bucket_size; 70 - int entries; 71 - }; 72 - }; 73 31 }; 74 32 75 - int timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params); 33 + #define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common) 76 34 77 - int timerlat_hist_main(int argc, char *argv[]); 78 - int timerlat_top_main(int argc, char *argv[]); 35 + int timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params); 79 36 int timerlat_main(int argc, char *argv[]); 37 + int timerlat_enable(struct osnoise_tool *tool); 38 + void timerlat_analyze(struct osnoise_tool *tool, bool stopped); 39 + void timerlat_free(struct osnoise_tool *tool); 40 +
+11 -11
tools/tracing/rtla/src/timerlat_bpf.c
··· 21 21 return 1; 22 22 23 23 /* Pass common options */ 24 - bpf->rodata->output_divisor = params->output_divisor; 25 - bpf->rodata->entries = params->entries; 26 - bpf->rodata->irq_threshold = params->stop_us; 27 - bpf->rodata->thread_threshold = params->stop_total_us; 28 - bpf->rodata->aa_only = params->aa_only; 24 + bpf->rodata->output_divisor = params->common.output_divisor; 25 + bpf->rodata->entries = params->common.hist.entries; 26 + bpf->rodata->irq_threshold = params->common.stop_us; 27 + bpf->rodata->thread_threshold = params->common.stop_total_us; 28 + bpf->rodata->aa_only = params->common.aa_only; 29 29 30 - if (params->entries != 0) { 30 + if (params->common.hist.entries != 0) { 31 31 /* Pass histogram options */ 32 - bpf->rodata->bucket_size = params->bucket_size; 32 + bpf->rodata->bucket_size = params->common.hist.bucket_size; 33 33 34 34 /* Set histogram array sizes */ 35 - bpf_map__set_max_entries(bpf->maps.hist_irq, params->entries); 36 - bpf_map__set_max_entries(bpf->maps.hist_thread, params->entries); 37 - bpf_map__set_max_entries(bpf->maps.hist_user, params->entries); 35 + bpf_map__set_max_entries(bpf->maps.hist_irq, params->common.hist.entries); 36 + bpf_map__set_max_entries(bpf->maps.hist_thread, params->common.hist.entries); 37 + bpf_map__set_max_entries(bpf->maps.hist_user, params->common.hist.entries); 38 38 } else { 39 39 /* No entries, disable histogram */ 40 40 bpf_map__set_autocreate(bpf->maps.hist_irq, false); ··· 42 42 bpf_map__set_autocreate(bpf->maps.hist_user, false); 43 43 } 44 44 45 - if (params->aa_only) { 45 + if (params->common.aa_only) { 46 46 /* Auto-analysis only, disable summary */ 47 47 bpf_map__set_autocreate(bpf->maps.summary_irq, false); 48 48 bpf_map__set_autocreate(bpf->maps.summary_thread, false);
+185 -463
tools/tracing/rtla/src/timerlat_hist.c
··· 16 16 17 17 #include "timerlat.h" 18 18 #include "timerlat_aa.h" 19 - #include "timerlat_u.h" 20 19 #include "timerlat_bpf.h" 21 20 22 21 struct timerlat_hist_cpu { ··· 71 72 /* one set of histograms per CPU */ 72 73 if (data->hist) 73 74 free(data->hist); 75 + } 74 76 75 - free(data); 77 + static void timerlat_free_histogram_tool(struct osnoise_tool *tool) 78 + { 79 + timerlat_free_histogram(tool->data); 80 + timerlat_free(tool); 76 81 } 77 82 78 83 /* ··· 138 135 unsigned long long context, 139 136 unsigned long long latency) 140 137 { 141 - struct timerlat_params *params = tool->params; 138 + struct timerlat_params *params = to_timerlat_params(tool->params); 142 139 struct timerlat_hist_data *data = tool->data; 143 140 int entries = data->entries; 144 141 int bucket; 145 142 int *hist; 146 143 147 - if (params->output_divisor) 148 - latency = latency / params->output_divisor; 144 + if (params->common.output_divisor) 145 + latency = latency / params->common.output_divisor; 149 146 150 147 bucket = latency / data->bucket_size; 151 148 ··· 285 282 */ 286 283 static void timerlat_hist_header(struct osnoise_tool *tool) 287 284 { 288 - struct timerlat_params *params = tool->params; 285 + struct timerlat_params *params = to_timerlat_params(tool->params); 289 286 struct timerlat_hist_data *data = tool->data; 290 287 struct trace_seq *s = tool->trace.seq; 291 288 char duration[26]; 292 289 int cpu; 293 290 294 - if (params->no_header) 291 + if (params->common.hist.no_header) 295 292 return; 296 293 297 294 get_duration(tool->start_time, duration, sizeof(duration)); 298 295 trace_seq_printf(s, "# RTLA timerlat histogram\n"); 299 296 trace_seq_printf(s, "# Time unit is %s (%s)\n", 300 - params->output_divisor == 1 ? "nanoseconds" : "microseconds", 301 - params->output_divisor == 1 ? "ns" : "us"); 297 + params->common.output_divisor == 1 ? "nanoseconds" : "microseconds", 298 + params->common.output_divisor == 1 ? "ns" : "us"); 302 299 303 300 trace_seq_printf(s, "# Duration: %s\n", duration); 304 301 305 - if (!params->no_index) 302 + if (!params->common.hist.no_index) 306 303 trace_seq_printf(s, "Index"); 307 304 308 305 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 309 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 306 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 310 307 continue; 311 308 312 309 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 313 310 continue; 314 311 315 - if (!params->no_irq) 312 + if (!params->common.hist.no_irq) 316 313 trace_seq_printf(s, " IRQ-%03d", cpu); 317 314 318 - if (!params->no_thread) 315 + if (!params->common.hist.no_thread) 319 316 trace_seq_printf(s, " Thr-%03d", cpu); 320 317 321 - if (params->user_data) 318 + if (params->common.user_data) 322 319 trace_seq_printf(s, " Usr-%03d", cpu); 323 320 } 324 321 trace_seq_printf(s, "\n"); ··· 353 350 { 354 351 int cpu; 355 352 356 - if (params->no_summary) 353 + if (params->common.hist.no_summary) 357 354 return; 358 355 359 - if (!params->no_index) 356 + if (!params->common.hist.no_index) 360 357 trace_seq_printf(trace->seq, "count:"); 361 358 362 359 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 363 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 360 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 364 361 continue; 365 362 366 363 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 367 364 continue; 368 365 369 - if (!params->no_irq) 366 + if (!params->common.hist.no_irq) 370 367 trace_seq_printf(trace->seq, "%9llu ", 371 368 data->hist[cpu].irq_count); 372 369 373 - if (!params->no_thread) 370 + if (!params->common.hist.no_thread) 374 371 trace_seq_printf(trace->seq, "%9llu ", 375 372 data->hist[cpu].thread_count); 376 373 377 - if (params->user_data) 374 + if (params->common.user_data) 378 375 trace_seq_printf(trace->seq, "%9llu ", 379 376 data->hist[cpu].user_count); 380 377 } 381 378 trace_seq_printf(trace->seq, "\n"); 382 379 383 - if (!params->no_index) 380 + if (!params->common.hist.no_index) 384 381 trace_seq_printf(trace->seq, "min: "); 385 382 386 383 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 387 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 384 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 388 385 continue; 389 386 390 387 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 391 388 continue; 392 389 393 - if (!params->no_irq) 390 + if (!params->common.hist.no_irq) 394 391 format_summary_value(trace->seq, 395 392 data->hist[cpu].irq_count, 396 393 data->hist[cpu].min_irq, 397 394 false); 398 395 399 - if (!params->no_thread) 396 + if (!params->common.hist.no_thread) 400 397 format_summary_value(trace->seq, 401 398 data->hist[cpu].thread_count, 402 399 data->hist[cpu].min_thread, 403 400 false); 404 401 405 - if (params->user_data) 402 + if (params->common.user_data) 406 403 format_summary_value(trace->seq, 407 404 data->hist[cpu].user_count, 408 405 data->hist[cpu].min_user, ··· 410 407 } 411 408 trace_seq_printf(trace->seq, "\n"); 412 409 413 - if (!params->no_index) 410 + if (!params->common.hist.no_index) 414 411 trace_seq_printf(trace->seq, "avg: "); 415 412 416 413 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 417 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 414 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 418 415 continue; 419 416 420 417 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 421 418 continue; 422 419 423 - if (!params->no_irq) 420 + if (!params->common.hist.no_irq) 424 421 format_summary_value(trace->seq, 425 422 data->hist[cpu].irq_count, 426 423 data->hist[cpu].sum_irq, 427 424 true); 428 425 429 - if (!params->no_thread) 426 + if (!params->common.hist.no_thread) 430 427 format_summary_value(trace->seq, 431 428 data->hist[cpu].thread_count, 432 429 data->hist[cpu].sum_thread, 433 430 true); 434 431 435 - if (params->user_data) 432 + if (params->common.user_data) 436 433 format_summary_value(trace->seq, 437 434 data->hist[cpu].user_count, 438 435 data->hist[cpu].sum_user, ··· 440 437 } 441 438 trace_seq_printf(trace->seq, "\n"); 442 439 443 - if (!params->no_index) 440 + if (!params->common.hist.no_index) 444 441 trace_seq_printf(trace->seq, "max: "); 445 442 446 443 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 447 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 444 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 448 445 continue; 449 446 450 447 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 451 448 continue; 452 449 453 - if (!params->no_irq) 450 + if (!params->common.hist.no_irq) 454 451 format_summary_value(trace->seq, 455 452 data->hist[cpu].irq_count, 456 453 data->hist[cpu].max_irq, 457 454 false); 458 455 459 - if (!params->no_thread) 456 + if (!params->common.hist.no_thread) 460 457 format_summary_value(trace->seq, 461 458 data->hist[cpu].thread_count, 462 459 data->hist[cpu].max_thread, 463 460 false); 464 461 465 - if (params->user_data) 462 + if (params->common.user_data) 466 463 format_summary_value(trace->seq, 467 464 data->hist[cpu].user_count, 468 465 data->hist[cpu].max_user, ··· 482 479 struct timerlat_hist_cpu sum; 483 480 int cpu; 484 481 485 - if (params->no_summary) 482 + if (params->common.hist.no_summary) 486 483 return; 487 484 488 485 memset(&sum, 0, sizeof(sum)); ··· 491 488 sum.min_user = ~0; 492 489 493 490 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 494 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 491 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 495 492 continue; 496 493 497 494 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) ··· 515 512 update_max(&sum.max_user, &cpu_data->max_user); 516 513 } 517 514 518 - if (!params->no_index) 515 + if (!params->common.hist.no_index) 519 516 trace_seq_printf(trace->seq, "ALL: "); 520 517 521 - if (!params->no_irq) 518 + if (!params->common.hist.no_irq) 522 519 trace_seq_printf(trace->seq, " IRQ"); 523 520 524 - if (!params->no_thread) 521 + if (!params->common.hist.no_thread) 525 522 trace_seq_printf(trace->seq, " Thr"); 526 523 527 - if (params->user_data) 524 + if (params->common.user_data) 528 525 trace_seq_printf(trace->seq, " Usr"); 529 526 530 527 trace_seq_printf(trace->seq, "\n"); 531 528 532 - if (!params->no_index) 529 + if (!params->common.hist.no_index) 533 530 trace_seq_printf(trace->seq, "count:"); 534 531 535 - if (!params->no_irq) 532 + if (!params->common.hist.no_irq) 536 533 trace_seq_printf(trace->seq, "%9llu ", 537 534 sum.irq_count); 538 535 539 - if (!params->no_thread) 536 + if (!params->common.hist.no_thread) 540 537 trace_seq_printf(trace->seq, "%9llu ", 541 538 sum.thread_count); 542 539 543 - if (params->user_data) 540 + if (params->common.user_data) 544 541 trace_seq_printf(trace->seq, "%9llu ", 545 542 sum.user_count); 546 543 547 544 trace_seq_printf(trace->seq, "\n"); 548 545 549 - if (!params->no_index) 546 + if (!params->common.hist.no_index) 550 547 trace_seq_printf(trace->seq, "min: "); 551 548 552 - if (!params->no_irq) 549 + if (!params->common.hist.no_irq) 553 550 format_summary_value(trace->seq, 554 551 sum.irq_count, 555 552 sum.min_irq, 556 553 false); 557 554 558 - if (!params->no_thread) 555 + if (!params->common.hist.no_thread) 559 556 format_summary_value(trace->seq, 560 557 sum.thread_count, 561 558 sum.min_thread, 562 559 false); 563 560 564 - if (params->user_data) 561 + if (params->common.user_data) 565 562 format_summary_value(trace->seq, 566 563 sum.user_count, 567 564 sum.min_user, ··· 569 566 570 567 trace_seq_printf(trace->seq, "\n"); 571 568 572 - if (!params->no_index) 569 + if (!params->common.hist.no_index) 573 570 trace_seq_printf(trace->seq, "avg: "); 574 571 575 - if (!params->no_irq) 572 + if (!params->common.hist.no_irq) 576 573 format_summary_value(trace->seq, 577 574 sum.irq_count, 578 575 sum.sum_irq, 579 576 true); 580 577 581 - if (!params->no_thread) 578 + if (!params->common.hist.no_thread) 582 579 format_summary_value(trace->seq, 583 580 sum.thread_count, 584 581 sum.sum_thread, 585 582 true); 586 583 587 - if (params->user_data) 584 + if (params->common.user_data) 588 585 format_summary_value(trace->seq, 589 586 sum.user_count, 590 587 sum.sum_user, ··· 592 589 593 590 trace_seq_printf(trace->seq, "\n"); 594 591 595 - if (!params->no_index) 592 + if (!params->common.hist.no_index) 596 593 trace_seq_printf(trace->seq, "max: "); 597 594 598 - if (!params->no_irq) 595 + if (!params->common.hist.no_irq) 599 596 format_summary_value(trace->seq, 600 597 sum.irq_count, 601 598 sum.max_irq, 602 599 false); 603 600 604 - if (!params->no_thread) 601 + if (!params->common.hist.no_thread) 605 602 format_summary_value(trace->seq, 606 603 sum.thread_count, 607 604 sum.max_thread, 608 605 false); 609 606 610 - if (params->user_data) 607 + if (params->common.user_data) 611 608 format_summary_value(trace->seq, 612 609 sum.user_count, 613 610 sum.max_user, ··· 622 619 * timerlat_print_stats - print data for each CPUs 623 620 */ 624 621 static void 625 - timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) 622 + timerlat_print_stats(struct osnoise_tool *tool) 626 623 { 624 + struct timerlat_params *params = to_timerlat_params(tool->params); 627 625 struct timerlat_hist_data *data = tool->data; 628 626 struct trace_instance *trace = &tool->trace; 629 627 int bucket, cpu; ··· 635 631 for (bucket = 0; bucket < data->entries; bucket++) { 636 632 total = 0; 637 633 638 - if (!params->no_index) 634 + if (!params->common.hist.no_index) 639 635 trace_seq_printf(trace->seq, "%-6d", 640 636 bucket * data->bucket_size); 641 637 642 638 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 643 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 639 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 644 640 continue; 645 641 646 642 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 647 643 continue; 648 644 649 - if (!params->no_irq) { 645 + if (!params->common.hist.no_irq) { 650 646 total += data->hist[cpu].irq[bucket]; 651 647 trace_seq_printf(trace->seq, "%9d ", 652 648 data->hist[cpu].irq[bucket]); 653 649 } 654 650 655 - if (!params->no_thread) { 651 + if (!params->common.hist.no_thread) { 656 652 total += data->hist[cpu].thread[bucket]; 657 653 trace_seq_printf(trace->seq, "%9d ", 658 654 data->hist[cpu].thread[bucket]); 659 655 } 660 656 661 - if (params->user_data) { 657 + if (params->common.user_data) { 662 658 total += data->hist[cpu].user[bucket]; 663 659 trace_seq_printf(trace->seq, "%9d ", 664 660 data->hist[cpu].user[bucket]); ··· 666 662 667 663 } 668 664 669 - if (total == 0 && !params->with_zeros) { 665 + if (total == 0 && !params->common.hist.with_zeros) { 670 666 trace_seq_reset(trace->seq); 671 667 continue; 672 668 } ··· 676 672 trace_seq_reset(trace->seq); 677 673 } 678 674 679 - if (!params->no_index) 675 + if (!params->common.hist.no_index) 680 676 trace_seq_printf(trace->seq, "over: "); 681 677 682 678 for (cpu = 0; cpu < data->nr_cpus; cpu++) { 683 - if (params->cpus && !CPU_ISSET(cpu, &params->monitored_cpus)) 679 + if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus)) 684 680 continue; 685 681 686 682 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 687 683 continue; 688 684 689 - if (!params->no_irq) 685 + if (!params->common.hist.no_irq) 690 686 trace_seq_printf(trace->seq, "%9d ", 691 687 data->hist[cpu].irq[data->entries]); 692 688 693 - if (!params->no_thread) 689 + if (!params->common.hist.no_thread) 694 690 trace_seq_printf(trace->seq, "%9d ", 695 691 data->hist[cpu].thread[data->entries]); 696 692 697 - if (params->user_data) 693 + if (params->common.user_data) 698 694 trace_seq_printf(trace->seq, "%9d ", 699 695 data->hist[cpu].user[data->entries]); 700 696 } ··· 784 780 /* 785 781 * timerlat_hist_parse_args - allocs, parse and fill the cmd line parameters 786 782 */ 787 - static struct timerlat_params 783 + static struct common_params 788 784 *timerlat_hist_parse_args(int argc, char *argv[]) 789 785 { 790 786 struct timerlat_params *params; ··· 798 794 if (!params) 799 795 exit(1); 800 796 801 - actions_init(&params->threshold_actions); 802 - actions_init(&params->end_actions); 797 + actions_init(&params->common.threshold_actions); 798 + actions_init(&params->common.end_actions); 803 799 804 800 /* disabled by default */ 805 801 params->dma_latency = -1; ··· 808 804 params->deepest_idle_state = -2; 809 805 810 806 /* display data in microseconds */ 811 - params->output_divisor = 1000; 812 - params->bucket_size = 1; 813 - params->entries = 256; 807 + params->common.output_divisor = 1000; 808 + params->common.hist.bucket_size = 1; 809 + params->common.hist.entries = 256; 814 810 815 811 /* default to BPF mode */ 816 812 params->mode = TRACING_MODE_BPF; ··· 871 867 auto_thresh = get_llong_from_str(optarg); 872 868 873 869 /* set thread stop to auto_thresh */ 874 - params->stop_total_us = auto_thresh; 875 - params->stop_us = auto_thresh; 870 + params->common.stop_total_us = auto_thresh; 871 + params->common.stop_us = auto_thresh; 876 872 877 873 /* get stack trace */ 878 874 params->print_stack = auto_thresh; ··· 882 878 883 879 break; 884 880 case 'c': 885 - retval = parse_cpu_set(optarg, &params->monitored_cpus); 881 + retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 886 882 if (retval) 887 883 timerlat_hist_usage("\nInvalid -c cpu list\n"); 888 - params->cpus = optarg; 884 + params->common.cpus = optarg; 889 885 break; 890 886 case 'C': 891 - params->cgroup = 1; 887 + params->common.cgroup = 1; 892 888 if (!optarg) { 893 889 /* will inherit this cgroup */ 894 - params->cgroup_name = NULL; 890 + params->common.cgroup_name = NULL; 895 891 } else if (*optarg == '=') { 896 892 /* skip the = */ 897 - params->cgroup_name = ++optarg; 893 + params->common.cgroup_name = ++optarg; 898 894 } 899 895 break; 900 896 case 'b': 901 - params->bucket_size = get_llong_from_str(optarg); 902 - if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) 897 + params->common.hist.bucket_size = get_llong_from_str(optarg); 898 + if (params->common.hist.bucket_size == 0 || 899 + params->common.hist.bucket_size >= 1000000) 903 900 timerlat_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); 904 901 break; 905 902 case 'D': 906 903 config_debug = 1; 907 904 break; 908 905 case 'd': 909 - params->duration = parse_seconds_duration(optarg); 910 - if (!params->duration) 906 + params->common.duration = parse_seconds_duration(optarg); 907 + if (!params->common.duration) 911 908 timerlat_hist_usage("Invalid -D duration\n"); 912 909 break; 913 910 case 'e': ··· 918 913 exit(EXIT_FAILURE); 919 914 } 920 915 921 - if (params->events) 922 - tevent->next = params->events; 916 + if (params->common.events) 917 + tevent->next = params->common.events; 923 918 924 - params->events = tevent; 919 + params->common.events = tevent; 925 920 break; 926 921 case 'E': 927 - params->entries = get_llong_from_str(optarg); 928 - if ((params->entries < 10) || (params->entries > 9999999)) 929 - timerlat_hist_usage("Entries must be > 10 and < 9999999\n"); 922 + params->common.hist.entries = get_llong_from_str(optarg); 923 + if (params->common.hist.entries < 10 || 924 + params->common.hist.entries > 9999999) 925 + timerlat_hist_usage("Entries must be > 10 and < 9999999\n"); 930 926 break; 931 927 case 'h': 932 928 case '?': 933 929 timerlat_hist_usage(NULL); 934 930 break; 935 931 case 'H': 936 - params->hk_cpus = 1; 937 - retval = parse_cpu_set(optarg, &params->hk_cpu_set); 932 + params->common.hk_cpus = 1; 933 + retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 938 934 if (retval) { 939 935 err_msg("Error parsing house keeping CPUs\n"); 940 936 exit(EXIT_FAILURE); 941 937 } 942 938 break; 943 939 case 'i': 944 - params->stop_us = get_llong_from_str(optarg); 940 + params->common.stop_us = get_llong_from_str(optarg); 945 941 break; 946 942 case 'k': 947 - params->kernel_workload = 1; 943 + params->common.kernel_workload = 1; 948 944 break; 949 945 case 'n': 950 - params->output_divisor = 1; 946 + params->common.output_divisor = 1; 951 947 break; 952 948 case 'p': 953 949 params->timerlat_period_us = get_llong_from_str(optarg); ··· 956 950 timerlat_hist_usage("Period longer than 1 s\n"); 957 951 break; 958 952 case 'P': 959 - retval = parse_prio(optarg, &params->sched_param); 953 + retval = parse_prio(optarg, &params->common.sched_param); 960 954 if (retval == -1) 961 955 timerlat_hist_usage("Invalid -P priority"); 962 - params->set_sched = 1; 956 + params->common.set_sched = 1; 963 957 break; 964 958 case 's': 965 959 params->print_stack = get_llong_from_str(optarg); 966 960 break; 967 961 case 'T': 968 - params->stop_total_us = get_llong_from_str(optarg); 962 + params->common.stop_total_us = get_llong_from_str(optarg); 969 963 break; 970 964 case 't': 971 965 if (optarg) { ··· 979 973 trace_output = "timerlat_trace.txt"; 980 974 break; 981 975 case 'u': 982 - params->user_workload = 1; 976 + params->common.user_workload = 1; 983 977 /* fallback: -u implies in -U */ 984 978 case 'U': 985 - params->user_data = 1; 979 + params->common.user_data = 1; 986 980 break; 987 981 case '0': /* no irq */ 988 - params->no_irq = 1; 982 + params->common.hist.no_irq = 1; 989 983 break; 990 984 case '1': /* no thread */ 991 - params->no_thread = 1; 985 + params->common.hist.no_thread = 1; 992 986 break; 993 987 case '2': /* no header */ 994 - params->no_header = 1; 988 + params->common.hist.no_header = 1; 995 989 break; 996 990 case '3': /* no summary */ 997 - params->no_summary = 1; 991 + params->common.hist.no_summary = 1; 998 992 break; 999 993 case '4': /* no index */ 1000 - params->no_index = 1; 994 + params->common.hist.no_index = 1; 1001 995 break; 1002 996 case '5': /* with zeros */ 1003 - params->with_zeros = 1; 997 + params->common.hist.with_zeros = 1; 1004 998 break; 1005 999 case '6': /* trigger */ 1006 - if (params->events) { 1007 - retval = trace_event_add_trigger(params->events, optarg); 1000 + if (params->common.events) { 1001 + retval = trace_event_add_trigger(params->common.events, optarg); 1008 1002 if (retval) { 1009 1003 err_msg("Error adding trigger %s\n", optarg); 1010 1004 exit(EXIT_FAILURE); ··· 1014 1008 } 1015 1009 break; 1016 1010 case '7': /* filter */ 1017 - if (params->events) { 1018 - retval = trace_event_add_filter(params->events, optarg); 1011 + if (params->common.events) { 1012 + retval = trace_event_add_filter(params->common.events, optarg); 1019 1013 if (retval) { 1020 1014 err_msg("Error adding filter %s\n", optarg); 1021 1015 exit(EXIT_FAILURE); ··· 1038 1032 params->dump_tasks = 1; 1039 1033 break; 1040 1034 case '\2': 1041 - params->warmup = get_llong_from_str(optarg); 1035 + params->common.warmup = get_llong_from_str(optarg); 1042 1036 break; 1043 1037 case '\3': 1044 - params->buffer_size = get_llong_from_str(optarg); 1038 + params->common.buffer_size = get_llong_from_str(optarg); 1045 1039 break; 1046 1040 case '\4': 1047 1041 params->deepest_idle_state = get_llong_from_str(optarg); 1048 1042 break; 1049 1043 case '\5': 1050 - retval = actions_parse(&params->threshold_actions, optarg); 1044 + retval = actions_parse(&params->common.threshold_actions, optarg, 1045 + "timerlat_trace.txt"); 1051 1046 if (retval) { 1052 1047 err_msg("Invalid action %s\n", optarg); 1053 1048 exit(EXIT_FAILURE); 1054 1049 } 1055 1050 break; 1056 1051 case '\6': 1057 - retval = actions_parse(&params->end_actions, optarg); 1052 + retval = actions_parse(&params->common.end_actions, optarg, 1053 + "timerlat_trace.txt"); 1058 1054 if (retval) { 1059 1055 err_msg("Invalid action %s\n", optarg); 1060 1056 exit(EXIT_FAILURE); ··· 1068 1060 } 1069 1061 1070 1062 if (trace_output) 1071 - actions_add_trace_output(&params->threshold_actions, trace_output); 1063 + actions_add_trace_output(&params->common.threshold_actions, trace_output); 1072 1064 1073 1065 if (geteuid()) { 1074 1066 err_msg("rtla needs root permission\n"); 1075 1067 exit(EXIT_FAILURE); 1076 1068 } 1077 1069 1078 - if (params->no_irq && params->no_thread) 1070 + if (params->common.hist.no_irq && params->common.hist.no_thread) 1079 1071 timerlat_hist_usage("no-irq and no-thread set, there is nothing to do here"); 1080 1072 1081 - if (params->no_index && !params->with_zeros) 1073 + if (params->common.hist.no_index && !params->common.hist.with_zeros) 1082 1074 timerlat_hist_usage("no-index set with with-zeros is not set - it does not make sense"); 1083 1075 1084 1076 /* 1085 1077 * Auto analysis only happens if stop tracing, thus: 1086 1078 */ 1087 - if (!params->stop_us && !params->stop_total_us) 1079 + if (!params->common.stop_us && !params->common.stop_total_us) 1088 1080 params->no_aa = 1; 1089 1081 1090 - if (params->kernel_workload && params->user_workload) 1082 + if (params->common.kernel_workload && params->common.user_workload) 1091 1083 timerlat_hist_usage("--kernel-threads and --user-threads are mutually exclusive!"); 1092 1084 1093 1085 /* ··· 1095 1087 * mixed mode 1096 1088 */ 1097 1089 if (params->mode == TRACING_MODE_BPF && 1098 - (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || 1099 - params->end_actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa)) 1090 + (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || 1091 + params->common.end_actions.present[ACTION_TRACE_OUTPUT] || 1092 + !params->no_aa)) 1100 1093 params->mode = TRACING_MODE_MIXED; 1101 1094 1102 - return params; 1095 + return &params->common; 1103 1096 } 1104 1097 1105 1098 /* 1106 1099 * timerlat_hist_apply_config - apply the hist configs to the initialized tool 1107 1100 */ 1108 1101 static int 1109 - timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) 1102 + timerlat_hist_apply_config(struct osnoise_tool *tool) 1110 1103 { 1104 + struct timerlat_params *params = to_timerlat_params(tool->params); 1111 1105 int retval; 1112 1106 1113 1107 retval = timerlat_apply_config(tool, params); ··· 1126 1116 * timerlat_init_hist - initialize a timerlat hist tool with parameters 1127 1117 */ 1128 1118 static struct osnoise_tool 1129 - *timerlat_init_hist(struct timerlat_params *params) 1119 + *timerlat_init_hist(struct common_params *params) 1130 1120 { 1131 1121 struct osnoise_tool *tool; 1132 1122 int nr_cpus; ··· 1137 1127 if (!tool) 1138 1128 return NULL; 1139 1129 1140 - tool->data = timerlat_alloc_histogram(nr_cpus, params->entries, params->bucket_size); 1130 + tool->data = timerlat_alloc_histogram(nr_cpus, params->hist.entries, 1131 + params->hist.bucket_size); 1141 1132 if (!tool->data) 1142 1133 goto out_err; 1143 - 1144 - tool->params = params; 1145 1134 1146 1135 tep_register_event_handler(tool->trace.tep, -1, "ftrace", "timerlat", 1147 1136 timerlat_hist_handler, tool); ··· 1152 1143 return NULL; 1153 1144 } 1154 1145 1155 - static int stop_tracing; 1156 - static struct trace_instance *hist_inst = NULL; 1157 - static void stop_hist(int sig) 1146 + static int timerlat_hist_bpf_main_loop(struct osnoise_tool *tool) 1158 1147 { 1159 - if (stop_tracing) { 1160 - /* 1161 - * Stop requested twice in a row; abort event processing and 1162 - * exit immediately 1163 - */ 1164 - tracefs_iterate_stop(hist_inst->inst); 1165 - return; 1166 - } 1167 - stop_tracing = 1; 1168 - if (hist_inst) 1169 - trace_instance_stop(hist_inst); 1170 - } 1171 - 1172 - /* 1173 - * timerlat_hist_set_signals - handles the signal to stop the tool 1174 - */ 1175 - static void 1176 - timerlat_hist_set_signals(struct timerlat_params *params) 1177 - { 1178 - signal(SIGINT, stop_hist); 1179 - if (params->duration) { 1180 - signal(SIGALRM, stop_hist); 1181 - alarm(params->duration); 1182 - } 1183 - } 1184 - 1185 - int timerlat_hist_main(int argc, char *argv[]) 1186 - { 1187 - struct timerlat_params *params; 1188 - struct osnoise_tool *record = NULL; 1189 - struct timerlat_u_params params_u; 1190 - enum result return_value = ERROR; 1191 - struct osnoise_tool *tool = NULL; 1192 - struct osnoise_tool *aa = NULL; 1193 - struct trace_instance *trace; 1194 - int dma_latency_fd = -1; 1195 - pthread_t timerlat_u; 1148 + struct timerlat_params *params = to_timerlat_params(tool->params); 1196 1149 int retval; 1197 - int nr_cpus, i; 1198 1150 1199 - params = timerlat_hist_parse_args(argc, argv); 1200 - if (!params) 1201 - exit(1); 1151 + while (!stop_tracing) { 1152 + timerlat_bpf_wait(-1); 1202 1153 1203 - tool = timerlat_init_hist(params); 1204 - if (!tool) { 1205 - err_msg("Could not init osnoise hist\n"); 1206 - goto out_exit; 1207 - } 1154 + if (!stop_tracing) { 1155 + /* Threshold overflow, perform actions on threshold */ 1156 + actions_perform(&params->common.threshold_actions); 1208 1157 1209 - trace = &tool->trace; 1210 - /* 1211 - * Save trace instance into global variable so that SIGINT can stop 1212 - * the timerlat tracer. 1213 - * Otherwise, rtla could loop indefinitely when overloaded. 1214 - */ 1215 - hist_inst = trace; 1158 + if (!params->common.threshold_actions.continue_flag) 1159 + /* continue flag not set, break */ 1160 + break; 1216 1161 1217 - /* 1218 - * Try to enable BPF, unless disabled explicitly. 1219 - * If BPF enablement fails, fall back to tracefs mode. 1220 - */ 1221 - if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { 1222 - debug_msg("RTLA_NO_BPF set, disabling BPF\n"); 1223 - params->mode = TRACING_MODE_TRACEFS; 1224 - } else if (!tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { 1225 - debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); 1226 - params->mode = TRACING_MODE_TRACEFS; 1227 - } else { 1228 - retval = timerlat_bpf_init(params); 1229 - if (retval) { 1230 - debug_msg("Could not enable BPF\n"); 1231 - params->mode = TRACING_MODE_TRACEFS; 1162 + /* continue action reached, re-enable tracing */ 1163 + if (tool->record) 1164 + trace_instance_start(&tool->record->trace); 1165 + if (tool->aa) 1166 + trace_instance_start(&tool->aa->trace); 1167 + timerlat_bpf_restart_tracing(); 1232 1168 } 1233 1169 } 1170 + timerlat_bpf_detach(); 1234 1171 1235 - retval = timerlat_hist_apply_config(tool, params); 1236 - if (retval) { 1237 - err_msg("Could not apply config\n"); 1238 - goto out_free; 1239 - } 1172 + retval = timerlat_hist_bpf_pull_data(tool); 1173 + if (retval) 1174 + err_msg("Error pulling BPF data\n"); 1240 1175 1241 - retval = enable_timerlat(trace); 1242 - if (retval) { 1243 - err_msg("Failed to enable timerlat tracer\n"); 1244 - goto out_free; 1245 - } 1246 - 1247 - if (params->set_sched) { 1248 - retval = set_comm_sched_attr("timerlat/", &params->sched_param); 1249 - if (retval) { 1250 - err_msg("Failed to set sched parameters\n"); 1251 - goto out_free; 1252 - } 1253 - } 1254 - 1255 - if (params->cgroup && !params->user_workload) { 1256 - retval = set_comm_cgroup("timerlat/", params->cgroup_name); 1257 - if (!retval) { 1258 - err_msg("Failed to move threads to cgroup\n"); 1259 - goto out_free; 1260 - } 1261 - } 1262 - 1263 - if (params->dma_latency >= 0) { 1264 - dma_latency_fd = set_cpu_dma_latency(params->dma_latency); 1265 - if (dma_latency_fd < 0) { 1266 - err_msg("Could not set /dev/cpu_dma_latency.\n"); 1267 - goto out_free; 1268 - } 1269 - } 1270 - 1271 - if (params->deepest_idle_state >= -1) { 1272 - if (!have_libcpupower_support()) { 1273 - err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n"); 1274 - goto out_free; 1275 - } 1276 - 1277 - nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 1278 - 1279 - for (i = 0; i < nr_cpus; i++) { 1280 - if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus)) 1281 - continue; 1282 - if (save_cpu_idle_disable_state(i) < 0) { 1283 - err_msg("Could not save cpu idle state.\n"); 1284 - goto out_free; 1285 - } 1286 - if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) { 1287 - err_msg("Could not set deepest cpu idle state.\n"); 1288 - goto out_free; 1289 - } 1290 - } 1291 - } 1292 - 1293 - if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || 1294 - params->end_actions.present[ACTION_TRACE_OUTPUT]) { 1295 - record = osnoise_init_trace_tool("timerlat"); 1296 - if (!record) { 1297 - err_msg("Failed to enable the trace instance\n"); 1298 - goto out_free; 1299 - } 1300 - params->threshold_actions.trace_output_inst = record->trace.inst; 1301 - params->end_actions.trace_output_inst = record->trace.inst; 1302 - 1303 - if (params->events) { 1304 - retval = trace_events_enable(&record->trace, params->events); 1305 - if (retval) 1306 - goto out_hist; 1307 - } 1308 - 1309 - if (params->buffer_size > 0) { 1310 - retval = trace_set_buffer_size(&record->trace, params->buffer_size); 1311 - if (retval) 1312 - goto out_hist; 1313 - } 1314 - } 1315 - 1316 - if (!params->no_aa) { 1317 - aa = osnoise_init_tool("timerlat_aa"); 1318 - if (!aa) 1319 - goto out_hist; 1320 - 1321 - retval = timerlat_aa_init(aa, params->dump_tasks); 1322 - if (retval) { 1323 - err_msg("Failed to enable the auto analysis instance\n"); 1324 - goto out_hist; 1325 - } 1326 - 1327 - retval = enable_timerlat(&aa->trace); 1328 - if (retval) { 1329 - err_msg("Failed to enable timerlat tracer\n"); 1330 - goto out_hist; 1331 - } 1332 - } 1333 - 1334 - if (params->user_workload) { 1335 - /* rtla asked to stop */ 1336 - params_u.should_run = 1; 1337 - /* all threads left */ 1338 - params_u.stopped_running = 0; 1339 - 1340 - params_u.set = &params->monitored_cpus; 1341 - if (params->set_sched) 1342 - params_u.sched_param = &params->sched_param; 1343 - else 1344 - params_u.sched_param = NULL; 1345 - 1346 - params_u.cgroup_name = params->cgroup_name; 1347 - 1348 - retval = pthread_create(&timerlat_u, NULL, timerlat_u_dispatcher, &params_u); 1349 - if (retval) 1350 - err_msg("Error creating timerlat user-space threads\n"); 1351 - } 1352 - 1353 - if (params->warmup > 0) { 1354 - debug_msg("Warming up for %d seconds\n", params->warmup); 1355 - sleep(params->warmup); 1356 - if (stop_tracing) 1357 - goto out_hist; 1358 - } 1359 - 1360 - /* 1361 - * Start the tracers here, after having set all instances. 1362 - * 1363 - * Let the trace instance start first for the case of hitting a stop 1364 - * tracing while enabling other instances. The trace instance is the 1365 - * one with most valuable information. 1366 - */ 1367 - if (record) 1368 - trace_instance_start(&record->trace); 1369 - if (!params->no_aa) 1370 - trace_instance_start(&aa->trace); 1371 - if (params->mode == TRACING_MODE_TRACEFS) { 1372 - trace_instance_start(trace); 1373 - } else { 1374 - retval = timerlat_bpf_attach(); 1375 - if (retval) { 1376 - err_msg("Error attaching BPF program\n"); 1377 - goto out_hist; 1378 - } 1379 - } 1380 - 1381 - tool->start_time = time(NULL); 1382 - timerlat_hist_set_signals(params); 1383 - 1384 - if (params->mode == TRACING_MODE_TRACEFS) { 1385 - while (!stop_tracing) { 1386 - sleep(params->sleep_time); 1387 - 1388 - retval = tracefs_iterate_raw_events(trace->tep, 1389 - trace->inst, 1390 - NULL, 1391 - 0, 1392 - collect_registered_events, 1393 - trace); 1394 - if (retval < 0) { 1395 - err_msg("Error iterating on events\n"); 1396 - goto out_hist; 1397 - } 1398 - 1399 - if (osnoise_trace_is_off(tool, record)) { 1400 - actions_perform(&params->threshold_actions); 1401 - 1402 - if (!params->threshold_actions.continue_flag) 1403 - /* continue flag not set, break */ 1404 - break; 1405 - 1406 - /* continue action reached, re-enable tracing */ 1407 - if (record) 1408 - trace_instance_start(&record->trace); 1409 - if (!params->no_aa) 1410 - trace_instance_start(&aa->trace); 1411 - trace_instance_start(trace); 1412 - } 1413 - 1414 - /* is there still any user-threads ? */ 1415 - if (params->user_workload) { 1416 - if (params_u.stopped_running) { 1417 - debug_msg("timerlat user-space threads stopped!\n"); 1418 - break; 1419 - } 1420 - } 1421 - } 1422 - } else { 1423 - while (!stop_tracing) { 1424 - timerlat_bpf_wait(-1); 1425 - 1426 - if (!stop_tracing) { 1427 - /* Threshold overflow, perform actions on threshold */ 1428 - actions_perform(&params->threshold_actions); 1429 - 1430 - if (!params->threshold_actions.continue_flag) 1431 - /* continue flag not set, break */ 1432 - break; 1433 - 1434 - /* continue action reached, re-enable tracing */ 1435 - if (record) 1436 - trace_instance_start(&record->trace); 1437 - if (!params->no_aa) 1438 - trace_instance_start(&aa->trace); 1439 - timerlat_bpf_restart_tracing(); 1440 - } 1441 - } 1442 - } 1443 - 1444 - if (params->mode != TRACING_MODE_TRACEFS) { 1445 - timerlat_bpf_detach(); 1446 - retval = timerlat_hist_bpf_pull_data(tool); 1447 - if (retval) { 1448 - err_msg("Error pulling BPF data\n"); 1449 - goto out_hist; 1450 - } 1451 - } 1452 - 1453 - if (params->user_workload && !params_u.stopped_running) { 1454 - params_u.should_run = 0; 1455 - sleep(1); 1456 - } 1457 - 1458 - timerlat_print_stats(params, tool); 1459 - 1460 - actions_perform(&params->end_actions); 1461 - 1462 - return_value = PASSED; 1463 - 1464 - if (osnoise_trace_is_off(tool, record) && !stop_tracing) { 1465 - printf("rtla timerlat hit stop tracing\n"); 1466 - 1467 - if (!params->no_aa) 1468 - timerlat_auto_analysis(params->stop_us, params->stop_total_us); 1469 - 1470 - return_value = FAILED; 1471 - } 1472 - 1473 - out_hist: 1474 - timerlat_aa_destroy(); 1475 - if (dma_latency_fd >= 0) 1476 - close(dma_latency_fd); 1477 - if (params->deepest_idle_state >= -1) { 1478 - for (i = 0; i < nr_cpus; i++) { 1479 - if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus)) 1480 - continue; 1481 - restore_cpu_idle_disable_state(i); 1482 - } 1483 - } 1484 - trace_events_destroy(&record->trace, params->events); 1485 - params->events = NULL; 1486 - out_free: 1487 - timerlat_free_histogram(tool->data); 1488 - osnoise_destroy_tool(aa); 1489 - osnoise_destroy_tool(record); 1490 - osnoise_destroy_tool(tool); 1491 - actions_destroy(&params->threshold_actions); 1492 - actions_destroy(&params->end_actions); 1493 - if (params->mode != TRACING_MODE_TRACEFS) 1494 - timerlat_bpf_destroy(); 1495 - free(params); 1496 - free_cpu_idle_disable_states(); 1497 - out_exit: 1498 - exit(return_value); 1176 + return retval; 1499 1177 } 1178 + 1179 + static int timerlat_hist_main(struct osnoise_tool *tool) 1180 + { 1181 + struct timerlat_params *params = to_timerlat_params(tool->params); 1182 + int retval; 1183 + 1184 + if (params->mode == TRACING_MODE_TRACEFS) 1185 + retval = hist_main_loop(tool); 1186 + else 1187 + retval = timerlat_hist_bpf_main_loop(tool); 1188 + 1189 + return retval; 1190 + } 1191 + 1192 + struct tool_ops timerlat_hist_ops = { 1193 + .tracer = "timerlat", 1194 + .comm_prefix = "timerlat/", 1195 + .parse_args = timerlat_hist_parse_args, 1196 + .init_tool = timerlat_init_hist, 1197 + .apply_config = timerlat_hist_apply_config, 1198 + .enable = timerlat_enable, 1199 + .main = timerlat_hist_main, 1200 + .print_stats = timerlat_print_stats, 1201 + .analyze = timerlat_analyze, 1202 + .free = timerlat_free_histogram_tool, 1203 + };
+119 -449
tools/tracing/rtla/src/timerlat_top.c
··· 17 17 18 18 #include "timerlat.h" 19 19 #include "timerlat_aa.h" 20 - #include "timerlat_u.h" 21 20 #include "timerlat_bpf.h" 22 21 23 22 struct timerlat_top_cpu { ··· 48 49 /* 49 50 * timerlat_free_top - free runtime data 50 51 */ 51 - static void 52 - timerlat_free_top(struct timerlat_top_data *data) 52 + static void timerlat_free_top(struct timerlat_top_data *data) 53 53 { 54 54 free(data->cpu_data); 55 55 free(data); 56 + } 57 + 58 + static void timerlat_free_top_tool(struct osnoise_tool *tool) 59 + { 60 + timerlat_free_top(tool->data); 61 + timerlat_free(tool); 56 62 } 57 63 58 64 /* ··· 132 128 unsigned long long thread, 133 129 unsigned long long latency) 134 130 { 135 - struct timerlat_params *params = tool->params; 131 + struct timerlat_params *params = to_timerlat_params(tool->params); 136 132 struct timerlat_top_data *data = tool->data; 137 133 struct timerlat_top_cpu *cpu_data = &data->cpu_data[cpu]; 138 134 139 - if (params->output_divisor) 140 - latency = latency / params->output_divisor; 135 + if (params->common.output_divisor) 136 + latency = latency / params->common.output_divisor; 141 137 142 138 if (!thread) { 143 139 cpu_data->irq_count++; ··· 168 164 struct tep_event *event, void *context) 169 165 { 170 166 struct trace_instance *trace = context; 171 - struct timerlat_params *params; 172 167 unsigned long long latency, thread; 173 168 struct osnoise_tool *top; 174 169 int cpu = record->cpu; 175 170 176 171 top = container_of(trace, struct osnoise_tool, trace); 177 - params = top->params; 178 172 179 - if (!params->aa_only) { 173 + if (!top->params->aa_only) { 180 174 tep_get_field_val(s, event, "context", record, &thread, 1); 181 175 tep_get_field_val(s, event, "timer_latency", record, &latency, 1); 182 176 ··· 260 258 static void timerlat_top_header(struct timerlat_params *params, struct osnoise_tool *top) 261 259 { 262 260 struct trace_seq *s = top->trace.seq; 261 + bool pretty = params->common.pretty_output; 263 262 char duration[26]; 264 263 265 264 get_duration(top->start_time, duration, sizeof(duration)); 266 265 267 - if (params->pretty_output) 266 + if (pretty) 268 267 trace_seq_printf(s, "\033[2;37;40m"); 269 268 270 269 trace_seq_printf(s, " Timer Latency "); 271 - if (params->user_data) 270 + if (params->common.user_data) 272 271 trace_seq_printf(s, " "); 273 272 274 - if (params->pretty_output) 273 + if (pretty) 275 274 trace_seq_printf(s, "\033[0;0;0m"); 276 275 trace_seq_printf(s, "\n"); 277 276 278 277 trace_seq_printf(s, "%-6s | IRQ Timer Latency (%s) | Thread Timer Latency (%s)", duration, 279 - params->output_divisor == 1 ? "ns" : "us", 280 - params->output_divisor == 1 ? "ns" : "us"); 278 + params->common.output_divisor == 1 ? "ns" : "us", 279 + params->common.output_divisor == 1 ? "ns" : "us"); 281 280 282 - if (params->user_data) { 281 + if (params->common.user_data) { 283 282 trace_seq_printf(s, " | Ret user Timer Latency (%s)", 284 - params->output_divisor == 1 ? "ns" : "us"); 283 + params->common.output_divisor == 1 ? "ns" : "us"); 285 284 } 286 285 287 286 trace_seq_printf(s, "\n"); 288 - if (params->pretty_output) 287 + if (pretty) 289 288 trace_seq_printf(s, "\033[2;30;47m"); 290 289 291 290 trace_seq_printf(s, "CPU COUNT | cur min avg max | cur min avg max"); 292 - if (params->user_data) 291 + if (params->common.user_data) 293 292 trace_seq_printf(s, " | cur min avg max"); 294 293 295 - if (params->pretty_output) 294 + if (pretty) 296 295 trace_seq_printf(s, "\033[0;0;0m"); 297 296 trace_seq_printf(s, "\n"); 298 297 } ··· 305 302 */ 306 303 static void timerlat_top_print(struct osnoise_tool *top, int cpu) 307 304 { 308 - 309 - struct timerlat_params *params = top->params; 305 + struct timerlat_params *params = to_timerlat_params(top->params); 310 306 struct timerlat_top_data *data = top->data; 311 307 struct timerlat_top_cpu *cpu_data = &data->cpu_data[cpu]; 312 308 struct trace_seq *s = top->trace.seq; ··· 340 338 trace_seq_printf(s, "%9llu", cpu_data->max_thread); 341 339 } 342 340 343 - if (!params->user_data) { 341 + if (!params->common.user_data) { 344 342 trace_seq_printf(s, "\n"); 345 343 return; 346 344 } ··· 365 363 timerlat_top_print_sum(struct osnoise_tool *top, struct timerlat_top_cpu *summary) 366 364 { 367 365 const char *split = "----------------------------------------"; 368 - struct timerlat_params *params = top->params; 366 + struct timerlat_params *params = to_timerlat_params(top->params); 369 367 unsigned long long count = summary->irq_count; 370 368 struct trace_seq *s = top->trace.seq; 371 369 int e = 0; ··· 382 380 } 383 381 384 382 trace_seq_printf(s, "%.*s|%.*s|%.*s", 15, split, 40, split, 39, split); 385 - if (params->user_data) 383 + if (params->common.user_data) 386 384 trace_seq_printf(s, "-|%.*s", 39, split); 387 385 trace_seq_printf(s, "\n"); 388 386 ··· 407 405 trace_seq_printf(s, "%9llu", summary->max_thread); 408 406 } 409 407 410 - if (!params->user_data) { 408 + if (!params->common.user_data) { 411 409 trace_seq_printf(s, "\n"); 412 410 return; 413 411 } ··· 438 436 * timerlat_print_stats - print data for all cpus 439 437 */ 440 438 static void 441 - timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *top) 439 + timerlat_print_stats(struct osnoise_tool *top) 442 440 { 441 + struct timerlat_params *params = to_timerlat_params(top->params); 443 442 struct trace_instance *trace = &top->trace; 444 443 struct timerlat_top_cpu summary; 445 444 static int nr_cpus = -1; 446 445 int i; 447 446 448 - if (params->aa_only) 447 + if (params->common.aa_only) 449 448 return; 450 449 451 450 if (nr_cpus == -1) 452 451 nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 453 452 454 - if (!params->quiet) 453 + if (!params->common.quiet) 455 454 clear_terminal(trace->seq); 456 455 457 456 timerlat_top_reset_sum(&summary); ··· 460 457 timerlat_top_header(params, top); 461 458 462 459 for (i = 0; i < nr_cpus; i++) { 463 - if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus)) 460 + if (params->common.cpus && !CPU_ISSET(i, &params->common.monitored_cpus)) 464 461 continue; 465 462 timerlat_top_print(top, i); 466 463 timerlat_top_update_sum(top, i, &summary); ··· 542 539 /* 543 540 * timerlat_top_parse_args - allocs, parse and fill the cmd line parameters 544 541 */ 545 - static struct timerlat_params 542 + static struct common_params 546 543 *timerlat_top_parse_args(int argc, char **argv) 547 544 { 548 545 struct timerlat_params *params; ··· 556 553 if (!params) 557 554 exit(1); 558 555 559 - actions_init(&params->threshold_actions); 560 - actions_init(&params->end_actions); 556 + actions_init(&params->common.threshold_actions); 557 + actions_init(&params->common.end_actions); 561 558 562 559 /* disabled by default */ 563 560 params->dma_latency = -1; ··· 566 563 params->deepest_idle_state = -2; 567 564 568 565 /* display data in microseconds */ 569 - params->output_divisor = 1000; 566 + params->common.output_divisor = 1000; 570 567 571 568 /* default to BPF mode */ 572 569 params->mode = TRACING_MODE_BPF; ··· 621 618 auto_thresh = get_llong_from_str(optarg); 622 619 623 620 /* set thread stop to auto_thresh */ 624 - params->stop_total_us = auto_thresh; 625 - params->stop_us = auto_thresh; 621 + params->common.stop_total_us = auto_thresh; 622 + params->common.stop_us = auto_thresh; 626 623 627 624 /* get stack trace */ 628 625 params->print_stack = auto_thresh; ··· 636 633 auto_thresh = get_llong_from_str(optarg); 637 634 638 635 /* set thread stop to auto_thresh */ 639 - params->stop_total_us = auto_thresh; 640 - params->stop_us = auto_thresh; 636 + params->common.stop_total_us = auto_thresh; 637 + params->common.stop_us = auto_thresh; 641 638 642 639 /* get stack trace */ 643 640 params->print_stack = auto_thresh; 644 641 645 642 /* set aa_only to avoid parsing the trace */ 646 - params->aa_only = 1; 643 + params->common.aa_only = 1; 647 644 break; 648 645 case 'c': 649 - retval = parse_cpu_set(optarg, &params->monitored_cpus); 646 + retval = parse_cpu_set(optarg, &params->common.monitored_cpus); 650 647 if (retval) 651 648 timerlat_top_usage("\nInvalid -c cpu list\n"); 652 - params->cpus = optarg; 649 + params->common.cpus = optarg; 653 650 break; 654 651 case 'C': 655 - params->cgroup = 1; 652 + params->common.cgroup = 1; 656 653 if (!optarg) { 657 654 /* will inherit this cgroup */ 658 - params->cgroup_name = NULL; 655 + params->common.cgroup_name = NULL; 659 656 } else if (*optarg == '=') { 660 657 /* skip the = */ 661 - params->cgroup_name = ++optarg; 658 + params->common.cgroup_name = ++optarg; 662 659 } 663 660 break; 664 661 case 'D': 665 662 config_debug = 1; 666 663 break; 667 664 case 'd': 668 - params->duration = parse_seconds_duration(optarg); 669 - if (!params->duration) 665 + params->common.duration = parse_seconds_duration(optarg); 666 + if (!params->common.duration) 670 667 timerlat_top_usage("Invalid -d duration\n"); 671 668 break; 672 669 case 'e': ··· 676 673 exit(EXIT_FAILURE); 677 674 } 678 675 679 - if (params->events) 680 - tevent->next = params->events; 681 - params->events = tevent; 676 + if (params->common.events) 677 + tevent->next = params->common.events; 678 + params->common.events = tevent; 682 679 break; 683 680 case 'h': 684 681 case '?': 685 682 timerlat_top_usage(NULL); 686 683 break; 687 684 case 'H': 688 - params->hk_cpus = 1; 689 - retval = parse_cpu_set(optarg, &params->hk_cpu_set); 685 + params->common.hk_cpus = 1; 686 + retval = parse_cpu_set(optarg, &params->common.hk_cpu_set); 690 687 if (retval) { 691 688 err_msg("Error parsing house keeping CPUs\n"); 692 689 exit(EXIT_FAILURE); 693 690 } 694 691 break; 695 692 case 'i': 696 - params->stop_us = get_llong_from_str(optarg); 693 + params->common.stop_us = get_llong_from_str(optarg); 697 694 break; 698 695 case 'k': 699 - params->kernel_workload = true; 696 + params->common.kernel_workload = true; 700 697 break; 701 698 case 'n': 702 - params->output_divisor = 1; 699 + params->common.output_divisor = 1; 703 700 break; 704 701 case 'p': 705 702 params->timerlat_period_us = get_llong_from_str(optarg); ··· 707 704 timerlat_top_usage("Period longer than 1 s\n"); 708 705 break; 709 706 case 'P': 710 - retval = parse_prio(optarg, &params->sched_param); 707 + retval = parse_prio(optarg, &params->common.sched_param); 711 708 if (retval == -1) 712 709 timerlat_top_usage("Invalid -P priority"); 713 - params->set_sched = 1; 710 + params->common.set_sched = 1; 714 711 break; 715 712 case 'q': 716 - params->quiet = 1; 713 + params->common.quiet = 1; 717 714 break; 718 715 case 's': 719 716 params->print_stack = get_llong_from_str(optarg); 720 717 break; 721 718 case 'T': 722 - params->stop_total_us = get_llong_from_str(optarg); 719 + params->common.stop_total_us = get_llong_from_str(optarg); 723 720 break; 724 721 case 't': 725 722 if (optarg) { ··· 733 730 trace_output = "timerlat_trace.txt"; 734 731 break; 735 732 case 'u': 736 - params->user_workload = true; 733 + params->common.user_workload = true; 737 734 /* fallback: -u implies -U */ 738 735 case 'U': 739 - params->user_data = true; 736 + params->common.user_data = true; 740 737 break; 741 738 case '0': /* trigger */ 742 - if (params->events) { 743 - retval = trace_event_add_trigger(params->events, optarg); 739 + if (params->common.events) { 740 + retval = trace_event_add_trigger(params->common.events, optarg); 744 741 if (retval) { 745 742 err_msg("Error adding trigger %s\n", optarg); 746 743 exit(EXIT_FAILURE); ··· 750 747 } 751 748 break; 752 749 case '1': /* filter */ 753 - if (params->events) { 754 - retval = trace_event_add_filter(params->events, optarg); 750 + if (params->common.events) { 751 + retval = trace_event_add_filter(params->common.events, optarg); 755 752 if (retval) { 756 753 err_msg("Error adding filter %s\n", optarg); 757 754 exit(EXIT_FAILURE); ··· 774 771 params->dump_tasks = 1; 775 772 break; 776 773 case '6': 777 - params->warmup = get_llong_from_str(optarg); 774 + params->common.warmup = get_llong_from_str(optarg); 778 775 break; 779 776 case '7': 780 - params->buffer_size = get_llong_from_str(optarg); 777 + params->common.buffer_size = get_llong_from_str(optarg); 781 778 break; 782 779 case '8': 783 780 params->deepest_idle_state = get_llong_from_str(optarg); 784 781 break; 785 782 case '9': 786 - retval = actions_parse(&params->threshold_actions, optarg); 783 + retval = actions_parse(&params->common.threshold_actions, optarg, 784 + "timerlat_trace.txt"); 787 785 if (retval) { 788 786 err_msg("Invalid action %s\n", optarg); 789 787 exit(EXIT_FAILURE); 790 788 } 791 789 break; 792 790 case '\1': 793 - retval = actions_parse(&params->end_actions, optarg); 791 + retval = actions_parse(&params->common.end_actions, optarg, 792 + "timerlat_trace.txt"); 794 793 if (retval) { 795 794 err_msg("Invalid action %s\n", optarg); 796 795 exit(EXIT_FAILURE); ··· 804 799 } 805 800 806 801 if (trace_output) 807 - actions_add_trace_output(&params->threshold_actions, trace_output); 802 + actions_add_trace_output(&params->common.threshold_actions, trace_output); 808 803 809 804 if (geteuid()) { 810 805 err_msg("rtla needs root permission\n"); ··· 814 809 /* 815 810 * Auto analysis only happens if stop tracing, thus: 816 811 */ 817 - if (!params->stop_us && !params->stop_total_us) 812 + if (!params->common.stop_us && !params->common.stop_total_us) 818 813 params->no_aa = 1; 819 814 820 - if (params->no_aa && params->aa_only) 815 + if (params->no_aa && params->common.aa_only) 821 816 timerlat_top_usage("--no-aa and --aa-only are mutually exclusive!"); 822 817 823 - if (params->kernel_workload && params->user_workload) 818 + if (params->common.kernel_workload && params->common.user_workload) 824 819 timerlat_top_usage("--kernel-threads and --user-threads are mutually exclusive!"); 825 820 826 821 /* ··· 828 823 * mixed mode 829 824 */ 830 825 if (params->mode == TRACING_MODE_BPF && 831 - (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || 832 - params->end_actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa)) 826 + (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || 827 + params->common.end_actions.present[ACTION_TRACE_OUTPUT] || 828 + !params->no_aa)) 833 829 params->mode = TRACING_MODE_MIXED; 834 830 835 - return params; 831 + return &params->common; 836 832 } 837 833 838 834 /* 839 835 * timerlat_top_apply_config - apply the top configs to the initialized tool 840 836 */ 841 837 static int 842 - timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_params *params) 838 + timerlat_top_apply_config(struct osnoise_tool *top) 843 839 { 840 + struct timerlat_params *params = to_timerlat_params(top->params); 844 841 int retval; 845 842 846 843 retval = timerlat_apply_config(top, params); 847 844 if (retval) 848 845 goto out_err; 849 846 850 - if (isatty(STDOUT_FILENO) && !params->quiet) 851 - params->pretty_output = 1; 847 + if (isatty(STDOUT_FILENO) && !params->common.quiet) 848 + params->common.pretty_output = 1; 852 849 853 850 return 0; 854 851 ··· 862 855 * timerlat_init_top - initialize a timerlat top tool with parameters 863 856 */ 864 857 static struct osnoise_tool 865 - *timerlat_init_top(struct timerlat_params *params) 858 + *timerlat_init_top(struct common_params *params) 866 859 { 867 860 struct osnoise_tool *top; 868 861 int nr_cpus; ··· 877 870 if (!top->data) 878 871 goto out_err; 879 872 880 - top->params = params; 881 - 882 873 tep_register_event_handler(top->trace.tep, -1, "ftrace", "timerlat", 883 874 timerlat_top_handler, top); 884 875 ··· 887 882 return NULL; 888 883 } 889 884 890 - static int stop_tracing; 891 - static struct trace_instance *top_inst = NULL; 892 - static void stop_top(int sig) 893 - { 894 - if (stop_tracing) { 895 - /* 896 - * Stop requested twice in a row; abort event processing and 897 - * exit immediately 898 - */ 899 - tracefs_iterate_stop(top_inst->inst); 900 - return; 901 - } 902 - stop_tracing = 1; 903 - if (top_inst) 904 - trace_instance_stop(top_inst); 905 - } 906 - 907 - /* 908 - * timerlat_top_set_signals - handles the signal to stop the tool 909 - */ 910 - static void 911 - timerlat_top_set_signals(struct timerlat_params *params) 912 - { 913 - signal(SIGINT, stop_top); 914 - if (params->duration) { 915 - signal(SIGALRM, stop_top); 916 - alarm(params->duration); 917 - } 918 - } 919 - 920 - /* 921 - * timerlat_top_main_loop - main loop to process events 922 - */ 923 - static int 924 - timerlat_top_main_loop(struct osnoise_tool *top, 925 - struct osnoise_tool *record, 926 - struct osnoise_tool *aa, 927 - struct timerlat_params *params, 928 - struct timerlat_u_params *params_u) 929 - { 930 - struct trace_instance *trace = &top->trace; 931 - int retval; 932 - 933 - while (!stop_tracing) { 934 - sleep(params->sleep_time); 935 - 936 - if (params->aa_only && !osnoise_trace_is_off(top, record)) 937 - continue; 938 - 939 - retval = tracefs_iterate_raw_events(trace->tep, 940 - trace->inst, 941 - NULL, 942 - 0, 943 - collect_registered_events, 944 - trace); 945 - if (retval < 0) { 946 - err_msg("Error iterating on events\n"); 947 - return retval; 948 - } 949 - 950 - if (!params->quiet) 951 - timerlat_print_stats(params, top); 952 - 953 - if (osnoise_trace_is_off(top, record)) { 954 - actions_perform(&params->threshold_actions); 955 - 956 - if (!params->threshold_actions.continue_flag) 957 - /* continue flag not set, break */ 958 - break; 959 - 960 - /* continue action reached, re-enable tracing */ 961 - if (record) 962 - trace_instance_start(&record->trace); 963 - if (!params->no_aa) 964 - trace_instance_start(&aa->trace); 965 - trace_instance_start(trace); 966 - } 967 - 968 - /* is there still any user-threads ? */ 969 - if (params->user_workload) { 970 - if (params_u->stopped_running) { 971 - debug_msg("timerlat user space threads stopped!\n"); 972 - break; 973 - } 974 - } 975 - } 976 - 977 - return 0; 978 - } 979 - 980 885 /* 981 886 * timerlat_top_bpf_main_loop - main loop to process events (BPF variant) 982 887 */ 983 888 static int 984 - timerlat_top_bpf_main_loop(struct osnoise_tool *top, 985 - struct osnoise_tool *record, 986 - struct osnoise_tool *aa, 987 - struct timerlat_params *params, 988 - struct timerlat_u_params *params_u) 889 + timerlat_top_bpf_main_loop(struct osnoise_tool *tool) 989 890 { 891 + struct timerlat_params *params = to_timerlat_params(tool->params); 990 892 int retval, wait_retval; 991 893 992 - if (params->aa_only) { 894 + if (params->common.aa_only) { 993 895 /* Auto-analysis only, just wait for stop tracing */ 994 896 timerlat_bpf_wait(-1); 995 897 return 0; ··· 904 992 905 993 /* Pull and display data in a loop */ 906 994 while (!stop_tracing) { 907 - wait_retval = timerlat_bpf_wait(params->quiet ? -1 : params->sleep_time); 995 + wait_retval = timerlat_bpf_wait(params->common.quiet ? -1 : 996 + params->common.sleep_time); 908 997 909 - retval = timerlat_top_bpf_pull_data(top); 998 + retval = timerlat_top_bpf_pull_data(tool); 910 999 if (retval) { 911 1000 err_msg("Error pulling BPF data\n"); 912 1001 return retval; 913 1002 } 914 1003 915 - if (!params->quiet) 916 - timerlat_print_stats(params, top); 1004 + if (!params->common.quiet) 1005 + timerlat_print_stats(tool); 917 1006 918 1007 if (wait_retval == 1) { 919 1008 /* Stopping requested by tracer */ 920 - actions_perform(&params->threshold_actions); 1009 + actions_perform(&params->common.threshold_actions); 921 1010 922 - if (!params->threshold_actions.continue_flag) 1011 + if (!params->common.threshold_actions.continue_flag) 923 1012 /* continue flag not set, break */ 924 1013 break; 925 1014 926 1015 /* continue action reached, re-enable tracing */ 927 - if (record) 928 - trace_instance_start(&record->trace); 929 - if (!params->no_aa) 930 - trace_instance_start(&aa->trace); 1016 + if (tool->record) 1017 + trace_instance_start(&tool->record->trace); 1018 + if (tool->aa) 1019 + trace_instance_start(&tool->aa->trace); 931 1020 timerlat_bpf_restart_tracing(); 932 1021 } 933 1022 934 1023 /* is there still any user-threads ? */ 935 - if (params->user_workload) { 936 - if (params_u->stopped_running) { 1024 + if (params->common.user_workload) { 1025 + if (params->common.user.stopped_running) { 937 1026 debug_msg("timerlat user space threads stopped!\n"); 938 1027 break; 939 1028 } ··· 944 1031 return 0; 945 1032 } 946 1033 947 - int timerlat_top_main(int argc, char *argv[]) 1034 + static int timerlat_top_main_loop(struct osnoise_tool *tool) 948 1035 { 949 - struct timerlat_params *params; 950 - struct osnoise_tool *record = NULL; 951 - struct timerlat_u_params params_u; 952 - enum result return_value = ERROR; 953 - struct osnoise_tool *top = NULL; 954 - struct osnoise_tool *aa = NULL; 955 - struct trace_instance *trace; 956 - int dma_latency_fd = -1; 957 - pthread_t timerlat_u; 958 - char *max_lat; 1036 + struct timerlat_params *params = to_timerlat_params(tool->params); 959 1037 int retval; 960 - int nr_cpus, i; 961 1038 962 - params = timerlat_top_parse_args(argc, argv); 963 - if (!params) 964 - exit(1); 965 - 966 - top = timerlat_init_top(params); 967 - if (!top) { 968 - err_msg("Could not init osnoise top\n"); 969 - goto out_exit; 970 - } 971 - 972 - trace = &top->trace; 973 - /* 974 - * Save trace instance into global variable so that SIGINT can stop 975 - * the timerlat tracer. 976 - * Otherwise, rtla could loop indefinitely when overloaded. 977 - */ 978 - top_inst = trace; 979 - 980 - /* 981 - * Try to enable BPF, unless disabled explicitly. 982 - * If BPF enablement fails, fall back to tracefs mode. 983 - */ 984 - if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { 985 - debug_msg("RTLA_NO_BPF set, disabling BPF\n"); 986 - params->mode = TRACING_MODE_TRACEFS; 987 - } else if (!tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { 988 - debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); 989 - params->mode = TRACING_MODE_TRACEFS; 990 - } else { 991 - retval = timerlat_bpf_init(params); 992 - if (retval) { 993 - debug_msg("Could not enable BPF\n"); 994 - params->mode = TRACING_MODE_TRACEFS; 995 - } 996 - } 997 - 998 - retval = timerlat_top_apply_config(top, params); 999 - if (retval) { 1000 - err_msg("Could not apply config\n"); 1001 - goto out_free; 1002 - } 1003 - 1004 - retval = enable_timerlat(trace); 1005 - if (retval) { 1006 - err_msg("Failed to enable timerlat tracer\n"); 1007 - goto out_free; 1008 - } 1009 - 1010 - if (params->set_sched) { 1011 - retval = set_comm_sched_attr("timerlat/", &params->sched_param); 1012 - if (retval) { 1013 - err_msg("Failed to set sched parameters\n"); 1014 - goto out_free; 1015 - } 1016 - } 1017 - 1018 - if (params->cgroup && !params->user_data) { 1019 - retval = set_comm_cgroup("timerlat/", params->cgroup_name); 1020 - if (!retval) { 1021 - err_msg("Failed to move threads to cgroup\n"); 1022 - goto out_free; 1023 - } 1024 - } 1025 - 1026 - if (params->dma_latency >= 0) { 1027 - dma_latency_fd = set_cpu_dma_latency(params->dma_latency); 1028 - if (dma_latency_fd < 0) { 1029 - err_msg("Could not set /dev/cpu_dma_latency.\n"); 1030 - goto out_free; 1031 - } 1032 - } 1033 - 1034 - if (params->deepest_idle_state >= -1) { 1035 - if (!have_libcpupower_support()) { 1036 - err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n"); 1037 - goto out_free; 1038 - } 1039 - 1040 - nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 1041 - 1042 - for (i = 0; i < nr_cpus; i++) { 1043 - if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus)) 1044 - continue; 1045 - if (save_cpu_idle_disable_state(i) < 0) { 1046 - err_msg("Could not save cpu idle state.\n"); 1047 - goto out_free; 1048 - } 1049 - if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) { 1050 - err_msg("Could not set deepest cpu idle state.\n"); 1051 - goto out_free; 1052 - } 1053 - } 1054 - } 1055 - 1056 - if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || 1057 - params->end_actions.present[ACTION_TRACE_OUTPUT]) { 1058 - record = osnoise_init_trace_tool("timerlat"); 1059 - if (!record) { 1060 - err_msg("Failed to enable the trace instance\n"); 1061 - goto out_free; 1062 - } 1063 - params->threshold_actions.trace_output_inst = record->trace.inst; 1064 - params->end_actions.trace_output_inst = record->trace.inst; 1065 - 1066 - if (params->events) { 1067 - retval = trace_events_enable(&record->trace, params->events); 1068 - if (retval) 1069 - goto out_top; 1070 - } 1071 - 1072 - if (params->buffer_size > 0) { 1073 - retval = trace_set_buffer_size(&record->trace, params->buffer_size); 1074 - if (retval) 1075 - goto out_top; 1076 - } 1077 - } 1078 - 1079 - if (!params->no_aa) { 1080 - aa = osnoise_init_tool("timerlat_aa"); 1081 - if (!aa) 1082 - goto out_top; 1083 - 1084 - retval = timerlat_aa_init(aa, params->dump_tasks); 1085 - if (retval) { 1086 - err_msg("Failed to enable the auto analysis instance\n"); 1087 - goto out_top; 1088 - } 1089 - 1090 - /* if it is re-using the main instance, there is no need to start it */ 1091 - if (aa != top) { 1092 - retval = enable_timerlat(&aa->trace); 1093 - if (retval) { 1094 - err_msg("Failed to enable timerlat tracer\n"); 1095 - goto out_top; 1096 - } 1097 - } 1098 - } 1099 - 1100 - if (params->user_workload) { 1101 - /* rtla asked to stop */ 1102 - params_u.should_run = 1; 1103 - /* all threads left */ 1104 - params_u.stopped_running = 0; 1105 - 1106 - params_u.set = &params->monitored_cpus; 1107 - if (params->set_sched) 1108 - params_u.sched_param = &params->sched_param; 1109 - else 1110 - params_u.sched_param = NULL; 1111 - 1112 - params_u.cgroup_name = params->cgroup_name; 1113 - 1114 - retval = pthread_create(&timerlat_u, NULL, timerlat_u_dispatcher, &params_u); 1115 - if (retval) 1116 - err_msg("Error creating timerlat user-space threads\n"); 1117 - } 1118 - 1119 - if (params->warmup > 0) { 1120 - debug_msg("Warming up for %d seconds\n", params->warmup); 1121 - sleep(params->warmup); 1122 - } 1123 - 1124 - /* 1125 - * Start the tracers here, after having set all instances. 1126 - * 1127 - * Let the trace instance start first for the case of hitting a stop 1128 - * tracing while enabling other instances. The trace instance is the 1129 - * one with most valuable information. 1130 - */ 1131 - if (record) 1132 - trace_instance_start(&record->trace); 1133 - if (!params->no_aa) 1134 - trace_instance_start(&aa->trace); 1135 1039 if (params->mode == TRACING_MODE_TRACEFS) { 1136 - trace_instance_start(trace); 1040 + retval = top_main_loop(tool); 1137 1041 } else { 1138 - retval = timerlat_bpf_attach(); 1139 - if (retval) { 1140 - err_msg("Error attaching BPF program\n"); 1141 - goto out_top; 1142 - } 1143 - } 1144 - 1145 - top->start_time = time(NULL); 1146 - timerlat_top_set_signals(params); 1147 - 1148 - if (params->mode == TRACING_MODE_TRACEFS) 1149 - retval = timerlat_top_main_loop(top, record, aa, params, &params_u); 1150 - else 1151 - retval = timerlat_top_bpf_main_loop(top, record, aa, params, &params_u); 1152 - 1153 - if (retval) 1154 - goto out_top; 1155 - 1156 - if (params->mode != TRACING_MODE_TRACEFS) 1042 + retval = timerlat_top_bpf_main_loop(tool); 1157 1043 timerlat_bpf_detach(); 1158 - 1159 - if (params->user_workload && !params_u.stopped_running) { 1160 - params_u.should_run = 0; 1161 - sleep(1); 1162 1044 } 1163 1045 1164 - timerlat_print_stats(params, top); 1165 - 1166 - actions_perform(&params->end_actions); 1167 - 1168 - return_value = PASSED; 1169 - 1170 - if (osnoise_trace_is_off(top, record) && !stop_tracing) { 1171 - printf("rtla timerlat hit stop tracing\n"); 1172 - 1173 - if (!params->no_aa) 1174 - timerlat_auto_analysis(params->stop_us, params->stop_total_us); 1175 - 1176 - return_value = FAILED; 1177 - } else if (params->aa_only) { 1178 - /* 1179 - * If the trace did not stop with --aa-only, at least print the 1180 - * max known latency. 1181 - */ 1182 - max_lat = tracefs_instance_file_read(trace->inst, "tracing_max_latency", NULL); 1183 - if (max_lat) { 1184 - printf(" Max latency was %s\n", max_lat); 1185 - free(max_lat); 1186 - } 1187 - } 1188 - 1189 - out_top: 1190 - timerlat_aa_destroy(); 1191 - if (dma_latency_fd >= 0) 1192 - close(dma_latency_fd); 1193 - if (params->deepest_idle_state >= -1) { 1194 - for (i = 0; i < nr_cpus; i++) { 1195 - if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus)) 1196 - continue; 1197 - restore_cpu_idle_disable_state(i); 1198 - } 1199 - } 1200 - trace_events_destroy(&record->trace, params->events); 1201 - params->events = NULL; 1202 - out_free: 1203 - timerlat_free_top(top->data); 1204 - if (aa && aa != top) 1205 - osnoise_destroy_tool(aa); 1206 - osnoise_destroy_tool(record); 1207 - osnoise_destroy_tool(top); 1208 - actions_destroy(&params->threshold_actions); 1209 - actions_destroy(&params->end_actions); 1210 - if (params->mode != TRACING_MODE_TRACEFS) 1211 - timerlat_bpf_destroy(); 1212 - free(params); 1213 - free_cpu_idle_disable_states(); 1214 - out_exit: 1215 - exit(return_value); 1046 + return retval; 1216 1047 } 1048 + 1049 + struct tool_ops timerlat_top_ops = { 1050 + .tracer = "timerlat", 1051 + .comm_prefix = "timerlat/", 1052 + .parse_args = timerlat_top_parse_args, 1053 + .init_tool = timerlat_init_top, 1054 + .apply_config = timerlat_top_apply_config, 1055 + .enable = timerlat_enable, 1056 + .main = timerlat_top_main_loop, 1057 + .print_stats = timerlat_print_stats, 1058 + .analyze = timerlat_analyze, 1059 + .free = timerlat_free_top_tool, 1060 + };
-3
tools/tracing/rtla/src/trace.h
··· 30 30 int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name); 31 31 void disable_tracer(struct tracefs_instance *inst); 32 32 33 - int enable_osnoise(struct trace_instance *trace); 34 - int enable_timerlat(struct trace_instance *trace); 35 - 36 33 struct tracefs_instance *create_instance(char *instance_name); 37 34 void destroy_instance(struct tracefs_instance *inst); 38 35
+18 -8
tools/tracing/rtla/tests/engine.sh
··· 43 43 tested_command=$1 44 44 expected_exitcode=${3:-0} 45 45 expected_output=$4 46 + unexpected_output=$5 46 47 # Simple check: run rtla with given arguments and test exit code. 47 48 # If TEST_COUNT is set, run the test. Otherwise, just count. 48 49 ctr=$(($ctr + 1)) ··· 54 53 # Run rtla; in case of failure, include its output as comment 55 54 # in the test results. 56 55 result=$(eval stdbuf -oL $TIMEOUT "$RTLA" $2 2>&1); exitcode=$? 56 + failbuf='' 57 + fail=0 58 + 57 59 # Test if the results matches if requested 58 - if [ -n "$expected_output" ] 60 + if [ -n "$expected_output" ] && ! grep -qE "$expected_output" <<< "$result" 59 61 then 60 - grep -E "$expected_output" <<< "$result" > /dev/null; grep_result=$? 61 - else 62 - grep_result=0 62 + fail=1 63 + failbuf+=$(printf "# Output match failed: \"%s\"" "$expected_output") 64 + failbuf+=$'\n' 63 65 fi 64 66 65 - if [ $exitcode -eq $expected_exitcode ] && [ $grep_result -eq 0 ] 67 + if [ -n "$unexpected_output" ] && grep -qE "$unexpected_output" <<< "$result" 68 + then 69 + fail=1 70 + failbuf+=$(printf "# Output non-match failed: \"%s\"" "$unexpected_output") 71 + failbuf+=$'\n' 72 + fi 73 + 74 + if [ $exitcode -eq $expected_exitcode ] && [ $fail -eq 0 ] 66 75 then 67 76 echo "ok $ctr - $1" 68 77 else 69 - echo "not ok $ctr - $1" 70 78 # Add rtla output and exit code as comments in case of failure 79 + echo "not ok $ctr - $1" 80 + echo -n "$failbuf" 71 81 echo "$result" | col -b | while read line; do echo "# $line"; done 72 82 printf "#\n# exit code %s\n" $exitcode 73 - [ -n "$expected_output" ] && [ $grep_result -ne 0 ] && \ 74 - printf "# Output match failed: \"%s\"\n" "$expected_output" 75 83 fi 76 84 fi 77 85 }
+26 -1
tools/tracing/rtla/tests/osnoise.t
··· 8 8 check "verify help page" \ 9 9 "osnoise --help" 0 "osnoise version" 10 10 check "verify the --priority/-P param" \ 11 - "osnoise top -P F:1 -c 0 -r 900000 -d 10s -q" 11 + "osnoise top -P F:1 -c 0 -r 900000 -d 10s -q -S 1 --on-threshold shell,command=\"tests/scripts/check-priority.sh osnoise/ SCHED_FIFO 1\"" \ 12 + 2 "Priorities are set correctly" 12 13 check "verify the --stop/-s param" \ 13 14 "osnoise top -s 30 -T 1" 2 "osnoise hit stop tracing" 14 15 check "verify the --trace param" \ ··· 22 21 # If default period is not set, this will time out. 23 22 check_with_osnoise_options "apply default period" \ 24 23 "osnoise hist -s 1" 2 period_us=600000000 24 + 25 + # Actions tests 26 + check "trace output through -t with custom filename" \ 27 + "osnoise hist -S 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" 28 + check "trace output through --on-threshold trace" \ 29 + "osnoise hist -S 2 --on-threshold trace" 2 "^ Saving trace to osnoise_trace.txt$" 30 + check "trace output through --on-threshold trace with custom filename" \ 31 + "osnoise hist -S 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" 32 + check "exec command" \ 33 + "osnoise hist -S 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$" 34 + check "multiple actions" \ 35 + "osnoise hist -S 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$" 36 + check "hist stop at failed action" \ 37 + "osnoise hist -S 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA osnoise histogram$" 38 + check "top stop at failed action" \ 39 + "timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" 40 + check "hist with continue" \ 41 + "osnoise hist -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 42 + check "top with continue" \ 43 + "osnoise top -q -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" 44 + check "hist with trace output at end" \ 45 + "osnoise hist -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$" 46 + check "top with trace output at end" \ 47 + "osnoise top -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$" 25 48 26 49 test_end
+2 -2
tools/tracing/rtla/tests/timerlat.t
··· 47 47 "timerlat hist -T 2 -t" 2 "^ Saving trace to timerlat_trace.txt$" 48 48 check "trace output through -t with custom filename" \ 49 49 "timerlat hist -T 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" 50 - check "trace output through -A trace" \ 50 + check "trace output through --on-threshold trace" \ 51 51 "timerlat hist -T 2 --on-threshold trace" 2 "^ Saving trace to timerlat_trace.txt$" 52 - check "trace output through -A trace with custom filename" \ 52 + check "trace output through --on-threshold trace with custom filename" \ 53 53 "timerlat hist -T 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" 54 54 check "exec command" \ 55 55 "timerlat hist -T 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$"