From: Jiebin Sun <jiebin.sun@intel.com>
To: Namhyung Kim <namhyung@kernel.org>,
acme@kernel.org, mingo@redhat.com, peterz@infradead.org
Cc: 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 v4 6/9] perf c2c: add function view hierarchy entry creation
Date: Fri, 24 Jul 2026 17:58:39 +0800 [thread overview]
Message-ID: <20260724095842.995920-7-jiebin.sun@intel.com> (raw)
In-Reply-To: <20260724095842.995920-1-jiebin.sun@intel.com>
Add the entry-creation layer: the borrowed-reference child allocation and
insertion, and the level-1/2/3 lookup-or-create functions keyed by
function symbol (level 1 read-side, level 2 writer) and cacheline address
(level 3).
These are driven by the hierarchy builder in the next patch and are
__maybe_unused until then.
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 | 277 +++++++++++++++++++++++++-
1 file changed, 271 insertions(+), 6 deletions(-)
diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers/c2c-function.c
index 1bddc6bdc073..9a7b1353e11c 100644
--- a/tools/perf/ui/browsers/c2c-function.c
+++ b/tools/perf/ui/browsers/c2c-function.c
@@ -29,6 +29,7 @@
#include "../../util/addr_location.h"
#include "../../util/cacheline.h"
#include "../../util/debug.h"
+#include "../../util/dso.h"
#include "../../util/hist.h"
#include "../../util/map.h"
#include "../../util/mem-events.h"
@@ -57,12 +58,34 @@ static inline __maybe_unused u64 c2c_hitm_count(const struct c2c_stats *stats)
return stats->tot_hitm;
}
-static inline __maybe_unused bool symbol_name_equal(struct symbol *a, struct symbol *b)
+static int64_t c2c_function_cmp(const struct map_symbol *left,
+ const struct map_symbol *right)
{
- /* Two unknown symbols compare equal, matching cmp_null() in util/sort.c. */
- if (!a || !b)
- return a == b;
- return arch__compare_symbol_names(a->name, b->name) == 0;
+ const struct dso *left_dso = left->map ? map__dso(left->map) : NULL;
+ const struct dso *right_dso = right->map ? map__dso(right->map) : NULL;
+ int ret;
+
+ if (!left_dso || !right_dso) {
+ if (left_dso != right_dso)
+ return left_dso ? 1 : -1;
+ } else {
+ /*
+ * Use the same DSO name as _sort__dso_cmp() (short name unless
+ * verbose), so this matches the DSO comparison the level-1
+ * entries are deduplicated by; otherwise same-basename DSOs
+ * could be split or merged inconsistently across levels.
+ */
+ const char *left_name = verbose > 0 ?
+ dso__long_name(left_dso) : dso__short_name(left_dso);
+ const char *right_name = verbose > 0 ?
+ dso__long_name(right_dso) : dso__short_name(right_dso);
+
+ ret = strcmp(left_name, right_name);
+ if (ret)
+ return ret;
+ }
+
+ return _sort__sym_cmp(left->sym, right->sym);
}
static inline __maybe_unused u64 hist_entry__iaddr(struct hist_entry *he)
@@ -737,7 +760,7 @@ static void c2c_he__free_hierarchy(struct hist_entry *he);
/*
* Free a function-view histogram entry (hist_entry_ops::free).
*/
-static void __maybe_unused c2c_function_he_free(void *ptr)
+static void c2c_function_he_free(void *ptr)
{
struct hist_entry *he = ptr;
struct c2c_hist_entry *c2c_he;
@@ -867,6 +890,248 @@ static int __maybe_unused c2c_he__prune_empty_writers(struct hist_entry *l1_he)
return surviving;
}
+/* Entry operations for function view */
+static struct hist_entry_ops c2c_function_entry_ops = {
+ .new = c2c_he_zalloc,
+ .free = c2c_function_he_free,
+};
+
+static struct c2c_hist_entry *
+c2c_child_entry__alloc(struct hist_entry *parent_he, struct hist_entry *src_he,
+ int depth, u64 ip)
+{
+ struct c2c_hist_entry *child_c2c;
+ struct hist_entry *child_he;
+
+ /* Function-view children never own or display callchains. */
+ child_he = c2c_he_zalloc(0);
+ if (!child_he)
+ return NULL;
+
+ child_c2c = container_of(child_he, struct c2c_hist_entry, he);
+ memcpy(&child_he->ms, &src_he->ms, sizeof(struct map_symbol));
+
+ if (src_he->mem_info) {
+ child_he->mem_info = mem_info__clone(src_he->mem_info);
+ if (!child_he->mem_info)
+ goto out_free;
+ }
+
+ child_he->thread = src_he->thread;
+ child_he->cpumode = src_he->cpumode;
+ child_he->cpu = src_he->cpu;
+ child_he->socket = src_he->socket;
+ child_he->level = src_he->level;
+ child_he->ip = ip;
+
+ child_he->parent_he = parent_he;
+ child_he->depth = depth;
+ child_he->leaf = (depth >= 2);
+ child_he->hists = &c2c_ext.function_hists.hists;
+ child_he->filtered = false;
+ child_he->unfolded = false;
+ child_he->has_children = false;
+ child_he->has_no_entry = false;
+ child_he->nr_rows = 0;
+ child_he->row_offset = 0;
+
+ memset(&child_he->stat, 0, sizeof(child_he->stat));
+ child_he->hroot_in = RB_ROOT_CACHED;
+ child_he->hroot_out = RB_ROOT_CACHED;
+ INIT_LIST_HEAD(&child_he->pairs.node);
+ child_he->hpp_list = &c2c_ext.function_hists.list;
+ if (symbol_conf.cumulate_callchain) {
+ child_he->stat_acc = calloc(1, sizeof(struct he_stat));
+ if (!child_he->stat_acc)
+ goto out_free;
+ }
+
+ return child_c2c;
+
+out_free:
+ if (child_he->mem_info)
+ mem_info__put(child_he->mem_info);
+ zfree(&child_c2c->cpuset);
+ zfree(&child_c2c->nodeset);
+ zfree(&child_c2c->node_stats);
+ free(child_c2c);
+ return NULL;
+}
+
+static void
+c2c_child_entry__insert(struct hist_entry *parent_he, struct hist_entry *child_he,
+ struct rb_node **p, struct rb_node *rb_parent, bool leftmost)
+{
+ rb_link_node(&child_he->rb_node, rb_parent, p);
+ rb_insert_color_cached(&child_he->rb_node, &parent_he->hroot_out, leftmost);
+
+ parent_he->has_children = true;
+ parent_he->leaf = false;
+}
+
+static __maybe_unused struct hist_entry *
+c2c_function_hists__level1_entry(struct symbol *sym,
+ struct hist_entry *detail_he,
+ struct thread *synthetic_thread)
+{
+ struct addr_location al;
+ struct perf_sample sample = {};
+ struct mem_info *mi;
+ struct hist_entry *he;
+ /*
+ * Key the level-1 entry by the function, not by a specific code
+ * address: use the symbol start so every instruction address inside
+ * the same function collapses into one entry. This makes level 1 a
+ * true "function view" rather than a per-code-address view.
+ */
+ u64 sym_start = sym ? map__unmap_ip(detail_he->ms.map, sym->start) : detail_he->ip;
+
+ mi = mem_info__new();
+ if (mi) {
+ mem_info__iaddr(mi)->addr = sym_start;
+ /* mem_info__put() will map_symbol__exit() these, so take refs. */
+ mem_info__iaddr(mi)->ms.thread = thread__get(detail_he->ms.thread);
+ mem_info__iaddr(mi)->ms.map = map__get(detail_he->ms.map);
+ mem_info__iaddr(mi)->ms.sym = sym;
+ mem_info__daddr(mi)->addr = 0;
+ }
+
+ addr_location__init(&al);
+ al.thread = thread__get(synthetic_thread);
+ al.map = map__get(detail_he->ms.map);
+ al.sym = sym;
+ al.addr = sym_start;
+ al.level = detail_he->level;
+ al.cpumode = detail_he->cpumode;
+ al.cpu = 0;
+ al.socket = 0;
+ al.filtered = 0;
+ al.latency = 0;
+
+ /*
+ * Synthetic sample: period/weight are placeholders only. The real
+ * c2c counters live in c2c_hist_entry::stats and are added via
+ * hist_entry__add_c2c_stats(); no function-view column or sort key
+ * reads he->stat.period/nr_events, so the +1 that __hists__add_entry()
+ * accrues on each dedup hit has no effect on what is displayed.
+ */
+ sample.period = 1;
+ sample.weight = 1;
+ sample.ip = sym_start;
+ sample.pid = thread__pid(synthetic_thread);
+ sample.tid = thread__tid(synthetic_thread);
+ sample.cpu = 0;
+
+ /* Add entry - histogram handles dedup */
+ he = hists__add_entry_ops(&c2c_ext.function_hists.hists,
+ &c2c_function_entry_ops,
+ &al, NULL, NULL, mi,
+ NULL, &sample, true);
+
+ addr_location__exit(&al);
+ if (mi)
+ mem_info__put(mi);
+
+ if (he)
+ he->hpp_list = &c2c_ext.function_hists.list;
+
+ return he;
+}
+
+/*
+ * Level 2: another function that writes a cacheline the level-1 function
+ * reads, keyed by DSO and symbol so all code addresses and cachelines for the
+ * same writer function aggregate into one row without merging identically
+ * named functions from different DSOs.
+ */
+static __maybe_unused struct c2c_hist_entry *
+c2c_function_hists__level2_entry(struct c2c_hist_entry *level1_c2c,
+ struct symbol *sym, struct hist_entry *detail_he)
+{
+ struct hist_entry *level1_he = &level1_c2c->he;
+ struct rb_node **p = &level1_he->hroot_out.rb_root.rb_node;
+ struct rb_node *parent = NULL;
+ struct c2c_hist_entry *level2_c2c;
+ bool leftmost = true;
+
+ while (*p) {
+ struct hist_entry *iter = rb_entry(*p, struct hist_entry, rb_node);
+ struct map_symbol key = detail_he->ms;
+ int64_t cmp;
+
+ key.sym = sym;
+ parent = *p;
+ cmp = c2c_function_cmp(&key, &iter->ms);
+
+ if (cmp < 0) {
+ p = &parent->rb_left;
+ } else if (cmp > 0) {
+ p = &parent->rb_right;
+ leftmost = false;
+ } else {
+ return container_of(iter, struct c2c_hist_entry, he);
+ }
+ }
+
+ /* Key by the function symbol start so all code addresses collapse. */
+ level2_c2c = c2c_child_entry__alloc(level1_he, detail_he, 1,
+ sym ? map__unmap_ip(detail_he->ms.map, sym->start) :
+ hist_entry__iaddr(detail_he));
+ if (!level2_c2c)
+ return NULL;
+
+ /* Key this level by the looked-up symbol, not detail_he's. */
+ level2_c2c->he.ms.sym = sym;
+ if (level2_c2c->he.mem_info)
+ mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym = sym;
+
+ c2c_child_entry__insert(level1_he, &level2_c2c->he, p, parent, leftmost);
+
+ return level2_c2c;
+}
+
+/* Level 3: a specific cacheline where the L1/L2 functions contend (keyed by cl_addr). */
+static __maybe_unused struct c2c_hist_entry *
+c2c_function_hists__level3_entry(struct c2c_hist_entry *level2_c2c, u64 cl_addr,
+ struct c2c_hist_entry *cacheline_src_he)
+{
+ struct hist_entry *level2_he = &level2_c2c->he;
+ struct rb_node **p = &level2_he->hroot_out.rb_root.rb_node;
+ struct rb_node *parent = NULL;
+ struct c2c_hist_entry *level3_c2c;
+ bool leftmost = true;
+
+ while (*p) {
+ struct hist_entry *iter = rb_entry(*p, struct hist_entry, rb_node);
+ u64 iter_addr = 0;
+
+ if (iter->mem_info) {
+ u64 daddr = mem_info__daddr(iter->mem_info)->addr;
+
+ iter_addr = cl_address(daddr, chk_double_cl);
+ }
+
+ parent = *p;
+ if (cl_addr < iter_addr) {
+ p = &parent->rb_left;
+ } else if (cl_addr > iter_addr) {
+ p = &parent->rb_right;
+ leftmost = false;
+ } else {
+ return container_of(iter, struct c2c_hist_entry, he);
+ }
+ }
+
+ level3_c2c = c2c_child_entry__alloc(level2_he, &cacheline_src_he->he, 2,
+ hist_entry__iaddr(&cacheline_src_he->he));
+ if (!level3_c2c)
+ return NULL;
+
+ c2c_child_entry__insert(level2_he, &level3_c2c->he, p, parent, leftmost);
+
+ return level3_c2c;
+}
+
int perf_c2c__browse_function_view(struct hists *hists __maybe_unused)
{
ui__warning("C2C function view is not implemented yet.\n");
--
2.52.0
next prev parent reply other threads:[~2026-07-24 9:52 UTC|newest]
Thread overview: 89+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-26 7:03 [PATCH 00/14] perf c2c: add a function view Jiebin Sun
2026-06-26 7:03 ` [PATCH 01/14] perf c2c: extract shared data structures into c2c.h Jiebin Sun
2026-06-26 7:13 ` sashiko-bot
2026-07-16 17:51 ` Namhyung Kim
2026-07-17 1:43 ` Jiebin Sun
2026-06-26 7:03 ` [PATCH 02/14] perf c2c: add function view browser skeleton Jiebin Sun
2026-06-26 7:11 ` sashiko-bot
2026-06-26 7:03 ` [PATCH 03/14] perf c2c: add function view type definitions and helpers Jiebin Sun
2026-06-26 7:14 ` sashiko-bot
2026-06-26 7:03 ` [PATCH 04/14] perf c2c: add column format infrastructure for function view Jiebin Sun
2026-06-26 7:03 ` [PATCH 05/14] perf c2c: add column entry functions " Jiebin Sun
2026-06-26 7:03 ` [PATCH 06/14] perf c2c: add comparison functions for function view sorting Jiebin Sun
2026-06-26 7:22 ` sashiko-bot
2026-06-26 7:03 ` [PATCH 07/14] perf c2c: add dimension definitions and format creation Jiebin Sun
2026-06-26 7:23 ` sashiko-bot
2026-06-26 7:03 ` [PATCH 08/14] perf c2c: add HPP list parsing for function view histograms Jiebin Sun
2026-06-26 7:16 ` sashiko-bot
2026-06-26 7:03 ` [PATCH 09/14] perf c2c: add stats merging and memory management helpers Jiebin Sun
2026-06-26 7:17 ` sashiko-bot
2026-06-26 7:03 ` [PATCH 10/14] perf c2c: add hierarchy entry creation and lookup functions Jiebin Sun
2026-06-26 7:19 ` sashiko-bot
2026-06-26 7:03 ` [PATCH 11/14] perf c2c: add function view hierarchy builder Jiebin Sun
2026-06-26 7:03 ` [PATCH 12/14] perf c2c: add function view browser UI Jiebin Sun
2026-06-26 7:03 ` [PATCH 13/14] perf c2c: add TAB key to switch to function view Jiebin Sun
2026-06-26 7:03 ` [PATCH 14/14] perf c2c: document function view in perf-c2c man page Jiebin Sun
2026-07-07 0:41 ` [PATCH 00/14] perf c2c: add a function view Namhyung Kim
2026-07-10 8:49 ` Jiebin Sun
2026-07-10 21:54 ` Namhyung Kim
2026-07-13 9:22 ` Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 " Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 01/14] perf c2c: extract shared data structures into c2c.h Jiebin Sun
2026-07-10 8:54 ` sashiko-bot
2026-07-10 8:42 ` [PATCH v2 02/14] perf c2c: add function view browser skeleton Jiebin Sun
2026-07-10 8:50 ` sashiko-bot
2026-07-10 8:42 ` [PATCH v2 03/14] perf c2c: add function view type definitions and helpers Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 04/14] perf c2c: add column format infrastructure for function view Jiebin Sun
2026-07-10 9:00 ` sashiko-bot
2026-07-10 8:42 ` [PATCH v2 05/14] perf c2c: add column entry functions " Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 06/14] perf c2c: add comparison functions for function view sorting Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 07/14] perf c2c: add dimension definitions and format creation Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 08/14] perf c2c: add HPP list parsing for function view histograms Jiebin Sun
2026-07-10 9:01 ` sashiko-bot
2026-07-10 8:42 ` [PATCH v2 09/14] perf c2c: add stats merging and memory management helpers Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 10/14] perf c2c: add hierarchy entry creation and lookup functions Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 11/14] perf c2c: add function view hierarchy builder Jiebin Sun
2026-07-10 9:01 ` sashiko-bot
2026-07-10 8:42 ` [PATCH v2 12/14] perf c2c: add function view browser UI Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 13/14] perf c2c: add TAB key to switch to function view Jiebin Sun
2026-07-10 8:42 ` [PATCH v2 14/14] perf c2c: document function view in perf-c2c man page Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 00/14] perf c2c: add a function view Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 01/14] perf c2c: extract shared data structures into c2c.h Jiebin Sun
2026-07-17 2:14 ` sashiko-bot
2026-07-17 2:05 ` [PATCH v3 02/14] perf c2c: add function view browser skeleton Jiebin Sun
2026-07-17 2:15 ` sashiko-bot
2026-07-17 2:05 ` [PATCH v3 03/14] perf c2c: add function view type definitions and helpers Jiebin Sun
2026-07-17 2:15 ` sashiko-bot
2026-07-17 2:05 ` [PATCH v3 04/14] perf c2c: add column format infrastructure for function view Jiebin Sun
2026-07-17 2:21 ` sashiko-bot
2026-07-17 2:05 ` [PATCH v3 05/14] perf c2c: add column entry functions " Jiebin Sun
2026-07-17 2:19 ` sashiko-bot
2026-07-17 2:05 ` [PATCH v3 06/14] perf c2c: add comparison functions for function view sorting Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 07/14] perf c2c: add dimension definitions and format creation Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 08/14] perf c2c: add HPP list parsing for function view histograms Jiebin Sun
2026-07-17 2:22 ` sashiko-bot
2026-07-17 2:05 ` [PATCH v3 09/14] perf c2c: add stats merging and memory management helpers Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 10/14] perf c2c: add hierarchy entry creation and lookup functions Jiebin Sun
2026-07-17 2:20 ` sashiko-bot
2026-07-17 2:05 ` [PATCH v3 11/14] perf c2c: add function view hierarchy builder Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 12/14] perf c2c: add function view browser UI Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 13/14] perf c2c: add TAB key to switch to function view Jiebin Sun
2026-07-17 2:05 ` [PATCH v3 14/14] perf c2c: document function view in perf-c2c man page Jiebin Sun
2026-07-18 4:58 ` [PATCH v3 00/14] perf c2c: add a function view Namhyung Kim
2026-07-20 8:39 ` Jiebin Sun
2026-07-23 5:40 ` Namhyung Kim
2026-07-24 10:10 ` [PATCH " Jiebin Sun
2026-07-24 9:58 ` [PATCH v4 0/9] " Jiebin Sun
2026-07-24 9:58 ` [PATCH v4 1/9] perf c2c: extract shared data structures into c2c.h Jiebin Sun
2026-07-24 9:58 ` [PATCH v4 2/9] perf c2c: add function view browser skeleton Jiebin Sun
2026-07-24 10:12 ` sashiko-bot
2026-07-24 9:58 ` [PATCH v4 3/9] perf c2c: add column rendering for function view Jiebin Sun
2026-07-24 10:09 ` sashiko-bot
2026-07-24 9:58 ` [PATCH v4 4/9] perf c2c: add HPP list parsing for function view columns Jiebin Sun
2026-07-24 10:02 ` sashiko-bot
2026-07-24 9:58 ` [PATCH v4 5/9] perf c2c: add function view stats merge and memory management Jiebin Sun
2026-07-24 9:58 ` Jiebin Sun [this message]
2026-07-24 9:58 ` [PATCH v4 7/9] perf c2c: build and finalize the function view hierarchy Jiebin Sun
2026-07-24 10:22 ` sashiko-bot
2026-07-24 9:58 ` [PATCH v4 8/9] perf c2c: add function view browser UI and cacheline detail Jiebin Sun
2026-07-24 9:58 ` [PATCH v4 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=20260724095842.995920-7-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