Skip to content

Commit 9a82a3f

Browse files
lenticularis39rostedt
authored andcommitted
rtla/timerlat_top: Use BPF to collect samples
Collect samples using BPF program instead of pulling them from tracefs. If the osnoise:timerlat_sample tracepoint is unavailable or the BPF program fails to load for whatever reason, rtla falls back to the old implementation. The collection of samples using the BPF program is fully self-contained and requires no activity of the userspace part of rtla during the measurement. Thus, rtla only pulls the summary from the BPF map and displays it every second, improving the performance. In --aa-only mode, the BPF program does not collect any data and only signalizes the end of tracing to userspace. An optimization that re-used the main trace instance for auto-analysis in aa-only mode was dropped, as rtla no longer turns tracing on in the main trace instance, making it useless for auto-analysis. Cc: John Kacur <[email protected]> Cc: Luis Goncalves <[email protected]> Cc: Gabriele Monaco <[email protected]> Cc: Clark Williams <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Tomas Glozar <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 1892380 commit 9a82a3f

File tree

1 file changed

+215
-40
lines changed

1 file changed

+215
-40
lines changed

tools/tracing/rtla/src/timerlat_top.c

Lines changed: 215 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "timerlat.h"
1919
#include "timerlat_aa.h"
2020
#include "timerlat_u.h"
21+
#include "timerlat_bpf.h"
2122

2223
struct timerlat_top_cpu {
2324
unsigned long long irq_count;
@@ -181,6 +182,76 @@ timerlat_top_handler(struct trace_seq *s, struct tep_record *record,
181182
return 0;
182183
}
183184

185+
/*
186+
* timerlat_top_bpf_pull_data - copy data from BPF maps into userspace
187+
*/
188+
static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
189+
{
190+
struct timerlat_top_data *data = tool->data;
191+
int i, err;
192+
long long value_irq[data->nr_cpus],
193+
value_thread[data->nr_cpus],
194+
value_user[data->nr_cpus];
195+
196+
/* Pull summary */
197+
err = timerlat_bpf_get_summary_value(SUMMARY_CURRENT,
198+
value_irq, value_thread, value_user,
199+
data->nr_cpus);
200+
if (err)
201+
return err;
202+
for (i = 0; i < data->nr_cpus; i++) {
203+
data->cpu_data[i].cur_irq = value_irq[i];
204+
data->cpu_data[i].cur_thread = value_thread[i];
205+
data->cpu_data[i].cur_user = value_user[i];
206+
}
207+
208+
err = timerlat_bpf_get_summary_value(SUMMARY_COUNT,
209+
value_irq, value_thread, value_user,
210+
data->nr_cpus);
211+
if (err)
212+
return err;
213+
for (i = 0; i < data->nr_cpus; i++) {
214+
data->cpu_data[i].irq_count = value_irq[i];
215+
data->cpu_data[i].thread_count = value_thread[i];
216+
data->cpu_data[i].user_count = value_user[i];
217+
}
218+
219+
err = timerlat_bpf_get_summary_value(SUMMARY_MIN,
220+
value_irq, value_thread, value_user,
221+
data->nr_cpus);
222+
if (err)
223+
return err;
224+
for (i = 0; i < data->nr_cpus; i++) {
225+
data->cpu_data[i].min_irq = value_irq[i];
226+
data->cpu_data[i].min_thread = value_thread[i];
227+
data->cpu_data[i].min_user = value_user[i];
228+
}
229+
230+
err = timerlat_bpf_get_summary_value(SUMMARY_MAX,
231+
value_irq, value_thread, value_user,
232+
data->nr_cpus);
233+
if (err)
234+
return err;
235+
for (i = 0; i < data->nr_cpus; i++) {
236+
data->cpu_data[i].max_irq = value_irq[i];
237+
data->cpu_data[i].max_thread = value_thread[i];
238+
data->cpu_data[i].max_user = value_user[i];
239+
}
240+
241+
err = timerlat_bpf_get_summary_value(SUMMARY_SUM,
242+
value_irq, value_thread, value_user,
243+
data->nr_cpus);
244+
if (err)
245+
return err;
246+
for (i = 0; i < data->nr_cpus; i++) {
247+
data->cpu_data[i].sum_irq = value_irq[i];
248+
data->cpu_data[i].sum_thread = value_thread[i];
249+
data->cpu_data[i].sum_user = value_user[i];
250+
}
251+
252+
return 0;
253+
}
254+
184255
/*
185256
* timerlat_top_header - print the header of the tool output
186257
*/
@@ -894,6 +965,111 @@ timerlat_top_set_signals(struct timerlat_params *params)
894965
}
895966
}
896967

968+
/*
969+
* timerlat_top_main_loop - main loop to process events
970+
*/
971+
static int
972+
timerlat_top_main_loop(struct osnoise_tool *top,
973+
struct osnoise_tool *record,
974+
struct timerlat_params *params,
975+
struct timerlat_u_params *params_u)
976+
{
977+
struct trace_instance *trace = &top->trace;
978+
int retval;
979+
980+
while (!stop_tracing) {
981+
sleep(params->sleep_time);
982+
983+
if (params->aa_only && !osnoise_trace_is_off(top, record))
984+
continue;
985+
986+
retval = tracefs_iterate_raw_events(trace->tep,
987+
trace->inst,
988+
NULL,
989+
0,
990+
collect_registered_events,
991+
trace);
992+
if (retval < 0) {
993+
err_msg("Error iterating on events\n");
994+
return retval;
995+
}
996+
997+
if (!params->quiet)
998+
timerlat_print_stats(params, top);
999+
1000+
if (osnoise_trace_is_off(top, record))
1001+
break;
1002+
1003+
/* is there still any user-threads ? */
1004+
if (params->user_workload) {
1005+
if (params_u->stopped_running) {
1006+
debug_msg("timerlat user space threads stopped!\n");
1007+
break;
1008+
}
1009+
}
1010+
}
1011+
1012+
return 0;
1013+
}
1014+
1015+
/*
1016+
* timerlat_top_bpf_main_loop - main loop to process events (BPF variant)
1017+
*/
1018+
static int
1019+
timerlat_top_bpf_main_loop(struct osnoise_tool *top,
1020+
struct osnoise_tool *record,
1021+
struct timerlat_params *params,
1022+
struct timerlat_u_params *params_u)
1023+
{
1024+
int retval, wait_retval;
1025+
1026+
if (params->aa_only) {
1027+
/* Auto-analysis only, just wait for stop tracing */
1028+
timerlat_bpf_wait(-1);
1029+
return 0;
1030+
}
1031+
1032+
if (params->quiet) {
1033+
/* Quiet mode: wait for stop and then, print results */
1034+
timerlat_bpf_wait(-1);
1035+
1036+
retval = timerlat_top_bpf_pull_data(top);
1037+
if (retval) {
1038+
err_msg("Error pulling BPF data\n");
1039+
return retval;
1040+
}
1041+
1042+
return 0;
1043+
}
1044+
1045+
/* Pull and display data in a loop */
1046+
while (!stop_tracing) {
1047+
wait_retval = timerlat_bpf_wait(params->sleep_time);
1048+
1049+
retval = timerlat_top_bpf_pull_data(top);
1050+
if (retval) {
1051+
err_msg("Error pulling BPF data\n");
1052+
return retval;
1053+
}
1054+
1055+
timerlat_print_stats(params, top);
1056+
1057+
if (wait_retval == 1)
1058+
/* Stopping requested by tracer */
1059+
break;
1060+
1061+
/* is there still any user-threads ? */
1062+
if (params->user_workload) {
1063+
if (params_u->stopped_running) {
1064+
debug_msg("timerlat user space threads stopped!\n");
1065+
break;
1066+
}
1067+
}
1068+
}
1069+
1070+
return 0;
1071+
}
1072+
8971073
int timerlat_top_main(int argc, char *argv[])
8981074
{
8991075
struct timerlat_params *params;
@@ -908,6 +1084,7 @@ int timerlat_top_main(int argc, char *argv[])
9081084
char *max_lat;
9091085
int retval;
9101086
int nr_cpus, i;
1087+
bool no_bpf = false;
9111088

9121089
params = timerlat_top_parse_args(argc, argv);
9131090
if (!params)
@@ -933,6 +1110,23 @@ int timerlat_top_main(int argc, char *argv[])
9331110
*/
9341111
top_inst = trace;
9351112

1113+
if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) {
1114+
debug_msg("RTLA_NO_BPF set, disabling BPF\n");
1115+
no_bpf = true;
1116+
}
1117+
1118+
if (!no_bpf && !tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) {
1119+
debug_msg("osnoise:timerlat_sample missing, disabling BPF\n");
1120+
no_bpf = true;
1121+
}
1122+
1123+
if (!no_bpf) {
1124+
retval = timerlat_bpf_init(params);
1125+
if (retval) {
1126+
debug_msg("Could not enable BPF\n");
1127+
no_bpf = true;
1128+
}
1129+
}
9361130

9371131
retval = enable_timerlat(trace);
9381132
if (retval) {
@@ -1007,15 +1201,9 @@ int timerlat_top_main(int argc, char *argv[])
10071201
}
10081202

10091203
if (!params->no_aa) {
1010-
if (params->aa_only) {
1011-
/* as top is not used for display, use it for aa */
1012-
aa = top;
1013-
} else {
1014-
/* otherwise, a new instance is needed */
1015-
aa = osnoise_init_tool("timerlat_aa");
1016-
if (!aa)
1017-
goto out_top;
1018-
}
1204+
aa = osnoise_init_tool("timerlat_aa");
1205+
if (!aa)
1206+
goto out_top;
10191207

10201208
retval = timerlat_aa_init(aa, params->dump_tasks);
10211209
if (retval) {
@@ -1066,44 +1254,31 @@ int timerlat_top_main(int argc, char *argv[])
10661254
*/
10671255
if (params->trace_output)
10681256
trace_instance_start(&record->trace);
1069-
if (!params->no_aa && aa != top)
1257+
if (!params->no_aa)
10701258
trace_instance_start(&aa->trace);
1071-
trace_instance_start(trace);
1259+
if (no_bpf) {
1260+
trace_instance_start(trace);
1261+
} else {
1262+
retval = timerlat_bpf_attach();
1263+
if (retval) {
1264+
err_msg("Error attaching BPF program\n");
1265+
goto out_top;
1266+
}
1267+
}
10721268

10731269
top->start_time = time(NULL);
10741270
timerlat_top_set_signals(params);
10751271

1076-
while (!stop_tracing) {
1077-
sleep(params->sleep_time);
1272+
if (no_bpf)
1273+
retval = timerlat_top_main_loop(top, record, params, &params_u);
1274+
else
1275+
retval = timerlat_top_bpf_main_loop(top, record, params, &params_u);
10781276

1079-
if (params->aa_only && !osnoise_trace_is_off(top, record))
1080-
continue;
1277+
if (retval)
1278+
goto out_top;
10811279

1082-
retval = tracefs_iterate_raw_events(trace->tep,
1083-
trace->inst,
1084-
NULL,
1085-
0,
1086-
collect_registered_events,
1087-
trace);
1088-
if (retval < 0) {
1089-
err_msg("Error iterating on events\n");
1090-
goto out_top;
1091-
}
1092-
1093-
if (!params->quiet)
1094-
timerlat_print_stats(params, top);
1095-
1096-
if (osnoise_trace_is_off(top, record))
1097-
break;
1098-
1099-
/* is there still any user-threads ? */
1100-
if (params->user_workload) {
1101-
if (params_u.stopped_running) {
1102-
debug_msg("timerlat user space threads stopped!\n");
1103-
break;
1104-
}
1105-
}
1106-
}
1280+
if (!no_bpf)
1281+
timerlat_bpf_detach();
11071282

11081283
if (params->user_workload && !params_u.stopped_running) {
11091284
params_u.should_run = 0;

0 commit comments

Comments
 (0)