[PATCH 04/14] perf c2c: add column format infrastructure for function view
From: Jiebin Sun
Date: Fri Jun 26 2026 - 03:05:42 EST
Add the column format plumbing functions used by all function view
dimensions:
- symbol_width(): constrain symbol column width
- c2c_width(): dispatch column width based on dimension type
- c2c_header(): render multi-line column headers
These are referenced by column entry functions and dimension
definitions added in subsequent patches.
Signed-off-by: Jiebin Sun <jiebin.sun@xxxxxxxxx>
Cc: Adrian Hunter <adrian.hunter@xxxxxxxxx>
Cc: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx>
Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
Cc: Ian Rogers <irogers@xxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: James Clark <james.clark@xxxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Mark Rutland <mark.rutland@xxxxxxx>
Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Cc: Thomas Falcon <thomas.falcon@xxxxxxxxx>
Reviewed-by: Tianyou Li <tianyou.li@xxxxxxxxx>
Reviewed-by: Wangyang Guo <wangyang.guo@xxxxxxxxx>
---
tools/perf/ui/browsers/c2c-function.c | 117 ++++++++++++++++++++++++++
1 file changed, 117 insertions(+)
diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers/c2c-function.c
index dbc912a4a242..d718cab6537d 100644
--- a/tools/perf/ui/browsers/c2c-function.c
+++ b/tools/perf/ui/browsers/c2c-function.c
@@ -66,6 +66,123 @@ static __maybe_unused inline u64 hist_entry__iaddr(struct hist_entry *he)
return he->ip;
}
+static __maybe_unused int symbol_width(struct hists *hists, struct sort_entry *se)
+{
+ int width = hists__col_len(hists, se->se_width_idx);
+
+ if (!c2c.symbol_full && width > SYMBOL_WIDTH)
+ width = SYMBOL_WIDTH;
+
+ return width;
+}
+
+static struct c2c_dimension dim_symbol_view;
+
+/*
+ * c2c_width - Calculate width for a C2C column in function view
+ */
+static __maybe_unused int c2c_width(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp __maybe_unused,
+ struct hists *hists)
+{
+ struct c2c_fmt *c2c_fmt;
+ struct c2c_dimension *dim;
+
+ c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
+ dim = c2c_fmt->dim;
+
+ if (dim == &dim_symbol_view)
+ return symbol_width(hists, dim->se);
+
+ return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
+ dim->width;
+}
+
+static __maybe_unused 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;
+ const char *text = NULL;
+ int width = c2c_width(fmt, hpp, hists);
+
+ c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
+ dim = c2c_fmt->dim;
+
+ if (dim->se) {
+ text = dim->header.line[line].text;
+ /* Use the last line from sort_entry if not defined. */
+ if (!text && line == hists->hpp_list->nr_header_lines - 1)
+ text = dim->se->se_header;
+ } else {
+ text = dim->header.line[line].text;
+
+ if (span) {
+ if (*span) {
+ (*span)--;
+ return 0;
+ }
+
+ *span = dim->header.line[line].span;
+ }
+ }
+
+ if (text == NULL)
+ text = "";
+
+ return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
+}
+
+/*
+ * Return the estimated total cycles for a c2c_hist_entry
+ * (rmt_hitm + lcl_hitm + rmt_peer + lcl_peer + other loads).
+ */
+static __maybe_unused u64 c2c_hist_entry__cycles(struct c2c_hist_entry *c2c_he)
+{
+ double cycles_rmt, cycles_lcl, cycles_load;
+ u64 other_load, total_hitm;
+
+ cycles_rmt = avg_stats(&c2c_he->cstats.rmt_hitm) * c2c_he->stats.rmt_hitm;
+ cycles_lcl = avg_stats(&c2c_he->cstats.lcl_hitm) * c2c_he->stats.lcl_hitm;
+ total_hitm = c2c_he->stats.tot_hitm;
+ other_load = (c2c_he->stats.load >= total_hitm) ? c2c_he->stats.load - total_hitm : 0;
+ cycles_load = avg_stats(&c2c_he->cstats.load) * other_load;
+
+ return (u64)(cycles_rmt + cycles_lcl + cycles_load);
+}
+
+/* Sum c2c_hist_entry__cycles() across all level-1 entries. */
+static __maybe_unused u64 c2c_ext__total_cycles(void)
+{
+ struct rb_node *nd;
+ u64 total = 0;
+
+ for (nd = rb_first_cached(&c2c_ext.function_hists.hists.entries); nd;
+ nd = rb_next(nd)) {
+ struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
+ struct c2c_hist_entry *c2c_he = container_of(he, struct c2c_hist_entry, he);
+
+ total += c2c_hist_entry__cycles(c2c_he);
+ }
+ return total;
+}
+
+/* Sum child entries' store counts under a level-1 hist_entry. */
+static __maybe_unused u64 hist_entry__child_stores(struct hist_entry *he)
+{
+ struct rb_node *nd;
+ u64 sum = 0;
+
+ for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) {
+ struct hist_entry *child = rb_entry(nd, struct hist_entry, rb_node);
+ struct c2c_hist_entry *c2c_child =
+ container_of(child, struct c2c_hist_entry, he);
+
+ sum += (u64)c2c_child->stats.store;
+ }
+ return sum;
+}
+
int perf_c2c__browse_function_view(struct hists *hists __maybe_unused)
{
ui__warning("C2C function view is not implemented yet.\n");
--
2.52.0