diff options
Diffstat (limited to 'tools/tracing/rtla/src/timerlat.c')
| -rw-r--r-- | tools/tracing/rtla/src/timerlat.c | 167 |
1 files changed, 160 insertions, 7 deletions
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index e4bf58db1dd2..b69212874127 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -15,9 +15,13 @@ #include <sched.h> #include "timerlat.h" +#include "timerlat_aa.h" +#include "timerlat_bpf.h" #define DEFAULT_TIMERLAT_PERIOD 1000 /* 1ms */ +static int dma_latency_fd = -1; + /* * timerlat_apply_config - apply common configs to the initialized tool */ @@ -26,6 +30,24 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) { int retval; + /* + * Try to enable BPF, unless disabled explicitly. + * If BPF enablement fails, fall back to tracefs mode. + */ + if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { + debug_msg("RTLA_NO_BPF set, disabling BPF\n"); + params->mode = TRACING_MODE_TRACEFS; + } else if (!tep_find_event_by_name(tool->trace.tep, "osnoise", "timerlat_sample")) { + debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); + params->mode = TRACING_MODE_TRACEFS; + } else { + retval = timerlat_bpf_init(params); + if (retval) { + debug_msg("Could not enable BPF\n"); + params->mode = TRACING_MODE_TRACEFS; + } + } + if (params->mode != TRACING_MODE_BPF) { /* * In tracefs and mixed mode, timerlat tracer handles stopping @@ -65,12 +87,12 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) * If the user did not specify a type of thread, try user-threads first. * Fall back to kernel threads otherwise. */ - if (!params->common.kernel_workload && !params->user_data) { + if (!params->common.kernel_workload && !params->common.user_data) { retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd"); if (retval) { debug_msg("User-space interface detected, setting user-threads\n"); - params->user_workload = 1; - params->user_data = 1; + params->common.user_workload = 1; + params->common.user_data = 1; } else { debug_msg("User-space interface not detected, setting kernel-threads\n"); params->common.kernel_workload = 1; @@ -83,6 +105,137 @@ out_err: return -1; } +int timerlat_enable(struct osnoise_tool *tool) +{ + struct timerlat_params *params = to_timerlat_params(tool->params); + int retval, nr_cpus, i; + + if (params->dma_latency >= 0) { + dma_latency_fd = set_cpu_dma_latency(params->dma_latency); + if (dma_latency_fd < 0) { + err_msg("Could not set /dev/cpu_dma_latency.\n"); + return -1; + } + } + + if (params->deepest_idle_state >= -1) { + if (!have_libcpupower_support()) { + err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n"); + return -1; + } + + nr_cpus = sysconf(_SC_NPROCESSORS_CONF); + + for (i = 0; i < nr_cpus; i++) { + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) + continue; + if (save_cpu_idle_disable_state(i) < 0) { + err_msg("Could not save cpu idle state.\n"); + return -1; + } + if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) { + err_msg("Could not set deepest cpu idle state.\n"); + return -1; + } + } + } + + if (!params->no_aa) { + tool->aa = osnoise_init_tool("timerlat_aa"); + if (!tool->aa) + return -1; + + retval = timerlat_aa_init(tool->aa, params->dump_tasks); + if (retval) { + err_msg("Failed to enable the auto analysis instance\n"); + return retval; + } + + retval = enable_tracer_by_name(tool->aa->trace.inst, "timerlat"); + if (retval) { + err_msg("Failed to enable aa tracer\n"); + return retval; + } + } + + if (params->common.warmup > 0) { + debug_msg("Warming up for %d seconds\n", params->common.warmup); + sleep(params->common.warmup); + if (stop_tracing) + return -1; + } + + /* + * Start the tracers here, after having set all instances. + * + * Let the trace instance start first for the case of hitting a stop + * tracing while enabling other instances. The trace instance is the + * one with most valuable information. + */ + if (tool->record) + trace_instance_start(&tool->record->trace); + if (!params->no_aa) + trace_instance_start(&tool->aa->trace); + if (params->mode == TRACING_MODE_TRACEFS) { + trace_instance_start(&tool->trace); + } else { + retval = timerlat_bpf_attach(); + if (retval) { + err_msg("Error attaching BPF program\n"); + return retval; + } + } + + return 0; +} + +void timerlat_analyze(struct osnoise_tool *tool, bool stopped) +{ + struct timerlat_params *params = to_timerlat_params(tool->params); + + if (stopped) { + if (!params->no_aa) + timerlat_auto_analysis(params->common.stop_us, + params->common.stop_total_us); + } else if (params->common.aa_only) { + char *max_lat; + + /* + * If the trace did not stop with --aa-only, at least print + * the max known latency. + */ + max_lat = tracefs_instance_file_read(trace_inst->inst, "tracing_max_latency", NULL); + if (max_lat) { + printf(" Max latency was %s\n", max_lat); + free(max_lat); + } + } +} + +void timerlat_free(struct osnoise_tool *tool) +{ + struct timerlat_params *params = to_timerlat_params(tool->params); + int nr_cpus, i; + + timerlat_aa_destroy(); + if (dma_latency_fd >= 0) + close(dma_latency_fd); + if (params->deepest_idle_state >= -1) { + for (i = 0; i < nr_cpus; i++) { + if (params->common.cpus && + !CPU_ISSET(i, ¶ms->common.monitored_cpus)) + continue; + restore_cpu_idle_disable_state(i); + } + } + + osnoise_destroy_tool(tool->aa); + + if (params->mode != TRACING_MODE_TRACEFS) + timerlat_bpf_destroy(); + free_cpu_idle_disable_states(); +} + static void timerlat_usage(int err) { int i; @@ -116,7 +269,7 @@ int timerlat_main(int argc, char *argv[]) * default cmdline. */ if (argc == 1) { - timerlat_top_main(argc, argv); + run_tool(&timerlat_top_ops, argc, argv); exit(0); } @@ -124,13 +277,13 @@ int timerlat_main(int argc, char *argv[]) timerlat_usage(0); } else if (strncmp(argv[1], "-", 1) == 0) { /* the user skipped the tool, call the default one */ - timerlat_top_main(argc, argv); + run_tool(&timerlat_top_ops, argc, argv); exit(0); } else if (strcmp(argv[1], "top") == 0) { - timerlat_top_main(argc-1, &argv[1]); + run_tool(&timerlat_top_ops, argc-1, &argv[1]); exit(0); } else if (strcmp(argv[1], "hist") == 0) { - timerlat_hist_main(argc-1, &argv[1]); + run_tool(&timerlat_hist_ops, argc-1, &argv[1]); exit(0); } |