rtla: Add the --warm-up option

On many cases, the results right after the startup are different
from the rest of the execution, biasing the results. For example,
on osnoise, the scheduler might take some time to adapt to the new
busy-loop workload.

Add the --warm-up <seconds> option, adding a warm-up phase (in
seconds) where the workload is set, but the results are discarded.

Link: https://lkml.kernel.org/r/e682d5ce5af90f123bd13220f63d5c3d118a92be.1713968967.git.bristot@kernel.org

Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Juri Lelli <juri.lelli@redhat.com>
Signed-off-by: default avatarDaniel Bristot de Oliveira <bristot@kernel.org>
parent 1462501c
...@@ -50,6 +50,10 @@ ...@@ -50,6 +50,10 @@
Set a *cgroup* to the tracer's threads. If the **-C** option is passed without arguments, the tracer's thread will inherit **rtla**'s *cgroup*. Otherwise, the threads will be placed on the *cgroup* passed to the option. Set a *cgroup* to the tracer's threads. If the **-C** option is passed without arguments, the tracer's thread will inherit **rtla**'s *cgroup*. Otherwise, the threads will be placed on the *cgroup* passed to the option.
**--warm-up** *s*
After starting the workload, let it run for *s* seconds before starting collecting the data, allowing the system to warm-up. Statistical data generated during warm-up is discarded.
**-h**, **--help** **-h**, **--help**
Print help menu. Print help menu.
...@@ -36,13 +36,13 @@ struct osnoise_hist_params { ...@@ -36,13 +36,13 @@ struct osnoise_hist_params {
cpu_set_t hk_cpu_set; cpu_set_t hk_cpu_set;
struct sched_attr sched_param; struct sched_attr sched_param;
struct trace_events *events; struct trace_events *events;
char no_header; char no_header;
char no_summary; char no_summary;
char no_index; char no_index;
char with_zeros; char with_zeros;
int bucket_size; int bucket_size;
int entries; int entries;
int warmup;
}; };
struct osnoise_hist_cpu { struct osnoise_hist_cpu {
...@@ -438,7 +438,7 @@ static void osnoise_hist_usage(char *usage) ...@@ -438,7 +438,7 @@ static void osnoise_hist_usage(char *usage)
" usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
" [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
" [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\", " [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\",
" [--no-index] [--with-zeros] [-C[=cgroup_name]]", " [--no-index] [--with-zeros] [-C[=cgroup_name]] [--warm-up]",
"", "",
" -h/--help: print this menu", " -h/--help: print this menu",
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
...@@ -468,6 +468,7 @@ static void osnoise_hist_usage(char *usage) ...@@ -468,6 +468,7 @@ static void osnoise_hist_usage(char *usage)
" f:prio - use SCHED_FIFO with prio", " f:prio - use SCHED_FIFO with prio",
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period", " d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
" in nanoseconds", " in nanoseconds",
" --warm-up: let the workload run for s seconds before collecting data",
NULL, NULL,
}; };
...@@ -531,13 +532,14 @@ static struct osnoise_hist_params ...@@ -531,13 +532,14 @@ static struct osnoise_hist_params
{"with-zeros", no_argument, 0, '3'}, {"with-zeros", no_argument, 0, '3'},
{"trigger", required_argument, 0, '4'}, {"trigger", required_argument, 0, '4'},
{"filter", required_argument, 0, '5'}, {"filter", required_argument, 0, '5'},
{"warm-up", required_argument, 0, '6'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
/* getopt_long stores the option index here. */ /* getopt_long stores the option index here. */
int option_index = 0; int option_index = 0;
c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:", c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:",
long_options, &option_index); long_options, &option_index);
/* detect the end of the options. */ /* detect the end of the options. */
...@@ -680,6 +682,9 @@ static struct osnoise_hist_params ...@@ -680,6 +682,9 @@ static struct osnoise_hist_params
osnoise_hist_usage("--filter requires a previous -e\n"); osnoise_hist_usage("--filter requires a previous -e\n");
} }
break; break;
case '6':
params->warmup = get_llong_from_str(optarg);
break;
default: default:
osnoise_hist_usage("Invalid option"); osnoise_hist_usage("Invalid option");
} }
...@@ -899,6 +904,25 @@ int osnoise_hist_main(int argc, char *argv[]) ...@@ -899,6 +904,25 @@ int osnoise_hist_main(int argc, char *argv[])
trace_instance_start(&record->trace); trace_instance_start(&record->trace);
trace_instance_start(trace); trace_instance_start(trace);
if (params->warmup > 0) {
debug_msg("Warming up for %d seconds\n", params->warmup);
sleep(params->warmup);
if (stop_tracing)
goto out_hist;
/*
* Clean up the buffer. The osnoise workload do not run
* with tracing off to avoid creating a performance penalty
* when not needed.
*/
retval = tracefs_instance_file_write(trace->inst, "trace", "");
if (retval < 0) {
debug_msg("Error cleaning up the buffer");
goto out_hist;
}
}
tool->start_time = time(NULL); tool->start_time = time(NULL);
osnoise_hist_set_signals(params); osnoise_hist_set_signals(params);
......
...@@ -40,6 +40,7 @@ struct osnoise_top_params { ...@@ -40,6 +40,7 @@ struct osnoise_top_params {
int set_sched; int set_sched;
int cgroup; int cgroup;
int hk_cpus; int hk_cpus;
int warmup;
cpu_set_t hk_cpu_set; cpu_set_t hk_cpu_set;
struct sched_attr sched_param; struct sched_attr sched_param;
struct trace_events *events; struct trace_events *events;
...@@ -282,7 +283,7 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage) ...@@ -282,7 +283,7 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage)
static const char * const msg[] = { static const char * const msg[] = {
" [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", " [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
" [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
" [-c cpu-list] [-H cpu-list] [-P priority] [-C[=cgroup_name]]", " [-c cpu-list] [-H cpu-list] [-P priority] [-C[=cgroup_name]] [--warm-up s]",
"", "",
" -h/--help: print this menu", " -h/--help: print this menu",
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
...@@ -307,6 +308,7 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage) ...@@ -307,6 +308,7 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage)
" f:prio - use SCHED_FIFO with prio", " f:prio - use SCHED_FIFO with prio",
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period", " d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
" in nanoseconds", " in nanoseconds",
" --warm-up s: let the workload run for s seconds before collecting data",
NULL, NULL,
}; };
...@@ -381,13 +383,14 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) ...@@ -381,13 +383,14 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
{"trace", optional_argument, 0, 't'}, {"trace", optional_argument, 0, 't'},
{"trigger", required_argument, 0, '0'}, {"trigger", required_argument, 0, '0'},
{"filter", required_argument, 0, '1'}, {"filter", required_argument, 0, '1'},
{"warm-up", required_argument, 0, '2'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
/* getopt_long stores the option index here. */ /* getopt_long stores the option index here. */
int option_index = 0; int option_index = 0;
c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:", c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:",
long_options, &option_index); long_options, &option_index);
/* Detect the end of the options. */ /* Detect the end of the options. */
...@@ -511,6 +514,9 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) ...@@ -511,6 +514,9 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
osnoise_top_usage(params, "--filter requires a previous -e\n"); osnoise_top_usage(params, "--filter requires a previous -e\n");
} }
break; break;
case '2':
params->warmup = get_llong_from_str(optarg);
break;
default: default:
osnoise_top_usage(params, "Invalid option"); osnoise_top_usage(params, "Invalid option");
} }
...@@ -732,6 +738,25 @@ int osnoise_top_main(int argc, char **argv) ...@@ -732,6 +738,25 @@ int osnoise_top_main(int argc, char **argv)
trace_instance_start(&record->trace); trace_instance_start(&record->trace);
trace_instance_start(trace); trace_instance_start(trace);
if (params->warmup > 0) {
debug_msg("Warming up for %d seconds\n", params->warmup);
sleep(params->warmup);
if (stop_tracing)
goto out_top;
/*
* Clean up the buffer. The osnoise workload do not run
* with tracing off to avoid creating a performance penalty
* when not needed.
*/
retval = tracefs_instance_file_write(trace->inst, "trace", "");
if (retval < 0) {
debug_msg("Error cleaning up the buffer");
goto out_top;
}
}
tool->start_time = time(NULL); tool->start_time = time(NULL);
osnoise_top_set_signals(params); osnoise_top_set_signals(params);
......
...@@ -52,6 +52,7 @@ struct timerlat_hist_params { ...@@ -52,6 +52,7 @@ struct timerlat_hist_params {
char with_zeros; char with_zeros;
int bucket_size; int bucket_size;
int entries; int entries;
int warmup;
}; };
struct timerlat_hist_cpu { struct timerlat_hist_cpu {
...@@ -628,6 +629,7 @@ static void timerlat_hist_usage(char *usage) ...@@ -628,6 +629,7 @@ static void timerlat_hist_usage(char *usage)
" [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\", " [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
" [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", " [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
" [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u]", " [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u]",
" [--warm-up s]",
"", "",
" -h/--help: print this menu", " -h/--help: print this menu",
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
...@@ -664,6 +666,7 @@ static void timerlat_hist_usage(char *usage) ...@@ -664,6 +666,7 @@ static void timerlat_hist_usage(char *usage)
" in nanoseconds", " in nanoseconds",
" -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads", " -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads",
" -U/--user-load: enable timerlat for user-defined user-space workload", " -U/--user-load: enable timerlat for user-defined user-space workload",
" --warm-up s: let the workload run for s seconds before collecting data",
NULL, NULL,
}; };
...@@ -738,13 +741,14 @@ static struct timerlat_hist_params ...@@ -738,13 +741,14 @@ static struct timerlat_hist_params
{"dma-latency", required_argument, 0, '8'}, {"dma-latency", required_argument, 0, '8'},
{"no-aa", no_argument, 0, '9'}, {"no-aa", no_argument, 0, '9'},
{"dump-task", no_argument, 0, '\1'}, {"dump-task", no_argument, 0, '\1'},
{"warm-up", required_argument, 0, '\2'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
/* getopt_long stores the option index here. */ /* getopt_long stores the option index here. */
int option_index = 0; int option_index = 0;
c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:uU0123456:7:8:9\1", c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:uU0123456:7:8:9\1\2:",
long_options, &option_index); long_options, &option_index);
/* detect the end of the options. */ /* detect the end of the options. */
...@@ -913,6 +917,9 @@ static struct timerlat_hist_params ...@@ -913,6 +917,9 @@ static struct timerlat_hist_params
case '\1': case '\1':
params->dump_tasks = 1; params->dump_tasks = 1;
break; break;
case '\2':
params->warmup = get_llong_from_str(optarg);
break;
default: default:
timerlat_hist_usage("Invalid option"); timerlat_hist_usage("Invalid option");
} }
...@@ -1167,22 +1174,6 @@ int timerlat_hist_main(int argc, char *argv[]) ...@@ -1167,22 +1174,6 @@ int timerlat_hist_main(int argc, char *argv[])
} }
} }
/*
* Start the tracers here, after having set all instances.
*
* Let the trace instance start first for the case of hitting a stop
* tracing while enabling other instances. The trace instance is the
* one with most valuable information.
*/
if (params->trace_output)
trace_instance_start(&record->trace);
if (!params->no_aa)
trace_instance_start(&aa->trace);
trace_instance_start(trace);
tool->start_time = time(NULL);
timerlat_hist_set_signals(params);
if (params->user_workload) { if (params->user_workload) {
/* rtla asked to stop */ /* rtla asked to stop */
params_u.should_run = 1; params_u.should_run = 1;
...@@ -1202,6 +1193,29 @@ int timerlat_hist_main(int argc, char *argv[]) ...@@ -1202,6 +1193,29 @@ int timerlat_hist_main(int argc, char *argv[])
err_msg("Error creating timerlat user-space threads\n"); err_msg("Error creating timerlat user-space threads\n");
} }
if (params->warmup > 0) {
debug_msg("Warming up for %d seconds\n", params->warmup);
sleep(params->warmup);
if (stop_tracing)
goto out_hist;
}
/*
* Start the tracers here, after having set all instances.
*
* Let the trace instance start first for the case of hitting a stop
* tracing while enabling other instances. The trace instance is the
* one with most valuable information.
*/
if (params->trace_output)
trace_instance_start(&record->trace);
if (!params->no_aa)
trace_instance_start(&aa->trace);
trace_instance_start(trace);
tool->start_time = time(NULL);
timerlat_hist_set_signals(params);
while (!stop_tracing) { while (!stop_tracing) {
sleep(params->sleep_time); sleep(params->sleep_time);
...@@ -1227,6 +1241,7 @@ int timerlat_hist_main(int argc, char *argv[]) ...@@ -1227,6 +1241,7 @@ int timerlat_hist_main(int argc, char *argv[])
} }
} }
} }
if (params->user_workload && !params_u.stopped_running) { if (params->user_workload && !params_u.stopped_running) {
params_u.should_run = 0; params_u.should_run = 0;
sleep(1); sleep(1);
......
...@@ -45,6 +45,7 @@ struct timerlat_top_params { ...@@ -45,6 +45,7 @@ struct timerlat_top_params {
int user_top; int user_top;
int user_workload; int user_workload;
int pretty_output; int pretty_output;
int warmup;
cpu_set_t hk_cpu_set; cpu_set_t hk_cpu_set;
struct sched_attr sched_param; struct sched_attr sched_param;
struct trace_events *events; struct trace_events *events;
...@@ -444,7 +445,7 @@ static void timerlat_top_usage(char *usage) ...@@ -444,7 +445,7 @@ static void timerlat_top_usage(char *usage)
"", "",
" usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\", " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\",
" [[-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\", " [[-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
" [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u]", " [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u] [--warm-up s]",
"", "",
" -h/--help: print this menu", " -h/--help: print this menu",
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
...@@ -475,6 +476,7 @@ static void timerlat_top_usage(char *usage) ...@@ -475,6 +476,7 @@ static void timerlat_top_usage(char *usage)
" in nanoseconds", " in nanoseconds",
" -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads", " -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads",
" -U/--user-load: enable timerlat for user-defined user-space workload", " -U/--user-load: enable timerlat for user-defined user-space workload",
" --warm-up s: let the workload run for s seconds before collecting data",
NULL, NULL,
}; };
...@@ -541,13 +543,14 @@ static struct timerlat_top_params ...@@ -541,13 +543,14 @@ static struct timerlat_top_params
{"no-aa", no_argument, 0, '3'}, {"no-aa", no_argument, 0, '3'},
{"dump-tasks", no_argument, 0, '4'}, {"dump-tasks", no_argument, 0, '4'},
{"aa-only", required_argument, 0, '5'}, {"aa-only", required_argument, 0, '5'},
{"warm-up", required_argument, 0, '6'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
/* getopt_long stores the option index here. */ /* getopt_long stores the option index here. */
int option_index = 0; int option_index = 0;
c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:np:P:qs:t::T:uU0:1:2:345:", c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:np:P:qs:t::T:uU0:1:2:345:6:",
long_options, &option_index); long_options, &option_index);
/* detect the end of the options. */ /* detect the end of the options. */
...@@ -704,6 +707,9 @@ static struct timerlat_top_params ...@@ -704,6 +707,9 @@ static struct timerlat_top_params
case '4': case '4':
params->dump_tasks = 1; params->dump_tasks = 1;
break; break;
case '6':
params->warmup = get_llong_from_str(optarg);
break;
default: default:
timerlat_top_usage("Invalid option"); timerlat_top_usage("Invalid option");
} }
...@@ -971,22 +977,6 @@ int timerlat_top_main(int argc, char *argv[]) ...@@ -971,22 +977,6 @@ int timerlat_top_main(int argc, char *argv[])
} }
} }
/*
* Start the tracers here, after having set all instances.
*
* Let the trace instance start first for the case of hitting a stop
* tracing while enabling other instances. The trace instance is the
* one with most valuable information.
*/
if (params->trace_output)
trace_instance_start(&record->trace);
if (!params->no_aa && aa != top)
trace_instance_start(&aa->trace);
trace_instance_start(trace);
top->start_time = time(NULL);
timerlat_top_set_signals(params);
if (params->user_workload) { if (params->user_workload) {
/* rtla asked to stop */ /* rtla asked to stop */
params_u.should_run = 1; params_u.should_run = 1;
...@@ -1006,6 +996,27 @@ int timerlat_top_main(int argc, char *argv[]) ...@@ -1006,6 +996,27 @@ int timerlat_top_main(int argc, char *argv[])
err_msg("Error creating timerlat user-space threads\n"); err_msg("Error creating timerlat user-space threads\n");
} }
if (params->warmup > 0) {
debug_msg("Warming up for %d seconds\n", params->warmup);
sleep(params->warmup);
}
/*
* Start the tracers here, after having set all instances.
*
* Let the trace instance start first for the case of hitting a stop
* tracing while enabling other instances. The trace instance is the
* one with most valuable information.
*/
if (params->trace_output)
trace_instance_start(&record->trace);
if (!params->no_aa && aa != top)
trace_instance_start(&aa->trace);
trace_instance_start(trace);
top->start_time = time(NULL);
timerlat_top_set_signals(params);
while (!stop_tracing) { while (!stop_tracing) {
sleep(params->sleep_time); sleep(params->sleep_time);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment