All of lore.kernel.org
 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: 38+ 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-11-04 20:53       ` Namhyung Kim
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.