13
13
#include <time.h>
14
14
#include <errno.h>
15
15
#include <sched.h>
16
+ #include <pthread.h>
16
17
17
18
#include "utils.h"
18
19
#include "osnoise.h"
19
20
#include "timerlat.h"
20
21
#include "timerlat_aa.h"
22
+ #include "timerlat_u.h"
21
23
22
24
struct timerlat_top_params {
23
25
char * cpus ;
@@ -40,6 +42,7 @@ struct timerlat_top_params {
40
42
int dump_tasks ;
41
43
int cgroup ;
42
44
int hk_cpus ;
45
+ int user_top ;
43
46
cpu_set_t hk_cpu_set ;
44
47
struct sched_attr sched_param ;
45
48
struct trace_events * events ;
@@ -48,6 +51,7 @@ struct timerlat_top_params {
48
51
struct timerlat_top_cpu {
49
52
int irq_count ;
50
53
int thread_count ;
54
+ int user_count ;
51
55
52
56
unsigned long long cur_irq ;
53
57
unsigned long long min_irq ;
@@ -58,6 +62,11 @@ struct timerlat_top_cpu {
58
62
unsigned long long min_thread ;
59
63
unsigned long long sum_thread ;
60
64
unsigned long long max_thread ;
65
+
66
+ unsigned long long cur_user ;
67
+ unsigned long long min_user ;
68
+ unsigned long long sum_user ;
69
+ unsigned long long max_user ;
61
70
};
62
71
63
72
struct timerlat_top_data {
@@ -98,6 +107,7 @@ static struct timerlat_top_data *timerlat_alloc_top(int nr_cpus)
98
107
for (cpu = 0 ; cpu < nr_cpus ; cpu ++ ) {
99
108
data -> cpu_data [cpu ].min_irq = ~0 ;
100
109
data -> cpu_data [cpu ].min_thread = ~0 ;
110
+ data -> cpu_data [cpu ].min_user = ~0 ;
101
111
}
102
112
103
113
return data ;
@@ -124,12 +134,18 @@ timerlat_top_update(struct osnoise_tool *tool, int cpu,
124
134
update_min (& cpu_data -> min_irq , & latency );
125
135
update_sum (& cpu_data -> sum_irq , & latency );
126
136
update_max (& cpu_data -> max_irq , & latency );
127
- } else {
137
+ } else if ( thread == 1 ) {
128
138
cpu_data -> thread_count ++ ;
129
139
cpu_data -> cur_thread = latency ;
130
140
update_min (& cpu_data -> min_thread , & latency );
131
141
update_sum (& cpu_data -> sum_thread , & latency );
132
142
update_max (& cpu_data -> max_thread , & latency );
143
+ } else {
144
+ cpu_data -> user_count ++ ;
145
+ cpu_data -> cur_user = latency ;
146
+ update_min (& cpu_data -> min_user , & latency );
147
+ update_sum (& cpu_data -> sum_user , & latency );
148
+ update_max (& cpu_data -> max_user , & latency );
133
149
}
134
150
}
135
151
@@ -172,15 +188,25 @@ static void timerlat_top_header(struct osnoise_tool *top)
172
188
173
189
trace_seq_printf (s , "\033[2;37;40m" );
174
190
trace_seq_printf (s , " Timer Latency " );
191
+ if (params -> user_top )
192
+ trace_seq_printf (s , " " );
175
193
trace_seq_printf (s , "\033[0;0;0m" );
176
194
trace_seq_printf (s , "\n" );
177
195
178
- trace_seq_printf (s , "%-6s | IRQ Timer Latency (%s) | Thread Timer Latency (%s)\n " , duration ,
196
+ trace_seq_printf (s , "%-6s | IRQ Timer Latency (%s) | Thread Timer Latency (%s)" , duration ,
179
197
params -> output_divisor == 1 ? "ns" : "us" ,
180
198
params -> output_divisor == 1 ? "ns" : "us" );
181
199
200
+ if (params -> user_top ) {
201
+ trace_seq_printf (s , " | Ret user Timer Latency (%s)" ,
202
+ params -> output_divisor == 1 ? "ns" : "us" );
203
+ }
204
+
205
+ trace_seq_printf (s , "\n" );
182
206
trace_seq_printf (s , "\033[2;30;47m" );
183
207
trace_seq_printf (s , "CPU COUNT | cur min avg max | cur min avg max" );
208
+ if (params -> user_top )
209
+ trace_seq_printf (s , " | cur min avg max" );
184
210
trace_seq_printf (s , "\033[0;0;0m" );
185
211
trace_seq_printf (s , "\n" );
186
212
}
@@ -233,7 +259,27 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu)
233
259
trace_seq_printf (s , "%9llu " , cpu_data -> min_thread / divisor );
234
260
trace_seq_printf (s , "%9llu " ,
235
261
(cpu_data -> sum_thread / cpu_data -> thread_count ) / divisor );
236
- trace_seq_printf (s , "%9llu\n" , cpu_data -> max_thread / divisor );
262
+ trace_seq_printf (s , "%9llu" , cpu_data -> max_thread / divisor );
263
+ }
264
+
265
+ if (!params -> user_top ) {
266
+ trace_seq_printf (s , "\n" );
267
+ return ;
268
+ }
269
+
270
+ trace_seq_printf (s , " |" );
271
+
272
+ if (!cpu_data -> user_count ) {
273
+ trace_seq_printf (s , " - " );
274
+ trace_seq_printf (s , " - " );
275
+ trace_seq_printf (s , " - " );
276
+ trace_seq_printf (s , " -\n" );
277
+ } else {
278
+ trace_seq_printf (s , "%9llu " , cpu_data -> cur_user / divisor );
279
+ trace_seq_printf (s , "%9llu " , cpu_data -> min_user / divisor );
280
+ trace_seq_printf (s , "%9llu " ,
281
+ (cpu_data -> sum_user / cpu_data -> user_count ) / divisor );
282
+ trace_seq_printf (s , "%9llu\n" , cpu_data -> max_user / divisor );
237
283
}
238
284
}
239
285
@@ -288,7 +334,7 @@ static void timerlat_top_usage(char *usage)
288
334
"" ,
289
335
" usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\" ,
290
336
" [[-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\" ,
291
- " [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]]" ,
337
+ " [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u] " ,
292
338
"" ,
293
339
" -h/--help: print this menu" ,
294
340
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit" ,
@@ -317,6 +363,7 @@ static void timerlat_top_usage(char *usage)
317
363
" f:prio - use SCHED_FIFO with prio" ,
318
364
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period" ,
319
365
" in nanoseconds" ,
366
+ " -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads" ,
320
367
NULL ,
321
368
};
322
369
@@ -371,6 +418,7 @@ static struct timerlat_top_params
371
418
{"stack" , required_argument , 0 , 's' },
372
419
{"thread" , required_argument , 0 , 'T' },
373
420
{"trace" , optional_argument , 0 , 't' },
421
+ {"user-threads" , no_argument , 0 , 'u' },
374
422
{"trigger" , required_argument , 0 , '0' },
375
423
{"filter" , required_argument , 0 , '1' },
376
424
{"dma-latency" , required_argument , 0 , '2' },
@@ -383,7 +431,7 @@ static struct timerlat_top_params
383
431
/* getopt_long stores the option index here. */
384
432
int option_index = 0 ;
385
433
386
- c = getopt_long (argc , argv , "a:c:C::d:De:hH:i:np:P:qs:t::T:0 :1:2:345:" ,
434
+ c = getopt_long (argc , argv , "a:c:C::d:De:hH:i:np:P:qs:t::T:u0 :1:2:345:" ,
387
435
long_options , & option_index );
388
436
389
437
/* detect the end of the options. */
@@ -498,6 +546,9 @@ static struct timerlat_top_params
498
546
else
499
547
params -> trace_output = "timerlat_trace.txt" ;
500
548
549
+ break ;
550
+ case 'u' :
551
+ params -> user_top = true;
501
552
break ;
502
553
case '0' : /* trigger */
503
554
if (params -> events ) {
@@ -563,6 +614,7 @@ static int
563
614
timerlat_top_apply_config (struct osnoise_tool * top , struct timerlat_top_params * params )
564
615
{
565
616
int retval ;
617
+ int i ;
566
618
567
619
if (!params -> sleep_time )
568
620
params -> sleep_time = 1 ;
@@ -573,6 +625,9 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
573
625
err_msg ("Failed to apply CPUs config\n" );
574
626
goto out_err ;
575
627
}
628
+ } else {
629
+ for (i = 0 ; i < sysconf (_SC_NPROCESSORS_CONF ); i ++ )
630
+ CPU_SET (i , & params -> monitored_cpus );
576
631
}
577
632
578
633
if (params -> stop_us ) {
@@ -627,6 +682,14 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
627
682
auto_house_keeping (& params -> monitored_cpus );
628
683
}
629
684
685
+ if (params -> user_top ) {
686
+ retval = osnoise_set_workload (top -> context , 0 );
687
+ if (retval ) {
688
+ err_msg ("Failed to set OSNOISE_WORKLOAD option\n" );
689
+ goto out_err ;
690
+ }
691
+ }
692
+
630
693
return 0 ;
631
694
632
695
out_err :
@@ -687,10 +750,12 @@ int timerlat_top_main(int argc, char *argv[])
687
750
{
688
751
struct timerlat_top_params * params ;
689
752
struct osnoise_tool * record = NULL ;
753
+ struct timerlat_u_params params_u ;
690
754
struct osnoise_tool * top = NULL ;
691
755
struct osnoise_tool * aa = NULL ;
692
756
struct trace_instance * trace ;
693
757
int dma_latency_fd = -1 ;
758
+ pthread_t timerlat_u ;
694
759
int return_value = 1 ;
695
760
char * max_lat ;
696
761
int retval ;
@@ -727,7 +792,7 @@ int timerlat_top_main(int argc, char *argv[])
727
792
}
728
793
}
729
794
730
- if (params -> cgroup ) {
795
+ if (params -> cgroup && ! params -> user_top ) {
731
796
retval = set_comm_cgroup ("timerlat/" , params -> cgroup_name );
732
797
if (!retval ) {
733
798
err_msg ("Failed to move threads to cgroup\n" );
@@ -800,6 +865,25 @@ int timerlat_top_main(int argc, char *argv[])
800
865
top -> start_time = time (NULL );
801
866
timerlat_top_set_signals (params );
802
867
868
+ if (params -> user_top ) {
869
+ /* rtla asked to stop */
870
+ params_u .should_run = 1 ;
871
+ /* all threads left */
872
+ params_u .stopped_running = 0 ;
873
+
874
+ params_u .set = & params -> monitored_cpus ;
875
+ if (params -> set_sched )
876
+ params_u .sched_param = & params -> sched_param ;
877
+ else
878
+ params_u .sched_param = NULL ;
879
+
880
+ params_u .cgroup_name = params -> cgroup_name ;
881
+
882
+ retval = pthread_create (& timerlat_u , NULL , timerlat_u_dispatcher , & params_u );
883
+ if (retval )
884
+ err_msg ("Error creating timerlat user-space threads\n" );
885
+ }
886
+
803
887
while (!stop_tracing ) {
804
888
sleep (params -> sleep_time );
805
889
@@ -823,6 +907,18 @@ int timerlat_top_main(int argc, char *argv[])
823
907
if (trace_is_off (& top -> trace , & record -> trace ))
824
908
break ;
825
909
910
+ /* is there still any user-threads ? */
911
+ if (params -> user_top ) {
912
+ if (params_u .stopped_running ) {
913
+ debug_msg ("timerlat user space threads stopped!\n" );
914
+ break ;
915
+ }
916
+ }
917
+ }
918
+
919
+ if (params -> user_top && !params_u .stopped_running ) {
920
+ params_u .should_run = 0 ;
921
+ sleep (1 );
826
922
}
827
923
828
924
timerlat_print_stats (params , top );
0 commit comments