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: Sat, 31 Oct 2026 00:05:52 -0700	[thread overview]
Message-ID: <auWTUJd4VJUI32S3@z2> (raw)
In-Reply-To: <20261026025735.546101-5-atomlin@atomlin.com>

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?

> +
> +		if (cs->overflow_depth > 0 &&
> +		    (top_raw_indent < 0 || leading_spaces > top_raw_indent)) {
> +			cs->overflow_depth--;
> +			return print_line(ftrace, line, out);
> +		}
> +
> +		match_idx = -1;
> +		if (exit_name[0] != '\0') {
> +			for (i = cs->depth - 1; i >= 0; i--) {
> +				if (cs->stack[i].name &&
> +				    cs->stack[i].raw_indent == leading_spaces &&
> +				    strcmp(cs->stack[i].name, exit_name) == 0) {
> +					match_idx = i;
> +					break;
> +				}
> +			}
> +		}
> +
> +		if (match_idx < 0 && exit_name[0] == '\0') {
> +			for (i = cs->depth - 1; i >= 0; i--) {
> +				if (cs->stack[i].raw_indent == leading_spaces) {
> +					match_idx = i;
> +					break;
> +				}
> +			}
> +		}
> +
> +		if (match_idx >= 0) {
> +			cs->overflow_depth = 0;
> +			while (cs->depth > match_idx) {
> +				free(cs->stack[cs->depth - 1].name);
> +				cs->depth--;
> +			}
> +		} else if (cs->overflow_depth > 0) {
> +			cs->overflow_depth--;
> +		}
> +
> +		return print_line(ftrace, line, out);
> +	}
> +
> +	has_open_brace = (strchr(func_start, '{') != NULL);
> +	has_semicolon = (strchr(func_start, ';') != NULL);
> +
> +	top_raw_indent = -1;
> +	for (i = cs->depth - 1; i >= 0; i--) {
> +		top_raw_indent = cs->stack[i].raw_indent;
> +		break;
> +	}

Ditto.

> +
> +	if (cs->overflow_depth > 0 && top_raw_indent >= 0 &&
> +	    leading_spaces <= top_raw_indent)
> +		cs->overflow_depth = 0;
> +
> +	if (has_open_brace && !has_semicolon) {
> +		char entry_name[128];
> +
> +		extract_entry_func_name(func_start, entry_name, sizeof(entry_name));
> +		if (cs->depth >= cs->max_stack &&
> +		    ftrace_task_state__grow_stack(cs) < 0) {
> +			cs->overflow_depth++;
> +		} else {
> +			cs->stack[cs->depth].name = strdup(entry_name);
> +			if (!cs->stack[cs->depth].name) {
> +				pr_err("Not enough memory\n");
> +				return -ENOMEM;
> +			}
> +			cs->stack[cs->depth].inlined = false;
> +			cs->stack[cs->depth].indent = leading_spaces;
> +			cs->stack[cs->depth].raw_indent = leading_spaces;
> +			cs->depth++;
> +		}
> +	}
> +
> +	return print_line(ftrace, line, out);
> +}
> diff --git a/tools/perf/util/ftrace.h b/tools/perf/util/ftrace.h
> index a3a679f74e9d..fa2974f46582 100644
> --- a/tools/perf/util/ftrace.h
> +++ b/tools/perf/util/ftrace.h
> @@ -1,6 +1,9 @@
>  #ifndef __PERF_FTRACE_H__
>  #define __PERF_FTRACE_H__
>  
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <sys/types.h>
>  #include <linux/list.h>
>  
>  #include "target.h"
> @@ -93,7 +96,34 @@ perf_ftrace__latency_cleanup_bpf(struct perf_ftrace *ftrace __maybe_unused)
>  
>  #endif  /* HAVE_BPF_SKEL */
>  
> +#define FTRACE_MAX_CPUS 4096
> +#define FTRACE_MAX_STACK 256
> +#define FTRACE_PID_HASH_BITS 10
> +#define FTRACE_PID_HASH_SIZE (1 << FTRACE_PID_HASH_BITS)
> +
> +#define FTRACE_IDLE_PID(cpu)       ((pid_t)(-1 - (cpu)))
> +#define FTRACE_UNKNOWN_PID(cpu)    ((pid_t)(-1 - FTRACE_MAX_CPUS - (cpu)))
> +
> +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.


> +};
> +
> +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?

Thanks,
Namhyung


> +};
> +
>  bool ftrace_parse_retaddr(const char *str, char *sym_name, size_t sym_len, u64 *offset);
>  void ftrace_filter_retaddr(char *str);
> +void ftrace_cpu_states__clear(void);
> +int ftrace_process_fgraph_line(struct perf_ftrace *ftrace, const char *line, FILE *out);
>  
>  #endif  /* __PERF_FTRACE_H__ */
> -- 
> 2.55.0
> 

  parent reply	other threads:[~2026-10-31  7:05 UTC|newest]

Thread overview: 24+ 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-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 [this message]
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-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-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=auWTUJd4VJUI32S3@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.