Skip to content

Commit cdca4f4

Browse files
Daniel Bristot de Oliveirarostedt
authored andcommitted
rtla/timerlat_top: Add timerlat user-space support
Add the support for running timerlat threads in user-space. In this mode, enabled with -u/--user-threads, timerlat dispatches user-space processes that will loop in the timerlat_fd, measuring the overhead for going to user-space and then returning to the kernel - in addition to the existing measurements. Here is one example of the tool's output with -u enabled: $ sudo timerlat top -u -d 600 -q Timer Latency 0 00:10:01 | IRQ Timer Latency (us) | Thread Timer Latency (us) | Ret user Timer Latency (us) CPU COUNT | cur min avg max | cur min avg max | cur min avg max 0 #600001 | 0 0 0 3 | 2 1 2 9 | 3 2 3 15 1 #600001 | 0 0 0 2 | 2 1 2 13 | 2 2 3 18 2 #600001 | 0 0 0 10 | 2 1 2 16 | 3 2 3 20 3 #600001 | 0 0 0 7 | 2 1 2 10 | 3 2 3 11 4 #600000 | 0 0 0 16 | 2 1 2 41 | 3 2 3 58 5 #600000 | 0 0 0 3 | 2 1 2 10 | 3 2 3 13 6 #600000 | 0 0 0 5 | 2 1 2 7 | 3 2 3 10 7 #600000 | 0 0 0 1 | 2 1 2 7 | 3 2 3 10 The tuning setup like -p or -C work for the user-space threads as well. Link: https://lkml.kernel.org/r/758ad2292a0a1d884138d08219e1a0f572d257a2.1686066600.git.bristot@kernel.org Cc: William White <[email protected]> Cc: Jonathan Corbet <[email protected]> Tested-by: Juri Lelli <[email protected]> Signed-off-by: Daniel Bristot de Oliveira <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 7bc4d30 commit cdca4f4

File tree

7 files changed

+474
-6
lines changed

7 files changed

+474
-6
lines changed

tools/tracing/rtla/src/osnoise.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,67 @@ static void osnoise_put_irq_disable(struct osnoise_context *context)
841841
context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
842842
}
843843

844+
static int osnoise_get_workload(struct osnoise_context *context)
845+
{
846+
if (context->opt_workload != OSNOISE_OPTION_INIT_VAL)
847+
return context->opt_workload;
848+
849+
if (context->orig_opt_workload != OSNOISE_OPTION_INIT_VAL)
850+
return context->orig_opt_workload;
851+
852+
context->orig_opt_workload = osnoise_options_get_option("OSNOISE_WORKLOAD");
853+
854+
return context->orig_opt_workload;
855+
}
856+
857+
int osnoise_set_workload(struct osnoise_context *context, bool onoff)
858+
{
859+
int opt_workload = osnoise_get_workload(context);
860+
int retval;
861+
862+
if (opt_workload == OSNOISE_OPTION_INIT_VAL)
863+
return -1;
864+
865+
if (opt_workload == onoff)
866+
return 0;
867+
868+
retval = osnoise_options_set_option("OSNOISE_WORKLOAD", onoff);
869+
if (retval < 0)
870+
return -1;
871+
872+
context->opt_workload = onoff;
873+
874+
return 0;
875+
}
876+
877+
static void osnoise_restore_workload(struct osnoise_context *context)
878+
{
879+
int retval;
880+
881+
if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL)
882+
return;
883+
884+
if (context->orig_opt_workload == context->opt_workload)
885+
goto out_done;
886+
887+
retval = osnoise_options_set_option("OSNOISE_WORKLOAD", context->orig_opt_workload);
888+
if (retval < 0)
889+
err_msg("Could not restore original OSNOISE_WORKLOAD option\n");
890+
891+
out_done:
892+
context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
893+
}
894+
895+
static void osnoise_put_workload(struct osnoise_context *context)
896+
{
897+
osnoise_restore_workload(context);
898+
899+
if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL)
900+
return;
901+
902+
context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
903+
}
904+
844905
/*
845906
* enable_osnoise - enable osnoise tracer in the trace_instance
846907
*/
@@ -908,6 +969,9 @@ struct osnoise_context *osnoise_context_alloc(void)
908969
context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
909970
context->opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
910971

972+
context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
973+
context->opt_workload = OSNOISE_OPTION_INIT_VAL;
974+
911975
osnoise_get_context(context);
912976

913977
return context;
@@ -935,6 +999,7 @@ void osnoise_put_context(struct osnoise_context *context)
935999
osnoise_put_print_stack(context);
9361000
osnoise_put_tracing_thresh(context);
9371001
osnoise_put_irq_disable(context);
1002+
osnoise_put_workload(context);
9381003

9391004
free(context);
9401005
}

tools/tracing/rtla/src/osnoise.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ struct osnoise_context {
4242
/* -1 as init value because 0 is off */
4343
int orig_opt_irq_disable;
4444
int opt_irq_disable;
45+
46+
/* -1 as init value because 0 is off */
47+
int orig_opt_workload;
48+
int opt_workload;
4549
};
4650

4751
/*
@@ -84,6 +88,7 @@ int osnoise_set_print_stack(struct osnoise_context *context,
8488
long long print_stack);
8589

8690
int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff);
91+
int osnoise_set_workload(struct osnoise_context *context, bool onoff);
8792

8893
/*
8994
* osnoise_tool - osnoise based tool definition.

tools/tracing/rtla/src/timerlat_top.c

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
#include <time.h>
1414
#include <errno.h>
1515
#include <sched.h>
16+
#include <pthread.h>
1617

1718
#include "utils.h"
1819
#include "osnoise.h"
1920
#include "timerlat.h"
2021
#include "timerlat_aa.h"
22+
#include "timerlat_u.h"
2123

2224
struct timerlat_top_params {
2325
char *cpus;
@@ -40,6 +42,7 @@ struct timerlat_top_params {
4042
int dump_tasks;
4143
int cgroup;
4244
int hk_cpus;
45+
int user_top;
4346
cpu_set_t hk_cpu_set;
4447
struct sched_attr sched_param;
4548
struct trace_events *events;
@@ -48,6 +51,7 @@ struct timerlat_top_params {
4851
struct timerlat_top_cpu {
4952
int irq_count;
5053
int thread_count;
54+
int user_count;
5155

5256
unsigned long long cur_irq;
5357
unsigned long long min_irq;
@@ -58,6 +62,11 @@ struct timerlat_top_cpu {
5862
unsigned long long min_thread;
5963
unsigned long long sum_thread;
6064
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;
6170
};
6271

6372
struct timerlat_top_data {
@@ -98,6 +107,7 @@ static struct timerlat_top_data *timerlat_alloc_top(int nr_cpus)
98107
for (cpu = 0; cpu < nr_cpus; cpu++) {
99108
data->cpu_data[cpu].min_irq = ~0;
100109
data->cpu_data[cpu].min_thread = ~0;
110+
data->cpu_data[cpu].min_user = ~0;
101111
}
102112

103113
return data;
@@ -124,12 +134,18 @@ timerlat_top_update(struct osnoise_tool *tool, int cpu,
124134
update_min(&cpu_data->min_irq, &latency);
125135
update_sum(&cpu_data->sum_irq, &latency);
126136
update_max(&cpu_data->max_irq, &latency);
127-
} else {
137+
} else if (thread == 1) {
128138
cpu_data->thread_count++;
129139
cpu_data->cur_thread = latency;
130140
update_min(&cpu_data->min_thread, &latency);
131141
update_sum(&cpu_data->sum_thread, &latency);
132142
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);
133149
}
134150
}
135151

@@ -172,15 +188,25 @@ static void timerlat_top_header(struct osnoise_tool *top)
172188

173189
trace_seq_printf(s, "\033[2;37;40m");
174190
trace_seq_printf(s, " Timer Latency ");
191+
if (params->user_top)
192+
trace_seq_printf(s, " ");
175193
trace_seq_printf(s, "\033[0;0;0m");
176194
trace_seq_printf(s, "\n");
177195

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,
179197
params->output_divisor == 1 ? "ns" : "us",
180198
params->output_divisor == 1 ? "ns" : "us");
181199

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");
182206
trace_seq_printf(s, "\033[2;30;47m");
183207
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");
184210
trace_seq_printf(s, "\033[0;0;0m");
185211
trace_seq_printf(s, "\n");
186212
}
@@ -233,7 +259,27 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu)
233259
trace_seq_printf(s, "%9llu ", cpu_data->min_thread / divisor);
234260
trace_seq_printf(s, "%9llu ",
235261
(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);
237283
}
238284
}
239285

@@ -288,7 +334,7 @@ static void timerlat_top_usage(char *usage)
288334
"",
289335
" usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\",
290336
" [[-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]",
292338
"",
293339
" -h/--help: print this menu",
294340
" -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)
317363
" f:prio - use SCHED_FIFO with prio",
318364
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
319365
" in nanoseconds",
366+
" -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads",
320367
NULL,
321368
};
322369

@@ -371,6 +418,7 @@ static struct timerlat_top_params
371418
{"stack", required_argument, 0, 's'},
372419
{"thread", required_argument, 0, 'T'},
373420
{"trace", optional_argument, 0, 't'},
421+
{"user-threads", no_argument, 0, 'u'},
374422
{"trigger", required_argument, 0, '0'},
375423
{"filter", required_argument, 0, '1'},
376424
{"dma-latency", required_argument, 0, '2'},
@@ -383,7 +431,7 @@ static struct timerlat_top_params
383431
/* getopt_long stores the option index here. */
384432
int option_index = 0;
385433

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:",
387435
long_options, &option_index);
388436

389437
/* detect the end of the options. */
@@ -498,6 +546,9 @@ static struct timerlat_top_params
498546
else
499547
params->trace_output = "timerlat_trace.txt";
500548

549+
break;
550+
case 'u':
551+
params->user_top = true;
501552
break;
502553
case '0': /* trigger */
503554
if (params->events) {
@@ -563,6 +614,7 @@ static int
563614
timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *params)
564615
{
565616
int retval;
617+
int i;
566618

567619
if (!params->sleep_time)
568620
params->sleep_time = 1;
@@ -573,6 +625,9 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
573625
err_msg("Failed to apply CPUs config\n");
574626
goto out_err;
575627
}
628+
} else {
629+
for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++)
630+
CPU_SET(i, &params->monitored_cpus);
576631
}
577632

578633
if (params->stop_us) {
@@ -627,6 +682,14 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
627682
auto_house_keeping(&params->monitored_cpus);
628683
}
629684

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+
630693
return 0;
631694

632695
out_err:
@@ -687,10 +750,12 @@ int timerlat_top_main(int argc, char *argv[])
687750
{
688751
struct timerlat_top_params *params;
689752
struct osnoise_tool *record = NULL;
753+
struct timerlat_u_params params_u;
690754
struct osnoise_tool *top = NULL;
691755
struct osnoise_tool *aa = NULL;
692756
struct trace_instance *trace;
693757
int dma_latency_fd = -1;
758+
pthread_t timerlat_u;
694759
int return_value = 1;
695760
char *max_lat;
696761
int retval;
@@ -727,7 +792,7 @@ int timerlat_top_main(int argc, char *argv[])
727792
}
728793
}
729794

730-
if (params->cgroup) {
795+
if (params->cgroup && !params->user_top) {
731796
retval = set_comm_cgroup("timerlat/", params->cgroup_name);
732797
if (!retval) {
733798
err_msg("Failed to move threads to cgroup\n");
@@ -800,6 +865,25 @@ int timerlat_top_main(int argc, char *argv[])
800865
top->start_time = time(NULL);
801866
timerlat_top_set_signals(params);
802867

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+
803887
while (!stop_tracing) {
804888
sleep(params->sleep_time);
805889

@@ -823,6 +907,18 @@ int timerlat_top_main(int argc, char *argv[])
823907
if (trace_is_off(&top->trace, &record->trace))
824908
break;
825909

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);
826922
}
827923

828924
timerlat_print_stats(params, top);

0 commit comments

Comments
 (0)