From: Jiebin Sun <jiebin.sun@intel.com>
To: Namhyung Kim <namhyung@kernel.org>
Cc: acme@kernel.org, mingo@redhat.com, peterz@infradead.org,
adrian.hunter@intel.com, alexander.shishkin@linux.intel.com,
irogers@google.com, james.clark@linaro.org, jolsa@kernel.org,
mark.rutland@arm.com, dapeng1.mi@linux.intel.com,
thomas.falcon@intel.com, tianyou.li@intel.com,
wangyang.guo@intel.com, linux-perf-users@vger.kernel.org,
linux-kernel@vger.kernel.org, Jiebin Sun <jiebin.sun@intel.com>
Subject: [PATCH v5 v5 4/9] perf c2c: add HPP list parsing for function view columns
Date: Thu, 30 Jul 2026 17:05:16 +0800 [thread overview]
Message-ID: <20260730090521.2206375-5-jiebin.sun@intel.com> (raw)
In-Reply-To: <20260730090521.2206375-1-jiebin.sun@intel.com>
Add the parsing that turns an output/sort column string into the function
view's hpp_list: the dimension lookup, the sort-entry comparator wrappers,
the c2c_fmt allocation, and the init/reinit entry points used by the
hierarchy builder.
Append the sort keys to the output fields with a local
c2c_function_hists__setup_output_field() helper. The shared
perf_hpp__setup_output_field() registers onto the global perf_hpp_list,
which would leave the function view's local list without output columns
and link its formats into the global list instead, so the function view
keeps its own copy that registers on the local hpp_list.
Signed-off-by: Jiebin Sun <jiebin.sun@intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Reviewed-by: Tianyou Li <tianyou.li@intel.com>
Reviewed-by: Wangyang Guo <wangyang.guo@intel.com>
---
tools/perf/ui/browsers/c2c-function.c | 268 +++++++++++++++++++++++++-
1 file changed, 265 insertions(+), 3 deletions(-)
diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers/c2c-function.c
index a7825140d049..caccb20f0ef4 100644
--- a/tools/perf/ui/browsers/c2c-function.c
+++ b/tools/perf/ui/browsers/c2c-function.c
@@ -133,8 +133,8 @@ static int c2c_width(struct perf_hpp_fmt *fmt,
dim->width;
}
-static int __maybe_unused c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
- struct hists *hists, int line, int *span)
+static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+ struct hists *hists, int line, int *span)
{
struct c2c_fmt *c2c_fmt;
struct c2c_dimension *dim;
@@ -409,13 +409,275 @@ static struct c2c_dimension dim_symbol_view = {
.width = SYMBOL_WIDTH,
};
-static struct c2c_dimension *function_view_dimensions[] __maybe_unused = {
+static struct c2c_dimension *function_view_dimensions[] = {
&dim_cycles_percent,
&dim_total_stores,
&dim_symbol_view,
NULL,
};
+static struct c2c_dimension *get_function_dimension(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; function_view_dimensions[i]; i++) {
+ struct c2c_dimension *dim = function_view_dimensions[i];
+
+ if (!strcmp(dim->name, name))
+ return dim;
+ }
+
+ return NULL;
+}
+
+/* Wrappers so sort_entry-backed dimensions sort/collapse via their se. */
+static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b)
+{
+ struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
+ struct c2c_dimension *dim = c2c_fmt->dim;
+
+ return dim->se->se_cmp(a, b);
+}
+
+static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b)
+{
+ struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
+ struct c2c_dimension *dim = c2c_fmt->dim;
+ int64_t (*collapse_fn)(struct hist_entry *a, struct hist_entry *b);
+
+ collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
+ return collapse_fn(a, b);
+}
+
+static int64_t c2c_se_sort(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b)
+{
+ struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
+ struct c2c_dimension *dim = c2c_fmt->dim;
+ int64_t (*sort_fn)(struct hist_entry *a, struct hist_entry *b);
+
+ sort_fn = dim->se->se_sort ?: dim->se->se_cmp;
+ return sort_fn(a, b);
+}
+
+/*
+ * Build the c2c_fmt for @name. Returns:
+ * 0 and *fmtp set on success;
+ * -ENOENT and *fmtp = NULL if @name is not a function-view dimension;
+ * -ENOMEM if allocation failed (distinct from -ENOENT so
+ * the caller does not misreport it as an
+ * "invalid field").
+ */
+static int get_function_format(const char *name, struct c2c_fmt **fmtp)
+{
+ struct c2c_dimension *dim = get_function_dimension(name);
+ struct c2c_fmt *c2c_fmt;
+ struct perf_hpp_fmt *fmt;
+
+ *fmtp = NULL;
+
+ if (!dim)
+ return -ENOENT;
+
+ c2c_fmt = zalloc(sizeof(*c2c_fmt));
+ if (!c2c_fmt)
+ return -ENOMEM;
+
+ fmt = &c2c_fmt->fmt;
+
+ c2c_fmt->dim = dim;
+ INIT_LIST_HEAD(&fmt->list);
+ INIT_LIST_HEAD(&fmt->sort_list);
+
+ fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
+ fmt->sort = dim->se ? c2c_se_sort : dim->cmp;
+ fmt->color = dim->color;
+ fmt->entry = dim->entry;
+ fmt->header = c2c_header;
+ fmt->width = c2c_width;
+ fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
+ fmt->equal = c2c_fmt_equal;
+ fmt->free = c2c_fmt_free;
+
+ *fmtp = c2c_fmt;
+ return 0;
+}
+
+static int
+c2c_function_hists__init_output(struct perf_hpp_list *hpp_list, char *name,
+ struct perf_env *env __maybe_unused)
+{
+ struct c2c_fmt *c2c_fmt;
+ int ret;
+
+ ret = get_function_format(name, &c2c_fmt);
+ if (ret == -ENOMEM)
+ return ret;
+ /* The function view only accepts its own dimensions. */
+ if (ret == -ENOENT)
+ return -EINVAL;
+
+ /*
+ * Mark symbol-backed columns so hists__has(hists, sym) is correct.
+ * Only dim_symbol_view carries a sort_entry (.se); the function
+ * view's field strings are fixed and always include symbol_view, so
+ * this single check is sufficient (unlike the user-configurable
+ * cacheline view, which must also test dim_iaddr).
+ */
+ if (c2c_fmt->dim->se == &sort_sym)
+ hpp_list->sym = 1;
+
+ perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
+ return 0;
+}
+
+static int
+c2c_function_hists__init_sort(struct perf_hpp_list *hpp_list, char *name,
+ struct perf_env *env __maybe_unused)
+{
+ struct c2c_fmt *c2c_fmt;
+ int ret;
+
+ ret = get_function_format(name, &c2c_fmt);
+ if (ret == -ENOMEM)
+ return ret;
+ /* The function view only accepts its own dimensions. */
+ if (ret == -ENOENT)
+ return -EINVAL;
+
+ /* Mark symbol-backed sort keys so hists__has(hists, sym) is correct. */
+ if (c2c_fmt->dim->se == &sort_sym)
+ hpp_list->sym = 1;
+
+ perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
+ return 0;
+}
+
+typedef int (*hpp_list_add_fn)(struct perf_hpp_list *hpp_list, char *name,
+ struct perf_env *env);
+
+static int function_hpp_list__add_tokens(struct perf_hpp_list *hpp_list, char *list,
+ struct perf_env *env, hpp_list_add_fn add)
+{
+ char *tok, *tmp;
+ int ret;
+
+ if (!list)
+ return 0;
+
+ for (tok = strtok_r(list, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
+ ret = add(hpp_list, tok, env);
+ if (ret) {
+ if (ret == -EINVAL || ret == -ESRCH)
+ pr_err("Invalid c2c function-view field: %s\n", tok);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Append the function view's sort keys to its own output fields, mirroring
+ * perf_hpp__setup_output_field() but on the local @list. The shared helper
+ * registers onto the global perf_hpp_list, which would leave this local list
+ * without output columns, so the function view keeps its own copy here.
+ */
+static void c2c_function_hists__setup_output_field(struct perf_hpp_list *list)
+{
+ struct perf_hpp_fmt *fmt;
+
+ perf_hpp_list__for_each_sort_list(list, fmt) {
+ struct perf_hpp_fmt *pos;
+
+ if (!fmt->entry && !fmt->color)
+ continue;
+
+ perf_hpp_list__for_each_format(list, pos) {
+ if (c2c_fmt_equal(fmt, pos))
+ goto next;
+ }
+
+ perf_hpp_list__column_register(list, fmt);
+next:
+ continue;
+ }
+}
+
+static int
+function_hpp_list__parse(struct perf_hpp_list *hpp_list,
+ const char *output_str,
+ const char *sort_str,
+ struct perf_env *env)
+{
+ char *output = output_str ? strdup(output_str) : NULL;
+ char *sort = sort_str ? strdup(sort_str) : NULL;
+ int ret = 0;
+
+ if ((output_str && !output) || (sort_str && !sort)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = function_hpp_list__add_tokens(hpp_list, output, env,
+ c2c_function_hists__init_output);
+ if (ret)
+ goto out;
+
+ ret = function_hpp_list__add_tokens(hpp_list, sort, env,
+ c2c_function_hists__init_sort);
+ if (ret)
+ goto out;
+
+ c2c_function_hists__setup_output_field(hpp_list);
+out:
+ if (ret)
+ perf_hpp__reset_output_field(hpp_list);
+ free(output);
+ free(sort);
+ return ret;
+}
+
+static int __maybe_unused
+c2c_function_hists__init(struct c2c_hists *hists,
+ const char *sort,
+ int nr_header_lines,
+ struct perf_env *env)
+{
+ __hists__init(&hists->hists, &hists->list);
+
+ perf_hpp_list__init(&hists->list);
+
+ hists->list.nr_header_lines = nr_header_lines;
+
+ return function_hpp_list__parse(&hists->list, /*output=*/NULL, sort, env);
+}
+
+static int __maybe_unused
+c2c_function_hists__reinit(struct c2c_hists *c2c_hists,
+ const char *output,
+ const char *sort,
+ struct perf_env *env)
+{
+ int nr_header_lines = c2c_hists->list.nr_header_lines;
+
+ perf_hpp__reset_output_field(&c2c_hists->list);
+
+ /* Clear stale state flags so a different output/sort set starts fresh. */
+ c2c_hists->list.need_collapse = 0;
+ c2c_hists->list.parent = 0;
+ c2c_hists->list.sym = 0;
+ c2c_hists->list.dso = 0;
+ c2c_hists->list.socket = 0;
+ c2c_hists->list.thread = 0;
+ c2c_hists->list.comm = 0;
+ c2c_hists->list.comm_nodigit = 0;
+ c2c_hists->list.nr_header_lines = nr_header_lines;
+
+ return function_hpp_list__parse(&c2c_hists->list, output, sort, env);
+}
+
int perf_c2c__browse_function_view(void)
{
ui__warning("C2C function view is not implemented yet.\n");
--
2.52.0
next prev parent reply other threads:[~2026-07-30 9:00 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 9:05 [PATCH v5 0/9] perf c2c: add a function view Jiebin Sun
2026-07-30 9:05 ` [PATCH v5 v5 1/9] perf c2c: extract shared data structures into c2c.h Jiebin Sun
2026-07-30 9:13 ` sashiko-bot
2026-07-30 9:05 ` [PATCH v5 v5 2/9] perf c2c: add function view browser skeleton Jiebin Sun
2026-07-30 9:05 ` [PATCH v5 v5 3/9] perf c2c: add column rendering for function view Jiebin Sun
2026-07-30 9:05 ` Jiebin Sun [this message]
2026-07-30 9:05 ` [PATCH v5 v5 5/9] perf c2c: add function view stats merge and memory management Jiebin Sun
2026-07-30 9:05 ` [PATCH v5 v5 6/9] perf c2c: add function view hierarchy entry creation Jiebin Sun
2026-07-30 9:19 ` sashiko-bot
2026-07-30 9:05 ` [PATCH v5 v5 7/9] perf c2c: build and finalize the function view hierarchy Jiebin Sun
2026-07-30 9:05 ` [PATCH v5 v5 8/9] perf c2c: add function view browser UI and cacheline detail Jiebin Sun
2026-07-30 9:30 ` sashiko-bot
2026-07-30 9:05 ` [PATCH v5 v5 9/9] perf c2c: document function view in perf-c2c man page Jiebin Sun
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=20260730090521.2206375-5-jiebin.sun@intel.com \
--to=jiebin.sun@intel.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=dapeng1.mi@linux.intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--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=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=thomas.falcon@intel.com \
--cc=tianyou.li@intel.com \
--cc=wangyang.guo@intel.com \
/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