18
18
#include "timerlat.h"
19
19
#include "timerlat_aa.h"
20
20
#include "timerlat_u.h"
21
+ #include "timerlat_bpf.h"
21
22
22
23
struct timerlat_top_cpu {
23
24
unsigned long long irq_count ;
@@ -181,6 +182,76 @@ timerlat_top_handler(struct trace_seq *s, struct tep_record *record,
181
182
return 0 ;
182
183
}
183
184
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
+
184
255
/*
185
256
* timerlat_top_header - print the header of the tool output
186
257
*/
@@ -894,6 +965,111 @@ timerlat_top_set_signals(struct timerlat_params *params)
894
965
}
895
966
}
896
967
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
+
897
1073
int timerlat_top_main (int argc , char * argv [])
898
1074
{
899
1075
struct timerlat_params * params ;
@@ -908,6 +1084,7 @@ int timerlat_top_main(int argc, char *argv[])
908
1084
char * max_lat ;
909
1085
int retval ;
910
1086
int nr_cpus , i ;
1087
+ bool no_bpf = false;
911
1088
912
1089
params = timerlat_top_parse_args (argc , argv );
913
1090
if (!params )
@@ -933,6 +1110,23 @@ int timerlat_top_main(int argc, char *argv[])
933
1110
*/
934
1111
top_inst = trace ;
935
1112
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
+ }
936
1130
937
1131
retval = enable_timerlat (trace );
938
1132
if (retval ) {
@@ -1007,15 +1201,9 @@ int timerlat_top_main(int argc, char *argv[])
1007
1201
}
1008
1202
1009
1203
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 ;
1019
1207
1020
1208
retval = timerlat_aa_init (aa , params -> dump_tasks );
1021
1209
if (retval ) {
@@ -1066,44 +1254,31 @@ int timerlat_top_main(int argc, char *argv[])
1066
1254
*/
1067
1255
if (params -> trace_output )
1068
1256
trace_instance_start (& record -> trace );
1069
- if (!params -> no_aa && aa != top )
1257
+ if (!params -> no_aa )
1070
1258
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
+ }
1072
1268
1073
1269
top -> start_time = time (NULL );
1074
1270
timerlat_top_set_signals (params );
1075
1271
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 );
1078
1276
1079
- if (params -> aa_only && ! osnoise_trace_is_off ( top , record ) )
1080
- continue ;
1277
+ if (retval )
1278
+ goto out_top ;
1081
1279
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 ();
1107
1282
1108
1283
if (params -> user_workload && !params_u .stopped_running ) {
1109
1284
params_u .should_run = 0 ;
0 commit comments