summaryrefslogtreecommitdiff
path: root/tools/tracing/rtla/src/timerlat.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/tracing/rtla/src/timerlat.c')
-rw-r--r--tools/tracing/rtla/src/timerlat.c167
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, &params->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, &params->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);
}