]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
rtla/timerlat: Add -A/--aligned CLI option
authorTomas Glozar <tglozar@redhat.com>
Wed, 27 May 2026 14:49:26 +0000 (16:49 +0200)
committerTomas Glozar <tglozar@redhat.com>
Thu, 28 May 2026 11:02:48 +0000 (13:02 +0200)
Add a new option, -A/--aligned, that enables timerlat thread alignment
implemented on the kernel-side in commit 4245bf4dc58f ("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>
tools/tracing/rtla/src/cli.c
tools/tracing/rtla/src/cli_p.h
tools/tracing/rtla/src/common.h
tools/tracing/rtla/src/osnoise.c
tools/tracing/rtla/src/osnoise.h
tools/tracing/rtla/src/timerlat.c
tools/tracing/rtla/src/timerlat.h

index 709219341a561bdd65cf29d2529ac73fee4c55a7..c5279c987531036e96424f5131f029222a384011 100644 (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,
index 3cea4f6e976ecf2ea633f7454f99e10061c1a71b..3c939de9abf02edeaa7317453c1c8ee8bb5c3bdb 100644 (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
  */
index 0dfca83bd72676153dafdc0c0902de1193389a03..04b287a03f6d4cd292f3b5c06e22840215b27f7c 100644 (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;
index e1e32898af2dc3d3a0af6a21cacfa7a1254fcb98..4ff5dad013b10d4966121434461366bec96e2fcd 100644 (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);
 }
index 168669aa7e0d5598dc64a03a38d34209ef2676e3..340ff5a64e6e4637568cc1b4893c6a8d4d665ccb 100644 (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);
index f990c8365776b86f0854c1c05a80ffac0b03772c..169aa9a6569d62cc8bdf9e4478f2621de193a33b 100644 (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.
index 38ab6b41a15e046939969c755d5da29db8a41c13..84ec6d77818300ff6910189c5a0b107abc992233 100644 (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)