rtla/timerlat: Add -A/--aligned CLI option

Add a new option, -A/--aligned, that enables timerlat thread alignment
implemented on the kernel-side in commit 4245bf4dc5 ("tracing/osnoise:
Add option to align tlat threads"). The option takes an argument,
representing alignment between timerlat threads in microseconds.

The feature is modeled after the option of the same name in the
cyclictest tool.

Link: https://lore.kernel.org/r/20260527144928.2944472-1-tglozar@redhat.com
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
This commit is contained in:
Tomas Glozar 2026-05-27 16:49:26 +02:00
parent 596a9bed0a
commit 03d745b984
7 changed files with 202 additions and 0 deletions

View File

@ -248,6 +248,7 @@ struct common_params *timerlat_top_parse_args(int argc, char **argv)
RTLA_OPT_USER_THREADS,
RTLA_OPT_KERNEL_THREADS,
RTLA_OPT_USER_LOAD,
TIMERLAT_OPT_ALIGNED,
OPT_GROUP("Output:"),
TIMERLAT_OPT_NANO,
@ -362,6 +363,7 @@ struct common_params *timerlat_hist_parse_args(int argc, char **argv)
RTLA_OPT_USER_THREADS,
RTLA_OPT_KERNEL_THREADS,
RTLA_OPT_USER_LOAD,
TIMERLAT_OPT_ALIGNED,
OPT_GROUP("Histogram Options:"),
HIST_OPT_BUCKET_SIZE,

View File

@ -447,6 +447,10 @@ static int opt_osnoise_on_end_cb(const struct option *opt, const char *arg, int
"set the stack format (truncate, skip, full)", \
opt_stack_format_cb)
#define TIMERLAT_OPT_ALIGNED OPT_CALLBACK('A', "aligned", params, "us", \
"align thread wakeups to a specific offset", \
opt_timerlat_align_cb)
/*
* Callback functions for command line options for timerlat tools
*/
@ -608,6 +612,19 @@ static int opt_stack_format_cb(const struct option *opt, const char *arg, int un
return 0;
}
static int opt_timerlat_align_cb(const struct option *opt, const char *arg, int unset)
{
struct timerlat_params *params = opt->value;
if (unset || !arg)
return -1;
params->timerlat_align = true;
params->timerlat_align_us = get_llong_from_str((char *)arg);
return 0;
}
/*
* Macros for command line options specific to histogram-based tools
*/

View File

@ -51,6 +51,14 @@ struct osnoise_context {
/* -1 as init value because 0 is off */
int orig_opt_workload;
int opt_workload;
/* -1 as init value because 0 is off */
int orig_opt_timerlat_align;
int opt_timerlat_align;
/* 0 as init value */
unsigned long long orig_timerlat_align_us;
unsigned long long timerlat_align_us;
};
extern volatile int stop_tracing;

View File

@ -423,6 +423,86 @@ void osnoise_put_timerlat_period_us(struct osnoise_context *context)
context->orig_timerlat_period_us = OSNOISE_TIME_INIT_VAL;
}
/*
* osnoise_get_timerlat_align_us - read and save the original "timerlat_align_us"
*/
static long long
osnoise_get_timerlat_align_us(struct osnoise_context *context)
{
long long timerlat_align_us;
if (context->timerlat_align_us != OSNOISE_OPTION_INIT_VAL)
return context->timerlat_align_us;
if (context->orig_timerlat_align_us != OSNOISE_OPTION_INIT_VAL)
return context->orig_timerlat_align_us;
timerlat_align_us = osnoise_read_ll_config("osnoise/timerlat_align_us");
if (timerlat_align_us < 0)
goto out_err;
context->orig_timerlat_align_us = timerlat_align_us;
return timerlat_align_us;
out_err:
return OSNOISE_OPTION_INIT_VAL;
}
/*
* osnoise_set_timerlat_align_us - set "timerlat_align_us"
*/
int osnoise_set_timerlat_align_us(struct osnoise_context *context, long long timerlat_align_us)
{
long long curr_timerlat_align_us = osnoise_get_timerlat_align_us(context);
int retval;
if (curr_timerlat_align_us == OSNOISE_OPTION_INIT_VAL)
return -1;
retval = osnoise_write_ll_config("osnoise/timerlat_align_us", timerlat_align_us);
if (retval < 0)
return -1;
context->timerlat_align_us = timerlat_align_us;
return 0;
}
/*
* osnoise_restore_timerlat_align_us - restore "timerlat_align_us"
*/
void osnoise_restore_timerlat_align_us(struct osnoise_context *context)
{
int retval;
if (context->orig_timerlat_align_us == OSNOISE_OPTION_INIT_VAL)
return;
if (context->orig_timerlat_align_us == context->timerlat_align_us)
goto out_done;
retval = osnoise_write_ll_config("osnoise/timerlat_align_us",
context->orig_timerlat_align_us);
if (retval < 0)
err_msg("Could not restore original osnoise timerlat_align_us\n");
out_done:
context->timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
}
/*
* osnoise_put_timerlat_align_us - restore original values and cleanup data
*/
void osnoise_put_timerlat_align_us(struct osnoise_context *context)
{
osnoise_restore_timerlat_align_us(context);
if (context->orig_timerlat_align_us == OSNOISE_OPTION_INIT_VAL)
return;
context->orig_timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
}
/*
* osnoise_get_stop_us - read and save the original "stop_tracing_us"
*/
@ -908,6 +988,67 @@ static void osnoise_put_workload(struct osnoise_context *context)
context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
}
static int osnoise_get_timerlat_align(struct osnoise_context *context)
{
if (context->opt_timerlat_align != OSNOISE_OPTION_INIT_VAL)
return context->opt_timerlat_align;
if (context->orig_opt_timerlat_align != OSNOISE_OPTION_INIT_VAL)
return context->orig_opt_timerlat_align;
context->orig_opt_timerlat_align = osnoise_options_get_option("TIMERLAT_ALIGN");
return context->orig_opt_timerlat_align;
}
int osnoise_set_timerlat_align(struct osnoise_context *context, bool onoff)
{
int opt_timerlat_align = osnoise_get_timerlat_align(context);
int retval;
if (opt_timerlat_align == OSNOISE_OPTION_INIT_VAL)
return -1;
if (opt_timerlat_align == onoff)
return 0;
retval = osnoise_options_set_option("TIMERLAT_ALIGN", onoff);
if (retval < 0)
return -2;
context->opt_timerlat_align = onoff;
return 0;
}
static void osnoise_restore_timerlat_align(struct osnoise_context *context)
{
int retval;
if (context->orig_opt_timerlat_align == OSNOISE_OPTION_INIT_VAL)
return;
if (context->orig_opt_timerlat_align == context->opt_timerlat_align)
goto out_done;
retval = osnoise_options_set_option("TIMERLAT_ALIGN", context->orig_opt_timerlat_align);
if (retval < 0)
err_msg("Could not restore original TIMERLAT_ALIGN option\n");
out_done:
context->orig_opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
}
static void osnoise_put_timerlat_align(struct osnoise_context *context)
{
osnoise_restore_timerlat_align(context);
if (context->orig_opt_timerlat_align == OSNOISE_OPTION_INIT_VAL)
return;
context->orig_opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
}
enum {
FLAG_CONTEXT_NEWLY_CREATED = (1 << 0),
FLAG_CONTEXT_DELETED = (1 << 1),
@ -960,6 +1101,12 @@ struct osnoise_context *osnoise_context_alloc(void)
context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
context->opt_workload = OSNOISE_OPTION_INIT_VAL;
context->orig_opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
context->opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
context->orig_timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
context->timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
osnoise_get_context(context);
return context;
@ -988,6 +1135,8 @@ void osnoise_put_context(struct osnoise_context *context)
osnoise_put_tracing_thresh(context);
osnoise_put_irq_disable(context);
osnoise_put_workload(context);
osnoise_put_timerlat_align(context);
osnoise_put_timerlat_align_us(context);
free(context);
}

View File

@ -49,6 +49,12 @@ void osnoise_restore_print_stack(struct osnoise_context *context);
int osnoise_set_print_stack(struct osnoise_context *context,
long long print_stack);
int osnoise_set_timerlat_align_us(struct osnoise_context *context,
long long timerlat_align_us);
void osnoise_restore_timerlat_align_us(struct osnoise_context *context);
int osnoise_set_timerlat_align(struct osnoise_context *context, bool onoff);
int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff);
void osnoise_report_missed_events(struct osnoise_tool *tool);
int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params);

View File

@ -77,6 +77,24 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
goto out_err;
}
retval = osnoise_set_timerlat_align(tool->context, params->timerlat_align);
if (retval && params->timerlat_align) {
/*
* We might be running on a kernel that does not support timerlat align.
* Unless user requested it explicitly, ignore the error.
*/
err_msg("Failed to enable timerlat align\n");
goto out_err;
}
if (params->timerlat_align) {
retval = osnoise_set_timerlat_align_us(tool->context, params->timerlat_align_us);
if (retval) {
err_msg("Failed to set timerlat align us\n");
goto out_err;
}
}
/*
* If the user did not specify a type of thread, try user-threads first.
* Fall back to kernel threads otherwise.

View File

@ -31,6 +31,8 @@ struct timerlat_params {
enum timerlat_tracing_mode mode;
const char *bpf_action_program;
enum stack_format stack_format;
bool timerlat_align;
unsigned long long timerlat_align_us;
};
#define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common)