diff options
Diffstat (limited to 'tools/tracing/rtla/src/timerlat.c')
-rw-r--r-- | tools/tracing/rtla/src/timerlat.c | 210 |
1 files changed, 160 insertions, 50 deletions
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index 63d6d43eafff..b69212874127 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -15,29 +15,37 @@ #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 */ int timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) { - int retval, i; - - if (!params->sleep_time) - params->sleep_time = 1; - - retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); - if (retval) { - err_msg("Failed to apply CPUs config\n"); - goto out_err; - } + int retval; - if (!params->cpus) { - for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) - CPU_SET(i, ¶ms->monitored_cpus); + /* + * 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) { @@ -45,13 +53,13 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) * In tracefs and mixed mode, timerlat tracer handles stopping * on threshold */ - retval = osnoise_set_stop_us(tool->context, params->stop_us); + retval = osnoise_set_stop_us(tool->context, params->common.stop_us); if (retval) { err_msg("Failed to set stop us\n"); goto out_err; } - retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); + retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us); if (retval) { err_msg("Failed to set stop total us\n"); goto out_err; @@ -75,55 +83,157 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) goto out_err; } - if (params->hk_cpus) { - retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), - ¶ms->hk_cpu_set); - if (retval == -1) { - err_msg("Failed to set rtla to the house keeping CPUs\n"); - goto out_err; - } - } else if (params->cpus) { - /* - * Even if the user do not set a house-keeping CPU, try to - * move rtla to a CPU set different to the one where the user - * set the workload to run. - * - * No need to check results as this is an automatic attempt. - */ - auto_house_keeping(¶ms->monitored_cpus); - } - /* * If the user did not specify a type of thread, try user-threads first. * Fall back to kernel threads otherwise. */ - if (!params->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->kernel_workload = 1; + params->common.kernel_workload = 1; + } + } + + return common_apply_config(tool, ¶ms->common); + +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; + } + /* - * Set workload according to type of thread if the kernel supports it. - * On kernels without support, user threads will have already failed - * on missing timerlat_fd, and kernel threads do not need it. + * 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. */ - retval = osnoise_set_workload(tool->context, params->kernel_workload); - if (retval < -1) { - err_msg("Failed to set OSNOISE_WORKLOAD option\n"); - goto out_err; + 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; +} -out_err: - return -1; +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) @@ -159,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); } @@ -167,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); } |