1212#include <stdio.h>
1313#include <time.h>
1414#include <sched.h>
15+ #include <pthread.h>
1516
1617#include "utils.h"
1718#include "osnoise.h"
1819#include "timerlat.h"
1920#include "timerlat_aa.h"
21+ #include "timerlat_u.h"
2022
2123struct timerlat_hist_params {
2224 char * cpus ;
@@ -37,6 +39,7 @@ struct timerlat_hist_params {
3739 int hk_cpus ;
3840 int no_aa ;
3941 int dump_tasks ;
42+ int user_hist ;
4043 cpu_set_t hk_cpu_set ;
4144 struct sched_attr sched_param ;
4245 struct trace_events * events ;
@@ -53,9 +56,11 @@ struct timerlat_hist_params {
5356struct timerlat_hist_cpu {
5457 int * irq ;
5558 int * thread ;
59+ int * user ;
5660
5761 int irq_count ;
5862 int thread_count ;
63+ int user_count ;
5964
6065 unsigned long long min_irq ;
6166 unsigned long long sum_irq ;
@@ -64,6 +69,10 @@ struct timerlat_hist_cpu {
6469 unsigned long long min_thread ;
6570 unsigned long long sum_thread ;
6671 unsigned long long max_thread ;
72+
73+ unsigned long long min_user ;
74+ unsigned long long sum_user ;
75+ unsigned long long max_user ;
6776};
6877
6978struct timerlat_hist_data {
@@ -88,6 +97,10 @@ timerlat_free_histogram(struct timerlat_hist_data *data)
8897
8998 if (data -> hist [cpu ].thread )
9099 free (data -> hist [cpu ].thread );
100+
101+ if (data -> hist [cpu ].user )
102+ free (data -> hist [cpu ].user );
103+
91104 }
92105
93106 /* one set of histograms per CPU */
@@ -124,15 +137,21 @@ static struct timerlat_hist_data
124137 data -> hist [cpu ].irq = calloc (1 , sizeof (* data -> hist -> irq ) * (entries + 1 ));
125138 if (!data -> hist [cpu ].irq )
126139 goto cleanup ;
140+
127141 data -> hist [cpu ].thread = calloc (1 , sizeof (* data -> hist -> thread ) * (entries + 1 ));
128142 if (!data -> hist [cpu ].thread )
129143 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 ;
130148 }
131149
132150 /* set the min to max */
133151 for (cpu = 0 ; cpu < nr_cpus ; cpu ++ ) {
134152 data -> hist [cpu ].min_irq = ~0 ;
135153 data -> hist [cpu ].min_thread = ~0 ;
154+ data -> hist [cpu ].min_user = ~0 ;
136155 }
137156
138157 return data ;
@@ -147,7 +166,7 @@ static struct timerlat_hist_data
147166 */
148167static void
149168timerlat_hist_update (struct osnoise_tool * tool , int cpu ,
150- unsigned long long thread ,
169+ unsigned long long context ,
151170 unsigned long long latency )
152171{
153172 struct timerlat_hist_params * params = tool -> params ;
@@ -162,18 +181,24 @@ timerlat_hist_update(struct osnoise_tool *tool, int cpu,
162181 if (data -> bucket_size )
163182 bucket = latency / data -> bucket_size ;
164183
165- if (!thread ) {
184+ if (!context ) {
166185 hist = data -> hist [cpu ].irq ;
167186 data -> hist [cpu ].irq_count ++ ;
168187 update_min (& data -> hist [cpu ].min_irq , & latency );
169188 update_sum (& data -> hist [cpu ].sum_irq , & latency );
170189 update_max (& data -> hist [cpu ].max_irq , & latency );
171- } else {
190+ } else if ( context == 1 ) {
172191 hist = data -> hist [cpu ].thread ;
173192 data -> hist [cpu ].thread_count ++ ;
174193 update_min (& data -> hist [cpu ].min_thread , & latency );
175194 update_sum (& data -> hist [cpu ].sum_thread , & latency );
176195 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 );
177202 }
178203
179204 if (bucket < entries )
@@ -190,16 +215,16 @@ timerlat_hist_handler(struct trace_seq *s, struct tep_record *record,
190215 struct tep_event * event , void * data )
191216{
192217 struct trace_instance * trace = data ;
193- unsigned long long thread , latency ;
218+ unsigned long long context , latency ;
194219 struct osnoise_tool * tool ;
195220 int cpu = record -> cpu ;
196221
197222 tool = container_of (trace , struct osnoise_tool , trace );
198223
199- tep_get_field_val (s , event , "context" , record , & thread , 1 );
224+ tep_get_field_val (s , event , "context" , record , & context , 1 );
200225 tep_get_field_val (s , event , "timer_latency" , record , & latency , 1 );
201226
202- timerlat_hist_update (tool , cpu , thread , latency );
227+ timerlat_hist_update (tool , cpu , context , latency );
203228
204229 return 0 ;
205230}
@@ -241,6 +266,9 @@ static void timerlat_hist_header(struct osnoise_tool *tool)
241266
242267 if (!params -> no_thread )
243268 trace_seq_printf (s , " Thr-%03d" , cpu );
269+
270+ if (params -> user_hist )
271+ trace_seq_printf (s , " Usr-%03d" , cpu );
244272 }
245273 trace_seq_printf (s , "\n" );
246274
@@ -279,6 +307,10 @@ timerlat_print_summary(struct timerlat_hist_params *params,
279307 if (!params -> no_thread )
280308 trace_seq_printf (trace -> seq , "%9d " ,
281309 data -> hist [cpu ].thread_count );
310+
311+ if (params -> user_hist )
312+ trace_seq_printf (trace -> seq , "%9d " ,
313+ data -> hist [cpu ].user_count );
282314 }
283315 trace_seq_printf (trace -> seq , "\n" );
284316
@@ -299,6 +331,10 @@ timerlat_print_summary(struct timerlat_hist_params *params,
299331 if (!params -> no_thread )
300332 trace_seq_printf (trace -> seq , "%9llu " ,
301333 data -> hist [cpu ].min_thread );
334+
335+ if (params -> user_hist )
336+ trace_seq_printf (trace -> seq , "%9llu " ,
337+ data -> hist [cpu ].min_user );
302338 }
303339 trace_seq_printf (trace -> seq , "\n" );
304340
@@ -323,7 +359,15 @@ timerlat_print_summary(struct timerlat_hist_params *params,
323359 if (!params -> no_thread ) {
324360 if (data -> hist [cpu ].thread_count )
325361 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 );
327371 else
328372 trace_seq_printf (trace -> seq , " - " );
329373 }
@@ -347,6 +391,10 @@ timerlat_print_summary(struct timerlat_hist_params *params,
347391 if (!params -> no_thread )
348392 trace_seq_printf (trace -> seq , "%9llu " ,
349393 data -> hist [cpu ].max_thread );
394+
395+ if (params -> user_hist )
396+ trace_seq_printf (trace -> seq , "%9llu " ,
397+ data -> hist [cpu ].max_user );
350398 }
351399 trace_seq_printf (trace -> seq , "\n" );
352400 trace_seq_do_printf (trace -> seq );
@@ -392,6 +440,12 @@ timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *t
392440 data -> hist [cpu ].thread [bucket ]);
393441 }
394442
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+
395449 }
396450
397451 if (total == 0 && !params -> with_zeros ) {
@@ -421,6 +475,10 @@ timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *t
421475 if (!params -> no_thread )
422476 trace_seq_printf (trace -> seq , "%9d " ,
423477 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 ]);
424482 }
425483 trace_seq_printf (trace -> seq , "\n" );
426484 trace_seq_do_printf (trace -> seq );
@@ -441,7 +499,7 @@ static void timerlat_hist_usage(char *usage)
441499 " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\" ,
442500 " [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\" ,
443501 " [-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] " ,
445503 "" ,
446504 " -h/--help: print this menu" ,
447505 " -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)
476534 " f:prio - use SCHED_FIFO with prio" ,
477535 " d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period" ,
478536 " in nanoseconds" ,
537+ " -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads" ,
479538 NULL ,
480539 };
481540
@@ -532,6 +591,7 @@ static struct timerlat_hist_params
532591 {"stack" , required_argument , 0 , 's' },
533592 {"thread" , required_argument , 0 , 'T' },
534593 {"trace" , optional_argument , 0 , 't' },
594+ {"user-threads" , no_argument , 0 , 'u' },
535595 {"event" , required_argument , 0 , 'e' },
536596 {"no-irq" , no_argument , 0 , '0' },
537597 {"no-thread" , no_argument , 0 , '1' },
@@ -550,7 +610,7 @@ static struct timerlat_hist_params
550610 /* getopt_long stores the option index here. */
551611 int option_index = 0 ;
552612
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" ,
554614 long_options , & option_index );
555615
556616 /* detect the end of the options. */
@@ -660,6 +720,9 @@ static struct timerlat_hist_params
660720 else
661721 params -> trace_output = "timerlat_trace.txt" ;
662722 break ;
723+ case 'u' :
724+ params -> user_hist = 1 ;
725+ break ;
663726 case '0' : /* no irq */
664727 params -> no_irq = 1 ;
665728 break ;
@@ -744,7 +807,7 @@ static struct timerlat_hist_params
744807static int
745808timerlat_hist_apply_config (struct osnoise_tool * tool , struct timerlat_hist_params * params )
746809{
747- int retval ;
810+ int retval , i ;
748811
749812 if (!params -> sleep_time )
750813 params -> sleep_time = 1 ;
@@ -755,6 +818,9 @@ timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_param
755818 err_msg ("Failed to apply CPUs config\n" );
756819 goto out_err ;
757820 }
821+ } else {
822+ for (i = 0 ; i < sysconf (_SC_NPROCESSORS_CONF ); i ++ )
823+ CPU_SET (i , & params -> monitored_cpus );
758824 }
759825
760826 if (params -> stop_us ) {
@@ -807,6 +873,14 @@ timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_param
807873 auto_house_keeping (& params -> monitored_cpus );
808874 }
809875
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+
810884 return 0 ;
811885
812886out_err :
@@ -867,11 +941,13 @@ int timerlat_hist_main(int argc, char *argv[])
867941{
868942 struct timerlat_hist_params * params ;
869943 struct osnoise_tool * record = NULL ;
944+ struct timerlat_u_params params_u ;
870945 struct osnoise_tool * tool = NULL ;
871946 struct osnoise_tool * aa = NULL ;
872947 struct trace_instance * trace ;
873948 int dma_latency_fd = -1 ;
874949 int return_value = 1 ;
950+ pthread_t timerlat_u ;
875951 int retval ;
876952
877953 params = timerlat_hist_parse_args (argc , argv );
@@ -906,7 +982,7 @@ int timerlat_hist_main(int argc, char *argv[])
906982 }
907983 }
908984
909- if (params -> cgroup ) {
985+ if (params -> cgroup && ! params -> user_hist ) {
910986 retval = set_comm_cgroup ("timerlat/" , params -> cgroup_name );
911987 if (!retval ) {
912988 err_msg ("Failed to move threads to cgroup\n" );
@@ -970,6 +1046,25 @@ int timerlat_hist_main(int argc, char *argv[])
9701046 tool -> start_time = time (NULL );
9711047 timerlat_hist_set_signals (params );
9721048
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+
9731068 while (!stop_tracing ) {
9741069 sleep (params -> sleep_time );
9751070
@@ -986,6 +1081,18 @@ int timerlat_hist_main(int argc, char *argv[])
9861081
9871082 if (trace_is_off (& tool -> trace , & record -> trace ))
9881083 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 );
9891096 }
9901097
9911098 timerlat_print_stats (params , tool );
0 commit comments