12
12
#include <stdio.h>
13
13
#include <time.h>
14
14
#include <sched.h>
15
+ #include <pthread.h>
15
16
16
17
#include "utils.h"
17
18
#include "osnoise.h"
18
19
#include "timerlat.h"
19
20
#include "timerlat_aa.h"
21
+ #include "timerlat_u.h"
20
22
21
23
struct timerlat_hist_params {
22
24
char * cpus ;
@@ -37,6 +39,7 @@ struct timerlat_hist_params {
37
39
int hk_cpus ;
38
40
int no_aa ;
39
41
int dump_tasks ;
42
+ int user_hist ;
40
43
cpu_set_t hk_cpu_set ;
41
44
struct sched_attr sched_param ;
42
45
struct trace_events * events ;
@@ -53,9 +56,11 @@ struct timerlat_hist_params {
53
56
struct timerlat_hist_cpu {
54
57
int * irq ;
55
58
int * thread ;
59
+ int * user ;
56
60
57
61
int irq_count ;
58
62
int thread_count ;
63
+ int user_count ;
59
64
60
65
unsigned long long min_irq ;
61
66
unsigned long long sum_irq ;
@@ -64,6 +69,10 @@ struct timerlat_hist_cpu {
64
69
unsigned long long min_thread ;
65
70
unsigned long long sum_thread ;
66
71
unsigned long long max_thread ;
72
+
73
+ unsigned long long min_user ;
74
+ unsigned long long sum_user ;
75
+ unsigned long long max_user ;
67
76
};
68
77
69
78
struct timerlat_hist_data {
@@ -88,6 +97,10 @@ timerlat_free_histogram(struct timerlat_hist_data *data)
88
97
89
98
if (data -> hist [cpu ].thread )
90
99
free (data -> hist [cpu ].thread );
100
+
101
+ if (data -> hist [cpu ].user )
102
+ free (data -> hist [cpu ].user );
103
+
91
104
}
92
105
93
106
/* one set of histograms per CPU */
@@ -124,15 +137,21 @@ static struct timerlat_hist_data
124
137
data -> hist [cpu ].irq = calloc (1 , sizeof (* data -> hist -> irq ) * (entries + 1 ));
125
138
if (!data -> hist [cpu ].irq )
126
139
goto cleanup ;
140
+
127
141
data -> hist [cpu ].thread = calloc (1 , sizeof (* data -> hist -> thread ) * (entries + 1 ));
128
142
if (!data -> hist [cpu ].thread )
129
143
goto cleanup ;
144
+
145
+ data -> hist [cpu ].user = calloc (1 , sizeof (* data -> hist -> user ) * (entries + 1 ));
146
+ if (!data -> hist [cpu ].user )
147
+ goto cleanup ;
130
148
}
131
149
132
150
/* set the min to max */
133
151
for (cpu = 0 ; cpu < nr_cpus ; cpu ++ ) {
134
152
data -> hist [cpu ].min_irq = ~0 ;
135
153
data -> hist [cpu ].min_thread = ~0 ;
154
+ data -> hist [cpu ].min_user = ~0 ;
136
155
}
137
156
138
157
return data ;
@@ -147,7 +166,7 @@ static struct timerlat_hist_data
147
166
*/
148
167
static void
149
168
timerlat_hist_update (struct osnoise_tool * tool , int cpu ,
150
- unsigned long long thread ,
169
+ unsigned long long context ,
151
170
unsigned long long latency )
152
171
{
153
172
struct timerlat_hist_params * params = tool -> params ;
@@ -162,18 +181,24 @@ timerlat_hist_update(struct osnoise_tool *tool, int cpu,
162
181
if (data -> bucket_size )
163
182
bucket = latency / data -> bucket_size ;
164
183
165
- if (!thread ) {
184
+ if (!context ) {
166
185
hist = data -> hist [cpu ].irq ;
167
186
data -> hist [cpu ].irq_count ++ ;
168
187
update_min (& data -> hist [cpu ].min_irq , & latency );
169
188
update_sum (& data -> hist [cpu ].sum_irq , & latency );
170
189
update_max (& data -> hist [cpu ].max_irq , & latency );
171
- } else {
190
+ } else if ( context == 1 ) {
172
191
hist = data -> hist [cpu ].thread ;
173
192
data -> hist [cpu ].thread_count ++ ;
174
193
update_min (& data -> hist [cpu ].min_thread , & latency );
175
194
update_sum (& data -> hist [cpu ].sum_thread , & latency );
176
195
update_max (& data -> hist [cpu ].max_thread , & latency );
196
+ } else { /* user */
197
+ hist = data -> hist [cpu ].user ;
198
+ data -> hist [cpu ].user_count ++ ;
199
+ update_min (& data -> hist [cpu ].min_user , & latency );
200
+ update_sum (& data -> hist [cpu ].sum_user , & latency );
201
+ update_max (& data -> hist [cpu ].max_user , & latency );
177
202
}
178
203
179
204
if (bucket < entries )
@@ -190,16 +215,16 @@ timerlat_hist_handler(struct trace_seq *s, struct tep_record *record,
190
215
struct tep_event * event , void * data )
191
216
{
192
217
struct trace_instance * trace = data ;
193
- unsigned long long thread , latency ;
218
+ unsigned long long context , latency ;
194
219
struct osnoise_tool * tool ;
195
220
int cpu = record -> cpu ;
196
221
197
222
tool = container_of (trace , struct osnoise_tool , trace );
198
223
199
- tep_get_field_val (s , event , "context" , record , & thread , 1 );
224
+ tep_get_field_val (s , event , "context" , record , & context , 1 );
200
225
tep_get_field_val (s , event , "timer_latency" , record , & latency , 1 );
201
226
202
- timerlat_hist_update (tool , cpu , thread , latency );
227
+ timerlat_hist_update (tool , cpu , context , latency );
203
228
204
229
return 0 ;
205
230
}
@@ -241,6 +266,9 @@ static void timerlat_hist_header(struct osnoise_tool *tool)
241
266
242
267
if (!params -> no_thread )
243
268
trace_seq_printf (s , " Thr-%03d" , cpu );
269
+
270
+ if (params -> user_hist )
271
+ trace_seq_printf (s , " Usr-%03d" , cpu );
244
272
}
245
273
trace_seq_printf (s , "\n" );
246
274
@@ -279,6 +307,10 @@ timerlat_print_summary(struct timerlat_hist_params *params,
279
307
if (!params -> no_thread )
280
308
trace_seq_printf (trace -> seq , "%9d " ,
281
309
data -> hist [cpu ].thread_count );
310
+
311
+ if (params -> user_hist )
312
+ trace_seq_printf (trace -> seq , "%9d " ,
313
+ data -> hist [cpu ].user_count );
282
314
}
283
315
trace_seq_printf (trace -> seq , "\n" );
284
316
@@ -299,6 +331,10 @@ timerlat_print_summary(struct timerlat_hist_params *params,
299
331
if (!params -> no_thread )
300
332
trace_seq_printf (trace -> seq , "%9llu " ,
301
333
data -> hist [cpu ].min_thread );
334
+
335
+ if (params -> user_hist )
336
+ trace_seq_printf (trace -> seq , "%9llu " ,
337
+ data -> hist [cpu ].min_user );
302
338
}
303
339
trace_seq_printf (trace -> seq , "\n" );
304
340
@@ -323,7 +359,15 @@ timerlat_print_summary(struct timerlat_hist_params *params,
323
359
if (!params -> no_thread ) {
324
360
if (data -> hist [cpu ].thread_count )
325
361
trace_seq_printf (trace -> seq , "%9llu " ,
326
- data -> hist [cpu ].sum_thread / data -> hist [cpu ].thread_count );
362
+ data -> hist [cpu ].sum_thread / data -> hist [cpu ].thread_count );
363
+ else
364
+ trace_seq_printf (trace -> seq , " - " );
365
+ }
366
+
367
+ if (params -> user_hist ) {
368
+ if (data -> hist [cpu ].user_count )
369
+ trace_seq_printf (trace -> seq , "%9llu " ,
370
+ data -> hist [cpu ].sum_user / data -> hist [cpu ].user_count );
327
371
else
328
372
trace_seq_printf (trace -> seq , " - " );
329
373
}
@@ -347,6 +391,10 @@ timerlat_print_summary(struct timerlat_hist_params *params,
347
391
if (!params -> no_thread )
348
392
trace_seq_printf (trace -> seq , "%9llu " ,
349
393
data -> hist [cpu ].max_thread );
394
+
395
+ if (params -> user_hist )
396
+ trace_seq_printf (trace -> seq , "%9llu " ,
397
+ data -> hist [cpu ].max_user );
350
398
}
351
399
trace_seq_printf (trace -> seq , "\n" );
352
400
trace_seq_do_printf (trace -> seq );
@@ -392,6 +440,12 @@ timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *t
392
440
data -> hist [cpu ].thread [bucket ]);
393
441
}
394
442
443
+ if (params -> user_hist ) {
444
+ total += data -> hist [cpu ].user [bucket ];
445
+ trace_seq_printf (trace -> seq , "%9d " ,
446
+ data -> hist [cpu ].user [bucket ]);
447
+ }
448
+
395
449
}
396
450
397
451
if (total == 0 && !params -> with_zeros ) {
@@ -421,6 +475,10 @@ timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *t
421
475
if (!params -> no_thread )
422
476
trace_seq_printf (trace -> seq , "%9d " ,
423
477
data -> hist [cpu ].thread [data -> entries ]);
478
+
479
+ if (params -> user_hist )
480
+ trace_seq_printf (trace -> seq , "%9d " ,
481
+ data -> hist [cpu ].user [data -> entries ]);
424
482
}
425
483
trace_seq_printf (trace -> seq , "\n" );
426
484
trace_seq_do_printf (trace -> seq );
@@ -441,7 +499,7 @@ static void timerlat_hist_usage(char *usage)
441
499
" usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\" ,
442
500
" [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\" ,
443
501
" [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\" ,
444
- " [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task]" ,
502
+ " [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u] " ,
445
503
"" ,
446
504
" -h/--help: print this menu" ,
447
505
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit" ,
@@ -476,6 +534,7 @@ static void timerlat_hist_usage(char *usage)
476
534
" f:prio - use SCHED_FIFO with prio" ,
477
535
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period" ,
478
536
" in nanoseconds" ,
537
+ " -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads" ,
479
538
NULL ,
480
539
};
481
540
@@ -532,6 +591,7 @@ static struct timerlat_hist_params
532
591
{"stack" , required_argument , 0 , 's' },
533
592
{"thread" , required_argument , 0 , 'T' },
534
593
{"trace" , optional_argument , 0 , 't' },
594
+ {"user-threads" , no_argument , 0 , 'u' },
535
595
{"event" , required_argument , 0 , 'e' },
536
596
{"no-irq" , no_argument , 0 , '0' },
537
597
{"no-thread" , no_argument , 0 , '1' },
@@ -550,7 +610,7 @@ static struct timerlat_hist_params
550
610
/* getopt_long stores the option index here. */
551
611
int option_index = 0 ;
552
612
553
- c = getopt_long (argc , argv , "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:0123456 :7:8:9\1" ,
613
+ c = getopt_long (argc , argv , "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:u0123456 :7:8:9\1" ,
554
614
long_options , & option_index );
555
615
556
616
/* detect the end of the options. */
@@ -660,6 +720,9 @@ static struct timerlat_hist_params
660
720
else
661
721
params -> trace_output = "timerlat_trace.txt" ;
662
722
break ;
723
+ case 'u' :
724
+ params -> user_hist = 1 ;
725
+ break ;
663
726
case '0' : /* no irq */
664
727
params -> no_irq = 1 ;
665
728
break ;
@@ -744,7 +807,7 @@ static struct timerlat_hist_params
744
807
static int
745
808
timerlat_hist_apply_config (struct osnoise_tool * tool , struct timerlat_hist_params * params )
746
809
{
747
- int retval ;
810
+ int retval , i ;
748
811
749
812
if (!params -> sleep_time )
750
813
params -> sleep_time = 1 ;
@@ -755,6 +818,9 @@ timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_param
755
818
err_msg ("Failed to apply CPUs config\n" );
756
819
goto out_err ;
757
820
}
821
+ } else {
822
+ for (i = 0 ; i < sysconf (_SC_NPROCESSORS_CONF ); i ++ )
823
+ CPU_SET (i , & params -> monitored_cpus );
758
824
}
759
825
760
826
if (params -> stop_us ) {
@@ -807,6 +873,14 @@ timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_param
807
873
auto_house_keeping (& params -> monitored_cpus );
808
874
}
809
875
876
+ if (params -> user_hist ) {
877
+ retval = osnoise_set_workload (tool -> context , 0 );
878
+ if (retval ) {
879
+ err_msg ("Failed to set OSNOISE_WORKLOAD option\n" );
880
+ goto out_err ;
881
+ }
882
+ }
883
+
810
884
return 0 ;
811
885
812
886
out_err :
@@ -867,11 +941,13 @@ int timerlat_hist_main(int argc, char *argv[])
867
941
{
868
942
struct timerlat_hist_params * params ;
869
943
struct osnoise_tool * record = NULL ;
944
+ struct timerlat_u_params params_u ;
870
945
struct osnoise_tool * tool = NULL ;
871
946
struct osnoise_tool * aa = NULL ;
872
947
struct trace_instance * trace ;
873
948
int dma_latency_fd = -1 ;
874
949
int return_value = 1 ;
950
+ pthread_t timerlat_u ;
875
951
int retval ;
876
952
877
953
params = timerlat_hist_parse_args (argc , argv );
@@ -906,7 +982,7 @@ int timerlat_hist_main(int argc, char *argv[])
906
982
}
907
983
}
908
984
909
- if (params -> cgroup ) {
985
+ if (params -> cgroup && ! params -> user_hist ) {
910
986
retval = set_comm_cgroup ("timerlat/" , params -> cgroup_name );
911
987
if (!retval ) {
912
988
err_msg ("Failed to move threads to cgroup\n" );
@@ -970,6 +1046,25 @@ int timerlat_hist_main(int argc, char *argv[])
970
1046
tool -> start_time = time (NULL );
971
1047
timerlat_hist_set_signals (params );
972
1048
1049
+ if (params -> user_hist ) {
1050
+ /* rtla asked to stop */
1051
+ params_u .should_run = 1 ;
1052
+ /* all threads left */
1053
+ params_u .stopped_running = 0 ;
1054
+
1055
+ params_u .set = & params -> monitored_cpus ;
1056
+ if (params -> set_sched )
1057
+ params_u .sched_param = & params -> sched_param ;
1058
+ else
1059
+ params_u .sched_param = NULL ;
1060
+
1061
+ params_u .cgroup_name = params -> cgroup_name ;
1062
+
1063
+ retval = pthread_create (& timerlat_u , NULL , timerlat_u_dispatcher , & params_u );
1064
+ if (retval )
1065
+ err_msg ("Error creating timerlat user-space threads\n" );
1066
+ }
1067
+
973
1068
while (!stop_tracing ) {
974
1069
sleep (params -> sleep_time );
975
1070
@@ -986,6 +1081,18 @@ int timerlat_hist_main(int argc, char *argv[])
986
1081
987
1082
if (trace_is_off (& tool -> trace , & record -> trace ))
988
1083
break ;
1084
+
1085
+ /* is there still any user-threads ? */
1086
+ if (params -> user_hist ) {
1087
+ if (params_u .stopped_running ) {
1088
+ debug_msg ("timerlat user-space threads stopped!\n" );
1089
+ break ;
1090
+ }
1091
+ }
1092
+ }
1093
+ if (params -> user_hist && !params_u .stopped_running ) {
1094
+ params_u .should_run = 0 ;
1095
+ sleep (1 );
989
1096
}
990
1097
991
1098
timerlat_print_stats (params , tool );
0 commit comments