Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308// SPDX-License-Identifier: GPL-2.0/* * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> */#define _GNU_SOURCE#include <sys/types.h>#include <sys/stat.h>#include <pthread.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <stdio.h>#include <sched.h>
#include <linux/compiler.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 */inttimerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params){ int retval; const char *const rtla_no_bpf = getenv("RTLA_NO_BPF");
/* * Try to enable BPF, unless disabled explicitly. * If BPF enablement fails, fall back to tracefs mode. */ if (rtla_no_bpf && strncmp_static(rtla_no_bpf, "1") == 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; } }
/* Check if BPF action program is requested but BPF is not available */ if (params->bpf_action_program) { if (params->mode == TRACING_MODE_TRACEFS) { err_msg("BPF actions are not supported in tracefs-only mode\n"); goto out_err; }
if (timerlat_load_bpf_action_program(params->bpf_action_program)) goto out_err; }
retval = osnoise_set_timerlat_period_us(tool->context, params->timerlat_period_us ? params->timerlat_period_us : DEFAULT_TIMERLAT_PERIOD); if (retval) { err_msg("Failed to set timerlat period\n"); goto out_err; }
retval = osnoise_set_print_stack(tool->context, params->print_stack); if (retval) { err_msg("Failed to set print stack\n"); goto out_err; }
retval = osnoise_set_timerlat_align(tool->context, params->timerlat_align); if (retval && params->timerlat_align) { /* * We might be running on a kernel that does not support timerlat align. * Unless user requested it explicitly, ignore the error. */ err_msg("Failed to enable timerlat align\n"); goto out_err; }
if (params->timerlat_align) { retval = osnoise_set_timerlat_align_us(tool->context, params->timerlat_align_us); if (retval) { err_msg("Failed to set timerlat align us\n"); goto out_err; } }
/* * 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->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->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; } }
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, 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; }
for_each_monitored_cpu(i, ¶ms->common) { 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, params->stack_format); 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; } }
/* * In tracefs and mixed mode, timerlat tracer handles stopping * on threshold */ if (params->mode != TRACING_MODE_BPF) { retval = osn_set_stop(tool); if (retval) 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(tool->trace.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 i;
timerlat_aa_destroy(); if (dma_latency_fd >= 0) close(dma_latency_fd); if (params->deepest_idle_state >= -1) { for_each_monitored_cpu(i, ¶ms->common) { 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();}
__noreturn static void timerlat_usage(int err){ int i;
static const char * const msg[] = { "", "timerlat version " VERSION, "", " usage: [rtla] timerlat [MODE] ...", "", " modes:", " top - prints the summary from timerlat tracer", " hist - prints a histogram of timer latencies", "", "if no MODE is given, the top mode is called, passing the arguments", NULL, };
for (i = 0; msg[i]; i++) fprintf(stderr, "%s\n", msg[i]); exit(err);}
int timerlat_main(int argc, char *argv[]){ if (argc == 0) goto usage;
/* * if timerlat was called without any argument, run the * default cmdline. */ if (argc == 1) { run_tool(&timerlat_top_ops, argc, argv); exit(0); }
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) { timerlat_usage(129); } else if (str_has_prefix(argv[1], "-")) { /* the user skipped the tool, call the default one */ run_tool(&timerlat_top_ops, argc, argv); exit(0); } else if (strcmp(argv[1], "top") == 0) { run_tool(&timerlat_top_ops, argc-1, &argv[1]); exit(0); } else if (strcmp(argv[1], "hist") == 0) { run_tool(&timerlat_hist_ops, argc-1, &argv[1]); exit(0); }
usage: timerlat_usage(129);}