Linux Perf Users
 help / color / mirror / Atom feed
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


  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