From: Namhyung Kim <namhyung@kernel.org>
To: Aaron Tomlin <atomlin@atomlin.com>
Cc: peterz@infradead.org, mingo@redhat.com, acme@kernel.org,
mark.rutland@arm.com, alexander.shishkin@linux.intel.com,
jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com,
chjohnst@mail.com, neelx@suse.com, sean@ashe.io,
linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH perf-tools-next v12 04/10] perf ftrace: Add basic task call stack management
Date: Tue, 3 Nov 2026 23:35:37 -0800 [thread overview]
Message-ID: <aurgSbFGfN0VC2L6@z2> (raw)
In-Reply-To: <5s4fy255agvlgqdg4b4f5ekvhgmpjndydvsaadeq56cubrtgot@mrflkcricted>
Hello,
On Sat, Oct 31, 2026 at 06:27:42PM -0400, Aaron Tomlin wrote:
> On Sat, Oct 31, 2026 at 12:05:52AM -0700, Namhyung Kim wrote:
> > On Sun, Oct 25, 2026 at 10:57:29PM -0400, Aaron Tomlin wrote:
> > > The function_graph tracer records kernel function entries and exits with
> > > nested indentation. To perform call graph analysis and subsequent inlined
> > > function reconstruction, userspace must track the active call stack on a
> > > per-task and per-CPU basis.
> > >
> > > Introduce basic call stack management for the function graph tracer:
> > >
> > > 1. Data structures
> > >
> > > Define struct ftrace_stack_frame to track function names,
> > > indentation, and inlined status.
> > >
> > > Define struct ftrace_task_state with a dynamically resisable call
> > > stack array, tracked in a hash table keyed by PID alongside per-CPU
> > > active task bindings (ftrace_cpu_tasks).
> > >
> > > 2. Trace stream processing
> > >
> > > Implement find_func_column() to isolate context columns (CPU,
> > > timestamps, duration) from function graph trace lines across
> > > standard and verbose layouts.
> > >
> > > Implement ftrace_process_fgraph_line() to parse function entries
> > > ("{") and exits ("}"), pushing and popping frames on the tracked
> > > stack and matching bare closing braces against preceding frames.
> > >
> > > 3. Integration in __cmd_ftrace()
> > >
> > > Stream complete trace lines through ftrace_process_fgraph_line()
> > > in __cmd_ftrace() and clean up allocated CPU states on exit via
> > > ftrace_cpu_states__clear().
> > >
> > > Tested-by: Ian Rogers <irogers@google.com>
> > > Reviewed-by: Ian Rogers <irogers@google.com>
> > > Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
> > > ---
> > [SNIP]
> > > +/**
> > > + * ftrace_process_fgraph_line - Process and output a function graph trace line
> > > + * @ftrace: Perf ftrace context
> > > + * @line: The trace line to process
> > > + * @out: File stream to output to
> > > + *
> > > + * Parse function entries and exits, maintain the task's call stack, and
> > > + * output the trace line.
> > > + *
> > > + * Return: 0 on success, or a negative error code on failure.
> > > + */
> > > +int ftrace_process_fgraph_line(struct perf_ftrace *ftrace, const char *line, FILE *out)
> > > +{
> > > + const char *pipe_char;
> > > + const char *after_pipe;
> > > + const char *func_start;
> > > + struct ftrace_task_state *cs;
> > > + int cpu = -1;
> > > + int leading_spaces;
> > > + int top_raw_indent;
> > > + int match_idx;
> > > + int i;
> > > + bool is_exit;
> > > + bool has_open_brace;
> > > + bool has_semicolon;
> > > +
> > > + pipe_char = find_func_column(ftrace, line, &cpu);
> > > + if (!pipe_char)
> > > + return print_line(ftrace, line, out);
> > > +
> > > + cs = get_cpu_state(ftrace, cpu);
> > > + if (!cs)
> > > + return print_line(ftrace, line, out);
> > > +
> > > + after_pipe = pipe_char + 1;
> > > + func_start = skip_spaces(after_pipe);
> > > + leading_spaces = func_start - after_pipe;
> > > +
> > > + if (*func_start == '\0')
> > > + return print_line(ftrace, line, out);
> > > +
> > > + is_exit = (*func_start == '}');
> > > +
> > > + if (is_exit) {
> > > + char exit_name[128];
> > > +
> > > + extract_exit_func_name(func_start, exit_name, sizeof(exit_name));
> > > +
> > > + top_raw_indent = -1;
> > > + for (i = cs->depth - 1; i >= 0; i--) {
> > > + top_raw_indent = cs->stack[i].raw_indent;
> > > + break;
> > > + }
> >
> > This loop doesn't look natural. Why not just use an if statement?
>
> Hi Namhyung,
>
> Thank you. I completely agree.
>
> A loop that unconditionally breaks on the first iteration is
> unnecessary here. I will replace it with a simple conditional check in
> the next revision:
>
> top_raw_indent = -1;
> if (cs->depth > 0)
> top_raw_indent = cs->stack[cs->depth - 1].raw_indent;
>
> All subsequent similar instances will be addressed accordingly as well.
>
> > > +struct ftrace_stack_frame {
> > > + char *name;
> > > + bool inlined;
> > > + int indent;
> > > + int raw_indent;
> >
> > Can you please add comments that explain why it has two indents?
> > Also inlined field may be added later.
>
> Certainly. The two indent fields serve distinct purposes once inlined
> frames are injected into the output.
>
> - raw_indent: Records the original leading whitespace count after "|"
> as emitted by the kernel's function_graph tracer. Because the kernel
> only traces real stack frames, raw_indent is used to match entry and
> exit frames against the raw trace stream.
>
> - indent: Records the adjusted visual indentation (in spaces) used when
> rendering the frame to output, accounting for any extra indentation
> added by preceding synthetic inlined frames so that the closing "}"
> aligns with its opening "{".
>
> Agreed, these fields are not used yet. I will move inlined and
> inlined_depth into the subsequent patch that introduces inlined function
> display, and add explanatory comments to both structures.
>
> > > +};
> > > +
> > > +struct ftrace_task_state {
> > > + struct hlist_node node;
> > > + pid_t pid;
> > > + struct ftrace_stack_frame *stack;
> > > + int max_stack;
> > > + int depth;
> > > + int inlined_depth;
> > > + int overflow_depth;
> >
> > Ditto. What are these depths?
>
> - max_stack: Current allocated capacity (in frames) of the dynamically
> resized 'stack' array.
>
> - depth: Current number of active frames stored on stack.
>
> - inlined_depth: Number of active synthetic inlined frames currently on
> stack, used to compute the extra visual indentation offset for
> child frames. This will also be moved to the later patch.
>
> - overflow_depth: Number of nested call frames entered while stack is
> saturated (at the maximum depth cap or on allocation failure), used
> so their matching exit braces can be consumed without prematurely
> popping valid parent frames.
>
> I will document all of these fields with comments in the next revision.
>
> Please see an example. When synthetic inlined frames are injected, the
> visual display column (indent) shifts right relative to the kernel stream
> (raw_indent):
>
> 1. What kernel function_graph emits:
>
> | foo() { <-- raw_indent = 2
> | bar() { <-- raw_indent = 4
> | } /* bar */ <-- raw_indent = 4
> | } /* foo */ <-- raw_indent = 2
>
> 2. Rendered output and stack state:
>
> When perf injects inlined function inline_helper() onto cs->stack,
> inlined_depth becomes 1. Every subsequent child frame shifts right
> by (inlined_depth * 2) spaces so bar() nests visually inside
> inline_helper(), while still retaining raw_indent = 4 to match the
> kernel's closing "}" event:
>
> Rendered Output cs->stack[idx] and ftrace_task_state
> --------------- ---------------------------
> | foo() { [0] foo:
> : raw_indent=2, indent=2, inlined=false
> : (depth=1, inlined_depth=0)
> :
> | inline_helper() { [1] inline_helper:
> : raw_indent=4, indent=4, inlined=true
> : (depth=2, inlined_depth=1)
> :
> | bar() { [2] bar:
> : raw_indent=4, indent=6, inlined=false
> : (depth=3, inlined_depth=1)
> : ^
> : '-- indent = raw_indent (4) +
> : inlined_depth * 2 (2) = 6
> :
> | } /* bar */ <-- kernel function_graph emits "}"
> : at raw_indent=4. Matched against [2]
> : via raw_indent=4, but printed at
> : [2].indent (6 spaces)
> :
> | } /* inline_helper */ <-- Popped automatically; printed at
> : [1].indent (4 spaces)
> :
> | } /* foo */ <-- kernel function_graph emits "}"
> at raw_indent=2. Matched against [0]
> via raw_indent=2, printed at
> [0].indent (2 spaces)
>
Thanks for the example, the comment also look good.
Namhyung
next prev parent reply other threads:[~2026-11-04 7:35 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 2:57 [PATCH perf-tools-next v12 00/10] perf ftrace: Support inlined functions and display enhancements in function graph tracer Aaron Tomlin
2026-10-26 2:57 ` [PATCH perf-tools-next v12 01/10] perf ftrace: Handle signals, non-blocking reads and pager exits in __cmd_ftrace() Aaron Tomlin
2026-10-26 9:23 ` sashiko-bot
2026-10-31 7:12 ` Namhyung Kim
2026-10-31 22:29 ` Aaron Tomlin
2026-10-26 2:57 ` [PATCH perf-tools-next v12 02/10] perf ftrace: Optimise __cmd_ftrace() stack frame with strbuf streaming Aaron Tomlin
2026-10-26 9:27 ` sashiko-bot
2026-10-26 2:57 ` [PATCH perf-tools-next v12 03/10] perf ftrace: Support filtering return address comments Aaron Tomlin
2026-10-26 9:33 ` sashiko-bot
2026-10-26 2:57 ` [PATCH perf-tools-next v12 04/10] perf ftrace: Add basic task call stack management Aaron Tomlin
2026-10-26 9:37 ` sashiko-bot
2026-10-31 7:05 ` Namhyung Kim
2026-10-31 22:27 ` Aaron Tomlin
2026-11-04 7:35 ` Namhyung Kim [this message]
2026-11-04 16:10 ` Aaron Tomlin
2026-10-26 2:57 ` [PATCH perf-tools-next v12 05/10] perf ftrace: Support context switch tracking in function graph tracer Aaron Tomlin
2026-10-26 9:45 ` sashiko-bot
2026-10-31 22:01 ` Namhyung Kim
2026-11-02 0:04 ` Aaron Tomlin
2026-11-04 7:42 ` Namhyung Kim
2026-11-04 16:45 ` Aaron Tomlin
2026-10-26 2:57 ` [PATCH perf-tools-next v12 06/10] perf ftrace: Support display of inlined functions " Aaron Tomlin
2026-10-26 9:55 ` sashiko-bot
2026-10-31 7:11 ` Namhyung Kim
2026-11-02 15:22 ` Aaron Tomlin
2026-10-31 23:33 ` Namhyung Kim
2026-11-02 19:20 ` Aaron Tomlin
2026-11-04 7:46 ` Namhyung Kim
2026-11-04 16:48 ` Aaron Tomlin
2026-10-26 2:57 ` [PATCH perf-tools-next v12 07/10] perf symbol: Introduce vmlinux_path__find() helper Aaron Tomlin
2026-10-26 10:04 ` sashiko-bot
2026-10-26 2:57 ` [PATCH perf-tools-next v12 08/10] perf test: Add test for ftrace inline and task stack tracking Aaron Tomlin
2026-10-26 10:09 ` sashiko-bot
2026-10-26 2:57 ` [PATCH perf-tools-next v12 09/10] perf ftrace: Support omitting execution duration in function graph tracer Aaron Tomlin
2026-10-26 10:15 ` sashiko-bot
2026-10-26 2:57 ` [PATCH perf-tools-next v12 10/10] perf ftrace: Filter extraneous functions " Aaron Tomlin
2026-10-26 10:30 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aurgSbFGfN0VC2L6@z2 \
--to=namhyung@kernel.org \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=atomlin@atomlin.com \
--cc=chjohnst@mail.com \
--cc=irogers@google.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=neelx@suse.com \
--cc=peterz@infradead.org \
--cc=sean@ashe.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox