diff --git a/tools/tracing/rtla/src/cli.c b/tools/tracing/rtla/src/cli.c index 709219341a56..c5279c987531 100644 --- a/tools/tracing/rtla/src/cli.c +++ b/tools/tracing/rtla/src/cli.c @@ -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, diff --git a/tools/tracing/rtla/src/cli_p.h b/tools/tracing/rtla/src/cli_p.h index 3cea4f6e976e..3c939de9abf0 100644 --- a/tools/tracing/rtla/src/cli_p.h +++ b/tools/tracing/rtla/src/cli_p.h @@ -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 */ diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index 0dfca83bd726..04b287a03f6d 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -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; diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c index e1e32898af2d..4ff5dad013b1 100644 --- a/tools/tracing/rtla/src/osnoise.c +++ b/tools/tracing/rtla/src/osnoise.c @@ -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); } diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h index 168669aa7e0d..340ff5a64e6e 100644 --- a/tools/tracing/rtla/src/osnoise.h +++ b/tools/tracing/rtla/src/osnoise.h @@ -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); diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index f990c8365776..169aa9a6569d 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -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. diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h index 38ab6b41a15e..84ec6d778183 100644 --- a/tools/tracing/rtla/src/timerlat.h +++ b/tools/tracing/rtla/src/timerlat.h @@ -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)