Skip to content

Commit ed774f7

Browse files
Daniel Bristot de Oliveirarostedt
authored andcommitted
rtla/timerlat_hist: 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 hist -u -c 1-3 -d 600 # RTLA timerlat histogram # Time unit is microseconds (us) # Duration: 0 00:10:01 Index IRQ-001 Thr-001 Usr-001 IRQ-002 Thr-002 Usr-002 IRQ-003 Thr-003 Usr-003 0 477555 0 0 425287 0 0 474357 0 0 1 122385 7998 0 174616 1921 0 125412 3138 0 2 47 587376 492150 89 594717 447830 147 593463 454872 3 11 2549 101930 7 2682 145580 64 2530 138680 4 3 1954 2833 1 463 4917 11 548 4656 5 0 60 1037 0 138 1117 6 179 1130 6 0 26 1837 0 38 277 1 76 339 7 0 15 143 0 28 147 2 37 156 8 0 10 23 0 11 75 0 12 80 9 0 7 17 0 0 26 0 11 42 10 0 2 11 0 0 18 0 2 20 11 0 0 7 0 1 8 0 2 12 12 0 0 6 0 1 4 0 2 8 13 0 1 3 0 0 0 0 0 1 14 0 1 0 0 0 1 0 0 2 15 0 1 0 0 0 0 0 0 2 16 0 1 2 0 0 0 0 0 0 17 0 0 1 0 0 0 0 0 0 19 0 0 1 0 0 0 0 0 0 over: 0 0 0 0 0 0 0 0 0 count: 600001 600001 600001 600000 600000 600000 600000 600000 600000 min: 0 1 2 0 1 2 0 1 2 avg: 0 1 2 0 2 2 0 2 2 max: 4 16 19 4 12 14 7 12 15 The tuning setup like -p or -C work for the user-space threads as well. Link: https://lkml.kernel.org/r/b6a042d55003c4a67ff7dce28d96044b7044f00d.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 cdca4f4 commit ed774f7

File tree

1 file changed

+118
-11
lines changed

1 file changed

+118
-11
lines changed

tools/tracing/rtla/src/timerlat_hist.c

Lines changed: 118 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
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

2123
struct 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 {
5356
struct 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

6978
struct 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
*/
148167
static void
149168
timerlat_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
744807
static int
745808
timerlat_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

812886
out_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

Comments
 (0)