* [PATCH 1/2] rtla/timerlat: Add --stack-format option
@ 2026-01-19 11:52 Tomas Glozar
2026-01-19 11:52 ` [PATCH 2/2] Documentation/rtla: Document " Tomas Glozar
2026-01-21 12:39 ` [PATCH 1/2] rtla/timerlat: Add " Wander Lairson Costa
0 siblings, 2 replies; 4+ messages in thread
From: Tomas Glozar @ 2026-01-19 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar
Cc: Costa Shulyupin, Crystal Wood, John Kacur, Luis Goncalves,
Wander Lairson Costa, LKML, Linux Trace Kernel
In the current implementation, the auto-analysis code for printing the
stack captured in the tracefs buffer of the aa instance stops at the
first encountered address that cannot be resolved into a function
symbol.
This is not always the desired behavior on all platforms; sometimes,
there might be resolvable entries after unresolvable ones, and
sometimes, the user might want to inspect the raw pointers for the
unresolvable entries.
Add a new option, --stack-format, with three values:
- truncate: stop at first unresolvable entry. This is the current
behavior, and is kept as the default.
- skip: skip unresolvable entries, but do not stop on them.
- full: print all entries, including unresolvable ones.
To make this work, the "size" field of the stack entry is now also read
and used as the maximum number of entries to print, capped at 64, since
that is the fixed length of the "caller" field.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
tools/tracing/rtla/src/timerlat.c | 2 +-
tools/tracing/rtla/src/timerlat.h | 1 +
tools/tracing/rtla/src/timerlat_aa.c | 36 +++++++++++++++++++++-----
tools/tracing/rtla/src/timerlat_aa.h | 2 +-
tools/tracing/rtla/src/timerlat_hist.c | 10 +++++++
tools/tracing/rtla/src/timerlat_top.c | 10 +++++++
tools/tracing/rtla/src/utils.c | 18 +++++++++++++
tools/tracing/rtla/src/utils.h | 7 +++++
8 files changed, 77 insertions(+), 9 deletions(-)
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 8f8811f7a13b..9e4daed0aafc 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -134,7 +134,7 @@ int timerlat_enable(struct osnoise_tool *tool)
if (!tool->aa)
return -1;
- retval = timerlat_aa_init(tool->aa, params->dump_tasks);
+ retval = timerlat_aa_init(tool->aa, params->dump_tasks, params->stack_format);
if (retval) {
err_msg("Failed to enable the auto analysis instance\n");
return retval;
diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h
index 8dd5d134ce08..364203a29abd 100644
--- a/tools/tracing/rtla/src/timerlat.h
+++ b/tools/tracing/rtla/src/timerlat.h
@@ -28,6 +28,7 @@ struct timerlat_params {
int deepest_idle_state;
enum timerlat_tracing_mode mode;
const char *bpf_action_program;
+ enum stack_format stack_format;
};
#define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common)
diff --git a/tools/tracing/rtla/src/timerlat_aa.c b/tools/tracing/rtla/src/timerlat_aa.c
index 31e66ea2b144..178de60dcef9 100644
--- a/tools/tracing/rtla/src/timerlat_aa.c
+++ b/tools/tracing/rtla/src/timerlat_aa.c
@@ -104,6 +104,7 @@ struct timerlat_aa_data {
struct timerlat_aa_context {
int nr_cpus;
int dump_tasks;
+ enum stack_format stack_format;
/* per CPU data */
struct timerlat_aa_data *taa_data;
@@ -481,23 +482,43 @@ static int timerlat_aa_stack_handler(struct trace_seq *s, struct tep_record *rec
{
struct timerlat_aa_context *taa_ctx = timerlat_aa_get_ctx();
struct timerlat_aa_data *taa_data = timerlat_aa_get_data(taa_ctx, record->cpu);
+ enum stack_format stack_format = taa_ctx->stack_format;
unsigned long *caller;
const char *function;
- int val, i;
+ int val;
+ unsigned long long i;
trace_seq_reset(taa_data->stack_seq);
trace_seq_printf(taa_data->stack_seq, " Blocking thread stack trace\n");
caller = tep_get_field_raw(s, event, "caller", record, &val, 1);
+
if (caller) {
- for (i = 0; ; i++) {
+ unsigned long long size;
+ unsigned long long max_entries;
+
+ if (tep_get_field_val(s, event, "size", record, &size, 1) == 0)
+ max_entries = size < 64 ? size : 64;
+ else
+ max_entries = 64;
+
+ for (i = 0; i < max_entries; i++) {
function = tep_find_function(taa_ctx->tool->trace.tep, caller[i]);
- if (!function)
- break;
- trace_seq_printf(taa_data->stack_seq, " %.*s -> %s\n",
- 14, spaces, function);
+ if (!function) {
+ if (stack_format == STACK_FORMAT_TRUNCATE)
+ break;
+ else if (stack_format == STACK_FORMAT_SKIP)
+ continue;
+ else if (stack_format == STACK_FORMAT_FULL)
+ trace_seq_printf(taa_data->stack_seq, " %.*s -> 0x%lx\n",
+ 14, spaces, caller[i]);
+ } else {
+ trace_seq_printf(taa_data->stack_seq, " %.*s -> %s\n",
+ 14, spaces, function);
+ }
}
}
+
return 0;
}
@@ -1020,7 +1041,7 @@ void timerlat_aa_destroy(void)
*
* Returns 0 on success, -1 otherwise.
*/
-int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks)
+int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks, enum stack_format stack_format)
{
int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
struct timerlat_aa_context *taa_ctx;
@@ -1035,6 +1056,7 @@ int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks)
taa_ctx->nr_cpus = nr_cpus;
taa_ctx->tool = tool;
taa_ctx->dump_tasks = dump_tasks;
+ taa_ctx->stack_format = stack_format;
taa_ctx->taa_data = calloc(nr_cpus, sizeof(*taa_ctx->taa_data));
if (!taa_ctx->taa_data)
diff --git a/tools/tracing/rtla/src/timerlat_aa.h b/tools/tracing/rtla/src/timerlat_aa.h
index cea4bb1531a8..a11b5f30cdce 100644
--- a/tools/tracing/rtla/src/timerlat_aa.h
+++ b/tools/tracing/rtla/src/timerlat_aa.h
@@ -3,7 +3,7 @@
* Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
*/
-int timerlat_aa_init(struct osnoise_tool *tool, int dump_task);
+int timerlat_aa_init(struct osnoise_tool *tool, int dump_task, enum stack_format stack_format);
void timerlat_aa_destroy(void);
void timerlat_auto_analysis(int irq_thresh, int thread_thresh);
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 4e8c38a61197..e5b3d4f098b2 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -747,6 +747,7 @@ static void timerlat_hist_usage(void)
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
+ " --stack-format <format>: set the stack format (truncate, skip, full)",
NULL,
};
@@ -787,6 +788,9 @@ static struct common_params
/* default to BPF mode */
params->mode = TRACING_MODE_BPF;
+ /* default to truncate stack format */
+ params->stack_format = STACK_FORMAT_TRUNCATE;
+
while (1) {
static struct option long_options[] = {
{"auto", required_argument, 0, 'a'},
@@ -819,6 +823,7 @@ static struct common_params
{"on-threshold", required_argument, 0, '\5'},
{"on-end", required_argument, 0, '\6'},
{"bpf-action", required_argument, 0, '\7'},
+ {"stack-format", required_argument, 0, '\10'},
{0, 0, 0, 0}
};
@@ -966,6 +971,11 @@ static struct common_params
case '\7':
params->bpf_action_program = optarg;
break;
+ case '\10':
+ params->stack_format = parse_stack_format(optarg);
+ if (params->stack_format == -1)
+ fatal("Invalid --stack-format option");
+ break;
default:
fatal("Invalid option");
}
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 284b74773c2b..d6ce7dcb8e82 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -518,6 +518,7 @@ static void timerlat_top_usage(void)
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
" --on-end: define action to be executed at measurement end, multiple are allowed",
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
+ " --stack-format <format>: set the stack format (truncate, skip, full)",
NULL,
};
@@ -556,6 +557,9 @@ static struct common_params
/* default to BPF mode */
params->mode = TRACING_MODE_BPF;
+ /* default to truncate stack format */
+ params->stack_format = STACK_FORMAT_TRUNCATE;
+
while (1) {
static struct option long_options[] = {
{"auto", required_argument, 0, 'a'},
@@ -582,6 +586,7 @@ static struct common_params
{"on-threshold", required_argument, 0, '9'},
{"on-end", required_argument, 0, '\1'},
{"bpf-action", required_argument, 0, '\2'},
+ {"stack-format", required_argument, 0, '\3'},
{0, 0, 0, 0}
};
@@ -716,6 +721,11 @@ static struct common_params
case '\2':
params->bpf_action_program = optarg;
break;
+ case '\3':
+ params->stack_format = parse_stack_format(optarg);
+ if (params->stack_format == -1)
+ fatal("Invalid --stack-format option");
+ break;
default:
fatal("Invalid option");
}
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 0da3b2470c31..d979159f6b70 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -164,6 +164,24 @@ int parse_cpu_set(char *cpu_list, cpu_set_t *set)
return 1;
}
+/*
+ * parse_stack_format - parse the stack format
+ *
+ * Return: the stack format on success, -1 otherwise.
+ */
+int parse_stack_format(char *arg)
+{
+ if (!strcmp(arg, "truncate"))
+ return STACK_FORMAT_TRUNCATE;
+ if (!strcmp(arg, "skip"))
+ return STACK_FORMAT_SKIP;
+ if (!strcmp(arg, "full"))
+ return STACK_FORMAT_FULL;
+
+ debug_msg("Error parsing the stack format %s\n", arg);
+ return -1;
+}
+
/*
* parse_duration - parse duration with s/m/h/d suffix converting it to seconds
*/
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index f7c2a52a0ab5..80d5ec0cf934 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -62,8 +62,15 @@ struct sched_attr {
};
#endif /* SCHED_ATTR_SIZE_VER0 */
+enum stack_format {
+ STACK_FORMAT_TRUNCATE,
+ STACK_FORMAT_SKIP,
+ STACK_FORMAT_FULL
+};
+
int parse_prio(char *arg, struct sched_attr *sched_param);
int parse_cpu_set(char *cpu_list, cpu_set_t *set);
+int parse_stack_format(char *arg);
int __set_sched_attr(int pid, struct sched_attr *attr);
int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr);
int set_comm_cgroup(const char *comm_prefix, const char *cgroup);
--
2.52.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/2] Documentation/rtla: Document --stack-format option
2026-01-19 11:52 [PATCH 1/2] rtla/timerlat: Add --stack-format option Tomas Glozar
@ 2026-01-19 11:52 ` Tomas Glozar
2026-01-21 12:41 ` Wander Lairson Costa
2026-01-21 12:39 ` [PATCH 1/2] rtla/timerlat: Add " Wander Lairson Costa
1 sibling, 1 reply; 4+ messages in thread
From: Tomas Glozar @ 2026-01-19 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar
Cc: Costa Shulyupin, Crystal Wood, John Kacur, Luis Goncalves,
Wander Lairson Costa, LKML, Linux Trace Kernel
Add documentation for --stack-format option of rtla-timerlat into its
common options.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
Documentation/tools/rtla/common_timerlat_options.txt | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Documentation/tools/rtla/common_timerlat_options.txt b/Documentation/tools/rtla/common_timerlat_options.txt
index 07a285fcf7cf..ab159b2cbfe7 100644
--- a/Documentation/tools/rtla/common_timerlat_options.txt
+++ b/Documentation/tools/rtla/common_timerlat_options.txt
@@ -83,3 +83,15 @@
**Note**: BPF actions require BPF support to be available. If BPF is not available
or disabled, the tool falls back to tracefs mode and BPF actions are not supported.
+
+**--stack-format** *format*
+
+ Adjust the format of the stack trace printed during auto-analysis.
+
+ The supported values for *format* are:
+
+ * **truncate** Print the stack trace up to the first unknown address (default).
+ * **skip** Skip unknown addresses.
+ * **full** Print the entire stack trace, including unknown addresses.
+
+ For unknown addresses, the raw pointer is printed.
--
2.52.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH 2/2] Documentation/rtla: Document --stack-format option
2026-01-19 11:52 ` [PATCH 2/2] Documentation/rtla: Document " Tomas Glozar
@ 2026-01-21 12:41 ` Wander Lairson Costa
0 siblings, 0 replies; 4+ messages in thread
From: Wander Lairson Costa @ 2026-01-21 12:41 UTC (permalink / raw)
To: Tomas Glozar
Cc: Steven Rostedt, Costa Shulyupin, Crystal Wood, John Kacur,
Luis Goncalves, LKML, Linux Trace Kernel
On Mon, Jan 19, 2026 at 8:53 AM Tomas Glozar <tglozar@redhat.com> wrote:
>
[...]
> +
> +**--stack-format** *format*
> +
> + Adjust the format of the stack trace printed during auto-analysis.
> +
> + The supported values for *format* are:
> +
> + * **truncate** Print the stack trace up to the first unknown address (default).
> + * **skip** Skip unknown addresses.
> + * **full** Print the entire stack trace, including unknown addresses.
> +
> + For unknown addresses, the raw pointer is printed.
> --
> 2.52.0
>
Reviewed-by: Wander Lairson Costa <wander@redhat.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] rtla/timerlat: Add --stack-format option
2026-01-19 11:52 [PATCH 1/2] rtla/timerlat: Add --stack-format option Tomas Glozar
2026-01-19 11:52 ` [PATCH 2/2] Documentation/rtla: Document " Tomas Glozar
@ 2026-01-21 12:39 ` Wander Lairson Costa
1 sibling, 0 replies; 4+ messages in thread
From: Wander Lairson Costa @ 2026-01-21 12:39 UTC (permalink / raw)
To: Tomas Glozar
Cc: Steven Rostedt, Costa Shulyupin, Crystal Wood, John Kacur,
Luis Goncalves, LKML, Linux Trace Kernel
On Mon, Jan 19, 2026 at 8:53 AM Tomas Glozar <tglozar@redhat.com> wrote:
>
> In the current implementation, the auto-analysis code for printing the
> stack captured in the tracefs buffer of the aa instance stops at the
> first encountered address that cannot be resolved into a function
> symbol.
>
> This is not always the desired behavior on all platforms; sometimes,
> there might be resolvable entries after unresolvable ones, and
> sometimes, the user might want to inspect the raw pointers for the
> unresolvable entries.
>
> Add a new option, --stack-format, with three values:
>
> - truncate: stop at first unresolvable entry. This is the current
> behavior, and is kept as the default.
> - skip: skip unresolvable entries, but do not stop on them.
> - full: print all entries, including unresolvable ones.
>
> To make this work, the "size" field of the stack entry is now also read
> and used as the maximum number of entries to print, capped at 64, since
> that is the fixed length of the "caller" field.
>
[...]
> +int parse_stack_format(char *arg)
> +{
For the sake of function interface, it would be better to
parse_stack_format() return enum stack_format...
> + if (!strcmp(arg, "truncate"))
> + return STACK_FORMAT_TRUNCATE;
> + if (!strcmp(arg, "skip"))
> + return STACK_FORMAT_SKIP;
> + if (!strcmp(arg, "full"))
> + return STACK_FORMAT_FULL;
> +
> + debug_msg("Error parsing the stack format %s\n", arg);
> + return -1;
... and add a new entry to the enum STACK_FORMAT_INVALID = -1...
> +}
> +
> /*
> * parse_duration - parse duration with s/m/h/d suffix converting it to seconds
> */
> diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
> index f7c2a52a0ab5..80d5ec0cf934 100644
> --- a/tools/tracing/rtla/src/utils.h
> +++ b/tools/tracing/rtla/src/utils.h
> @@ -62,8 +62,15 @@ struct sched_attr {
> };
> #endif /* SCHED_ATTR_SIZE_VER0 */
>
> +enum stack_format {
> + STACK_FORMAT_TRUNCATE,
> + STACK_FORMAT_SKIP,
> + STACK_FORMAT_FULL
... here
[...]
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-01-21 12:41 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-19 11:52 [PATCH 1/2] rtla/timerlat: Add --stack-format option Tomas Glozar
2026-01-19 11:52 ` [PATCH 2/2] Documentation/rtla: Document " Tomas Glozar
2026-01-21 12:41 ` Wander Lairson Costa
2026-01-21 12:39 ` [PATCH 1/2] rtla/timerlat: Add " Wander Lairson Costa
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox