#include "timerlat.h"
#include "timerlat_aa.h"
#include "timerlat_u.h"
+#include "timerlat_bpf.h"
struct timerlat_top_cpu {
unsigned long long irq_count;
return 0;
}
+/*
+ * timerlat_top_bpf_pull_data - copy data from BPF maps into userspace
+ */
+static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
+{
+ struct timerlat_top_data *data = tool->data;
+ int i, err;
+ long long value_irq[data->nr_cpus],
+ value_thread[data->nr_cpus],
+ value_user[data->nr_cpus];
+
+ /* Pull summary */
+ err = timerlat_bpf_get_summary_value(SUMMARY_CURRENT,
+ value_irq, value_thread, value_user,
+ data->nr_cpus);
+ if (err)
+ return err;
+ for (i = 0; i < data->nr_cpus; i++) {
+ data->cpu_data[i].cur_irq = value_irq[i];
+ data->cpu_data[i].cur_thread = value_thread[i];
+ data->cpu_data[i].cur_user = value_user[i];
+ }
+
+ err = timerlat_bpf_get_summary_value(SUMMARY_COUNT,
+ value_irq, value_thread, value_user,
+ data->nr_cpus);
+ if (err)
+ return err;
+ for (i = 0; i < data->nr_cpus; i++) {
+ data->cpu_data[i].irq_count = value_irq[i];
+ data->cpu_data[i].thread_count = value_thread[i];
+ data->cpu_data[i].user_count = value_user[i];
+ }
+
+ err = timerlat_bpf_get_summary_value(SUMMARY_MIN,
+ value_irq, value_thread, value_user,
+ data->nr_cpus);
+ if (err)
+ return err;
+ for (i = 0; i < data->nr_cpus; i++) {
+ data->cpu_data[i].min_irq = value_irq[i];
+ data->cpu_data[i].min_thread = value_thread[i];
+ data->cpu_data[i].min_user = value_user[i];
+ }
+
+ err = timerlat_bpf_get_summary_value(SUMMARY_MAX,
+ value_irq, value_thread, value_user,
+ data->nr_cpus);
+ if (err)
+ return err;
+ for (i = 0; i < data->nr_cpus; i++) {
+ data->cpu_data[i].max_irq = value_irq[i];
+ data->cpu_data[i].max_thread = value_thread[i];
+ data->cpu_data[i].max_user = value_user[i];
+ }
+
+ err = timerlat_bpf_get_summary_value(SUMMARY_SUM,
+ value_irq, value_thread, value_user,
+ data->nr_cpus);
+ if (err)
+ return err;
+ for (i = 0; i < data->nr_cpus; i++) {
+ data->cpu_data[i].sum_irq = value_irq[i];
+ data->cpu_data[i].sum_thread = value_thread[i];
+ data->cpu_data[i].sum_user = value_user[i];
+ }
+
+ return 0;
+}
+
/*
* timerlat_top_header - print the header of the tool output
*/
}
}
+/*
+ * timerlat_top_main_loop - main loop to process events
+ */
+static int
+timerlat_top_main_loop(struct osnoise_tool *top,
+ struct osnoise_tool *record,
+ struct timerlat_params *params,
+ struct timerlat_u_params *params_u)
+{
+ struct trace_instance *trace = &top->trace;
+ int retval;
+
+ while (!stop_tracing) {
+ sleep(params->sleep_time);
+
+ if (params->aa_only && !osnoise_trace_is_off(top, record))
+ continue;
+
+ retval = tracefs_iterate_raw_events(trace->tep,
+ trace->inst,
+ NULL,
+ 0,
+ collect_registered_events,
+ trace);
+ if (retval < 0) {
+ err_msg("Error iterating on events\n");
+ return retval;
+ }
+
+ if (!params->quiet)
+ timerlat_print_stats(params, top);
+
+ if (osnoise_trace_is_off(top, record))
+ break;
+
+ /* is there still any user-threads ? */
+ if (params->user_workload) {
+ if (params_u->stopped_running) {
+ debug_msg("timerlat user space threads stopped!\n");
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * timerlat_top_bpf_main_loop - main loop to process events (BPF variant)
+ */
+static int
+timerlat_top_bpf_main_loop(struct osnoise_tool *top,
+ struct osnoise_tool *record,
+ struct timerlat_params *params,
+ struct timerlat_u_params *params_u)
+{
+ int retval, wait_retval;
+
+ if (params->aa_only) {
+ /* Auto-analysis only, just wait for stop tracing */
+ timerlat_bpf_wait(-1);
+ return 0;
+ }
+
+ if (params->quiet) {
+ /* Quiet mode: wait for stop and then, print results */
+ timerlat_bpf_wait(-1);
+
+ retval = timerlat_top_bpf_pull_data(top);
+ if (retval) {
+ err_msg("Error pulling BPF data\n");
+ return retval;
+ }
+
+ return 0;
+ }
+
+ /* Pull and display data in a loop */
+ while (!stop_tracing) {
+ wait_retval = timerlat_bpf_wait(params->sleep_time);
+
+ retval = timerlat_top_bpf_pull_data(top);
+ if (retval) {
+ err_msg("Error pulling BPF data\n");
+ return retval;
+ }
+
+ timerlat_print_stats(params, top);
+
+ if (wait_retval == 1)
+ /* Stopping requested by tracer */
+ break;
+
+ /* is there still any user-threads ? */
+ if (params->user_workload) {
+ if (params_u->stopped_running) {
+ debug_msg("timerlat user space threads stopped!\n");
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
int timerlat_top_main(int argc, char *argv[])
{
struct timerlat_params *params;
char *max_lat;
int retval;
int nr_cpus, i;
+ bool no_bpf = false;
params = timerlat_top_parse_args(argc, argv);
if (!params)
*/
top_inst = trace;
+ if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) {
+ debug_msg("RTLA_NO_BPF set, disabling BPF\n");
+ no_bpf = true;
+ }
+
+ if (!no_bpf && !tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) {
+ debug_msg("osnoise:timerlat_sample missing, disabling BPF\n");
+ no_bpf = true;
+ }
+
+ if (!no_bpf) {
+ retval = timerlat_bpf_init(params);
+ if (retval) {
+ debug_msg("Could not enable BPF\n");
+ no_bpf = true;
+ }
+ }
retval = enable_timerlat(trace);
if (retval) {
}
if (!params->no_aa) {
- if (params->aa_only) {
- /* as top is not used for display, use it for aa */
- aa = top;
- } else {
- /* otherwise, a new instance is needed */
- aa = osnoise_init_tool("timerlat_aa");
- if (!aa)
- goto out_top;
- }
+ aa = osnoise_init_tool("timerlat_aa");
+ if (!aa)
+ goto out_top;
retval = timerlat_aa_init(aa, params->dump_tasks);
if (retval) {
*/
if (params->trace_output)
trace_instance_start(&record->trace);
- if (!params->no_aa && aa != top)
+ if (!params->no_aa)
trace_instance_start(&aa->trace);
- trace_instance_start(trace);
+ if (no_bpf) {
+ trace_instance_start(trace);
+ } else {
+ retval = timerlat_bpf_attach();
+ if (retval) {
+ err_msg("Error attaching BPF program\n");
+ goto out_top;
+ }
+ }
top->start_time = time(NULL);
timerlat_top_set_signals(params);
- while (!stop_tracing) {
- sleep(params->sleep_time);
+ if (no_bpf)
+ retval = timerlat_top_main_loop(top, record, params, ¶ms_u);
+ else
+ retval = timerlat_top_bpf_main_loop(top, record, params, ¶ms_u);
- if (params->aa_only && !osnoise_trace_is_off(top, record))
- continue;
+ if (retval)
+ goto out_top;
- retval = tracefs_iterate_raw_events(trace->tep,
- trace->inst,
- NULL,
- 0,
- collect_registered_events,
- trace);
- if (retval < 0) {
- err_msg("Error iterating on events\n");
- goto out_top;
- }
-
- if (!params->quiet)
- timerlat_print_stats(params, top);
-
- if (osnoise_trace_is_off(top, record))
- break;
-
- /* is there still any user-threads ? */
- if (params->user_workload) {
- if (params_u.stopped_running) {
- debug_msg("timerlat user space threads stopped!\n");
- break;
- }
- }
- }
+ if (!no_bpf)
+ timerlat_bpf_detach();
if (params->user_workload && !params_u.stopped_running) {
params_u.should_run = 0;