From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A9C9925742F; Fri, 10 Jul 2026 08:42:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672960; cv=none; b=VNHuELNqY4xh/GhjO7oHZyzBmJx9MS9jpxBv0Igcn3eLbXkgj3yj1jDO8faCZ9TUiwp6APJWQTHpElOkB8YjypnHtWIGvgNqwml3B5nMzezauzB0JEMMIc2h5t1Rma9aXHUWno3N+xmRuXM+zT4Zw0gCGgACIj1WmtdNTI/1Cow= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672960; c=relaxed/simple; bh=VpxaWHixIHvF6GGb8RtG214NQ5rleokKJbMSUsYn0gg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=G/DCz3iuOMCVVCCj9yIPu1wL/TBwSihkMsCXBfq440CtQ7jKsHe7EPJquCC8SilRPcuQNYKjAr61hDnsR+SWxPUUcBDJINLppbfGXG9U5nbRgEmArfmIGllBfl/9LTpEAC955ao1rnwx410OKuYdlIfhHfSTQKQpYB2Ipb3ifyw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=hz41V3XA; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="hz41V3XA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672958; x=1815208958; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VpxaWHixIHvF6GGb8RtG214NQ5rleokKJbMSUsYn0gg=; b=hz41V3XA4wdMV18MztqXyzL7+2/iarjdq+t/ZKY7613c3HEF/DY7Bc7U whMSWPlvd9zir7DjsOxtFFUhOXjfokqdepcZ9bEx9HNJSoHN33nCr1Lk9 Dv01+KbF8zyREDMPiQpyuqFEHq5RH5MQciGXcUOxDwBzVo3b9LyKLuUTk 5aw/J2Gw/hodYd+wVm2Ye/wrRQvQgRi2n+Y5mqHyKV7+KqusNsYVYRuAP pbg8ddpHHdtY8BogTnbYIS9V3qVKsfgeKqX4Sr4LkIw1zE7rXSSoTXGeJ fcqUdNeQ8SNW9UxUlqBXfWz1f08YP8M9BoevscVap80fV6WWesTRb6BgH Q==; X-CSE-ConnectionGUID: aQG5Xx6JQJWXYSeWavKuZg== X-CSE-MsgGUID: 7tV3CXEMSmuxqRkCFM+u2g== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390774" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390774" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:42:38 -0700 X-CSE-ConnectionGUID: XWLjY0niTZ2NzwRb2fvcHA== X-CSE-MsgGUID: nV/65W37QL+M5AbMGSeQ6g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435311" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:42:33 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 01/14] perf c2c: extract shared data structures into c2c.h Date: Fri, 10 Jul 2026 16:42:34 +0800 Message-ID: <20260710084247.3576706-2-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move c2c_hists, compute_stats, c2c_hist_entry, and perf_c2c structure definitions from builtin-c2c.c into a new shared header c2c.h. This allows the upcoming function view browser (c2c-function.c) to reuse these types. Make the global perf_c2c instance 'c2c' non-static and export perf_c2c__browse_cacheline() so they can be accessed from the new function view module. No functional change. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/builtin-c2c.c | 124 ++------------------------------- tools/perf/c2c.h | 147 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 118 deletions(-) create mode 100644 tools/perf/c2c.h diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index c9584dbedf77..33271554e354 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -38,6 +38,7 @@ #include "mem-events.h" #include "mem-info.h" #include "mem2node.h" +#include "c2c.h" #include "pmus.h" #include "session.h" #include "sort.h" @@ -52,75 +53,9 @@ #include "util/symbol.h" #include "util/util.h" =20 -struct c2c_hists { - struct hists hists; - struct perf_hpp_list list; - struct c2c_stats stats; -}; - -struct compute_stats { - struct stats lcl_hitm; - struct stats rmt_hitm; - struct stats lcl_peer; - struct stats rmt_peer; - struct stats load; -}; - -struct c2c_hist_entry { - struct c2c_hists *hists; - struct evsel *evsel; - struct c2c_stats stats; - unsigned long *cpuset; - unsigned long *nodeset; - struct c2c_stats *node_stats; - unsigned int cacheline_idx; - - struct compute_stats cstats; - - unsigned long paddr; - unsigned long paddr_cnt; - bool paddr_zero; - char *nodestr; - - /* - * must be at the end, - * because of its callchain dynamic entry - */ - struct hist_entry he; -}; =20 static char const *coalesce_default =3D "iaddr"; =20 -struct perf_c2c { - struct perf_tool tool; - struct c2c_hists hists; - struct mem2node mem2node; - - unsigned long **nodes; - int nodes_cnt; - int cpus_cnt; - int *cpu2node; - int node_info; - - bool show_src; - bool show_all; - bool use_stdio; - bool stats_only; - bool symbol_full; - bool stitch_lbr; - - /* Shared cache line stats */ - struct c2c_stats shared_clines_stats; - int shared_clines; - - int display; - - const char *coalesce; - char *cl_sort; - char *cl_resort; - char *cl_output; -}; - enum { DISPLAY_LCL_HITM, DISPLAY_RMT_HITM, @@ -141,9 +76,9 @@ static const struct option c2c_options[] =3D { OPT_END() }; =20 -static struct perf_c2c c2c; +struct perf_c2c c2c; =20 -static void *c2c_he_zalloc(size_t size) +void *c2c_he_zalloc(size_t size) { struct c2c_hist_entry *c2c_he; =20 @@ -458,36 +393,6 @@ static const char * const __usage_report[] =3D { =20 static const char * const *report_c2c_usage =3D __usage_report; =20 -#define C2C_HEADER_MAX 2 - -struct c2c_header { - struct { - const char *text; - int span; - } line[C2C_HEADER_MAX]; -}; - -struct c2c_dimension { - struct c2c_header header; - const char *name; - int width; - struct sort_entry *se; - - int64_t (*cmp)(struct perf_hpp_fmt *fmt, - struct hist_entry *, struct hist_entry *); - int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hist_entry *he); - int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hist_entry *he); -}; - -struct c2c_fmt { - struct perf_hpp_fmt fmt; - struct c2c_dimension *dim; -}; - -#define SYMBOL_WIDTH 30 - static struct c2c_dimension dim_symbol; static struct c2c_dimension dim_srcline; =20 @@ -1389,23 +1294,6 @@ cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct = perf_hpp *hpp, return scnprintf(hpp->buf, hpp->size, "%*s", width, ""); } =20 -#define HEADER_LOW(__h) \ - { \ - .line[1] =3D { \ - .text =3D __h, \ - }, \ - } - -#define HEADER_BOTH(__h0, __h1) \ - { \ - .line[0] =3D { \ - .text =3D __h0, \ - }, \ - .line[1] =3D { \ - .text =3D __h1, \ - }, \ - } - #define HEADER_SPAN(__h0, __h1, __s) \ { \ .line[0] =3D { \ @@ -1928,7 +1816,7 @@ static struct c2c_dimension *dimensions[] =3D { NULL, }; =20 -static void fmt_free(struct perf_hpp_fmt *fmt) +void fmt_free(struct perf_hpp_fmt *fmt) { struct c2c_fmt *c2c_fmt; =20 @@ -1936,7 +1824,7 @@ static void fmt_free(struct perf_hpp_fmt *fmt) free(c2c_fmt); } =20 -static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) +bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) { struct c2c_fmt *c2c_a =3D container_of(a, struct c2c_fmt, fmt); struct c2c_fmt *c2c_b =3D container_of(b, struct c2c_fmt, fmt); @@ -2710,7 +2598,7 @@ c2c_cacheline_browser__new(struct hists *hists, struc= t hist_entry *he) return browser; } =20 -static int perf_c2c__browse_cacheline(struct hist_entry *he) +int perf_c2c__browse_cacheline(struct hist_entry *he) { struct c2c_hist_entry *c2c_he; struct c2c_hists *c2c_hists; diff --git a/tools/perf/c2c.h b/tools/perf/c2c.h new file mode 100644 index 000000000000..5c3f6ae633ea --- /dev/null +++ b/tools/perf/c2c.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PERF_C2C_H_ +#define _PERF_C2C_H_ 1 + +#include +#include +#include +#include "util/stat.h" +#include "util/hist.h" +#include "util/mem-events.h" +#include "util/mem2node.h" +#include "util/tool.h" + +struct sort_entry; + +struct compute_stats { + struct stats lcl_hitm; + struct stats rmt_hitm; + struct stats lcl_peer; + struct stats rmt_peer; + struct stats load; +}; + +struct c2c_hists { + struct hists hists; + struct perf_hpp_list list; + struct c2c_stats stats; +}; + +struct c2c_hist_entry { + struct c2c_hists *hists; + struct evsel *evsel; + struct c2c_stats stats; + unsigned long *cpuset; + unsigned long *nodeset; + struct c2c_stats *node_stats; + unsigned int cacheline_idx; + + struct compute_stats cstats; + + unsigned long paddr; + unsigned long paddr_cnt; + bool paddr_zero; + char *nodestr; + + /* + * Function view only: cached sum of the level-2 children's store + * counts, accumulated while the hierarchy is built. Lets the + * total-stores column and its sort comparator avoid an O(children) + * walk on every access. Unused by the cacheline view. + */ + u64 child_stores; + + /* + * must be at the end, + * because of its callchain dynamic entry + */ + struct hist_entry he; +}; + +struct perf_c2c { + struct perf_tool tool; + struct c2c_hists hists; + struct mem2node mem2node; + + unsigned long **nodes; + int nodes_cnt; + int cpus_cnt; + int *cpu2node; + int node_info; + + bool show_src; + bool show_all; + bool use_stdio; + bool stats_only; + bool symbol_full; + bool stitch_lbr; + + /* Shared cache line stats */ + struct c2c_stats shared_clines_stats; + int shared_clines; + + int display; + + const char *coalesce; + char *cl_sort; + char *cl_resort; + char *cl_output; +}; + +extern struct perf_c2c c2c; + +#define C2C_HEADER_MAX 2 +#define SYMBOL_WIDTH 30 + +#define HEADER_LOW(__h) \ + { \ + .line[1] =3D { \ + .text =3D __h, \ + }, \ + } + +#define HEADER_BOTH(__h0, __h1) \ + { \ + .line[0] =3D { \ + .text =3D __h0, \ + }, \ + .line[1] =3D { \ + .text =3D __h1, \ + }, \ + } + +struct c2c_header { + struct { + const char *text; + int span; + } line[C2C_HEADER_MAX]; +}; + +struct c2c_dimension { + struct c2c_header header; + const char *name; + int width; + struct sort_entry *se; + + int64_t (*cmp)(struct perf_hpp_fmt *fmt, + struct hist_entry *left, struct hist_entry *right); + int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he); + int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he); +}; + +struct c2c_fmt { + struct perf_hpp_fmt fmt; + struct c2c_dimension *dim; +}; + +void *c2c_he_zalloc(size_t size); +void fmt_free(struct perf_hpp_fmt *fmt); +bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); + +#ifdef HAVE_SLANG_SUPPORT +int perf_c2c__browse_cacheline(struct hist_entry *he); +#endif + +#endif /* _PERF_C2C_H_ */ --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F1E43F1AB9; Fri, 10 Jul 2026 08:42:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672964; cv=none; b=EWFT8rTXA6Q6Za0kEMygmkAt9z7Iw8Z6dcdfgByqc8ov4OC5KtpEbVsoo+TgdNUzIPhUONJZbSBg2YTg815ZNcu6zqgBbzCOI9yCi+R54R0KW4PGF+gTSKngPaV/5Lz29AtLmaapyx93OswNhcF8KT/iNVulw4CYM2GPXpkfpCs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672964; c=relaxed/simple; bh=7ARFCtiyQ0mdwUlF4qKBVojXRwHPX9YvqZCwKOLJ/hg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Kvit7XZ9+jutghJkmkT1e8ZgD5KJ3eHKgfbyHJNoJqgD0AAvdhkx8taYJ0pLczxgX137SgyXyPvch/73ykHG+uPdACdVpWKaNH5i2Bwav8NK6ScbupVsA/EDICERn2+NXGqCG/DJ84g44Mp3NGnsVmrlo2aOV3eUdU6ifEkSNbc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=GJT1e0T8; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="GJT1e0T8" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672963; x=1815208963; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7ARFCtiyQ0mdwUlF4qKBVojXRwHPX9YvqZCwKOLJ/hg=; b=GJT1e0T8kSWTRbNf5piKPQ/uMmo4pb4Skl8uMHTJY5Fgfk0q47YzUa33 7C5hucmHgeqxoUtOyq690TBqWlORhUmic6DgXgEDFIn7ROHQ80RtTHsi/ rsDAa1EZhoPQKkIJnDFr4I7n2eBRhzwuO5+B86V5jggcFZwQkl8tjjYbu J40m4XgyKOgUwr4YFgchDQn8qgqn7+/u0F+YodlSL6jM3j2QRiJeSvd8S jNe+Q/mXHhnXHhEKftUW+l5N02zQAq+FohSbk2QjO1ddSWdQNR/Xn9EdY an7S39BoKwh3vLKCprd86zmRF1+aIzdDv7YlWYHpyMc1JBiXEPav5sPVO g==; X-CSE-ConnectionGUID: ODITmqKZS+mj/KlSxHIPAg== X-CSE-MsgGUID: ZvSp0ublT9Sb4+aZwD+lsQ== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390794" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390794" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:42:42 -0700 X-CSE-ConnectionGUID: gN2mKdjsQnywqDhRZPw/Hw== X-CSE-MsgGUID: tze00yY2SMmytnZ7ffunLw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435318" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:42:38 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 02/14] perf c2c: add function view browser skeleton Date: Fri, 10 Jul 2026 16:42:35 +0800 Message-ID: <20260710084247.3576706-3-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add c2c-function.c with a stub perf_c2c__browse_function_view() entry point and register it in the build system. Declare the function prototype in c2c.h. This lays the groundwork for the function-level cacheline sharing analysis browser that will be implemented in subsequent patches. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/c2c.h | 1 + tools/perf/ui/browsers/Build | 1 + tools/perf/ui/browsers/c2c-function.c | 44 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 tools/perf/ui/browsers/c2c-function.c diff --git a/tools/perf/c2c.h b/tools/perf/c2c.h index 5c3f6ae633ea..ffcd43d4c903 100644 --- a/tools/perf/c2c.h +++ b/tools/perf/c2c.h @@ -142,6 +142,7 @@ bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_= fmt *b); =20 #ifdef HAVE_SLANG_SUPPORT int perf_c2c__browse_cacheline(struct hist_entry *he); +int perf_c2c__browse_function_view(struct hists *hists); #endif =20 #endif /* _PERF_C2C_H_ */ diff --git a/tools/perf/ui/browsers/Build b/tools/perf/ui/browsers/Build index a07489e44765..ae67a2161f7d 100644 --- a/tools/perf/ui/browsers/Build +++ b/tools/perf/ui/browsers/Build @@ -5,3 +5,4 @@ perf-ui-y +=3D map.o perf-ui-y +=3D scripts.o perf-ui-y +=3D header.o perf-ui-y +=3D res_sample.o +perf-ui-y +=3D c2c-function.o diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c new file mode 100644 index 000000000000..040266288be3 --- /dev/null +++ b/tools/perf/ui/browsers/c2c-function.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * C2C Function Browser - function-level cacheline sharing analysis + * + * Planned UI: 3-level hierarchy showing which functions share cachelines = (not implemented yet): + * Level 1: Primary functions sorted by Cycles % (estimated load cycles) + * Level 2: Other functions sharing cachelines with the level-1 function + * Level 3: Specific shared cachelines between each pair of functions + * + * Uses c2c_hist_entry->hists to build the hierarchy without adding any + * per-entry state to the existing c2c data structures. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../browser.h" +#include "../helpline.h" +#include "../keysyms.h" +#include "../libslang.h" +#include "../ui.h" +#include "../../util/addr_location.h" +#include "../../util/cacheline.h" +#include "../../util/debug.h" +#include "../../util/hist.h" +#include "../../util/map.h" +#include "../../util/mem-events.h" +#include "../../util/mem-info.h" +#include "../../util/sort.h" +#include "../../util/symbol.h" +#include "../../util/thread.h" +#include "../../c2c.h" +#include "hists.h" + +int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) +{ + ui__warning("C2C function view is not implemented yet.\n"); + return -ENOSYS; +} --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 156523F20FC; Fri, 10 Jul 2026 08:42:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672969; cv=none; b=Y464KdXgMWtEQGazL8meu24FkZHZnF2rgSwwwyt5bANOPoyGpW3vZfNxJOdD3IuLt3tHLcfQPllBympXyWg+U17/1miygOQD16SEkOR8mbKmPNQGHz2O2Knd8Y76RKkAvS+TCe/a930tUOx/Es9gYbSrV0H5oRu3HU892PXB3xk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672969; c=relaxed/simple; bh=ACA+l2tFRTl838fEEpWhN9TkeLd2KYYm60b5EBAW6rk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IKVtdtiQ6WfwDT+gWHmEW1BOttBWtwbUdTGa58Z4NU0G6PbbLfWgaEpmjB1nVgPgZ6YTIq9JySHxKJ2NQkTtO2AwXhQzw2fcN7MfPYzThZPeeeYETHDSSyrE4xZFChtTvHVvEM6Cuiyc7y5D0gcUZL+GWMtZRM2rQcRiQsIbYmo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=nfw8FBrB; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="nfw8FBrB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672967; x=1815208967; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ACA+l2tFRTl838fEEpWhN9TkeLd2KYYm60b5EBAW6rk=; b=nfw8FBrB6VhWVA9ByyQRUNDSiHBCH3b7Qnbi8pR1/qYDHTwAXZ4At+cs mkvIbUSspV+Lf2rdIEucBMIhhcLHL0E0k6t8ZtXZvu7yctdH6FY2wk3FZ Iut9FrZeeU/7G6DBm1dqzxedyJQbnvR/Y/BiClaCVUClfWNzCQ3OKcxG5 617alkZgbA7vG7NPSis+rolspHKH63xD0SPIWuL/H/CeqO2dQm+Nq9NZ7 riOo656faMTOPHOtuK4HlujBXYIheGCN/44koRUcqg8kon27p9v7Y7OTW qBRpYlBco0HXDAEbm6X9xyNOuDCTxuJyAPzTrVI/mcA/ssRclFDLnTiIo g==; X-CSE-ConnectionGUID: 8H4YBsnuQTmOxsCHe5gzfA== X-CSE-MsgGUID: Zet7kLnkQxyl0rHjX3LuLQ== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390807" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390807" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:42:47 -0700 X-CSE-ConnectionGUID: iTYJQ43STIOCBgKdamcSZw== X-CSE-MsgGUID: kczTEktATPOdHIdgyMpRVw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435328" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:42:43 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 03/14] perf c2c: add function view type definitions and helpers Date: Fri, 10 Jul 2026 16:42:36 +0800 Message-ID: <20260710084247.3576706-4-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the foundational type definitions and helper functions for the function view browser: - perf_c2c_ext: extended context holding function-grouped histograms - c2c_function_browser: browser state wrapping hist_browser - symbol_name_equal(): symbol comparison by name - hist_entry__iaddr(): instruction address extraction helper - c2c_hitm_count(): inline accessor for a c2c_stats HITM total Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 040266288be3..dbc912a4a242 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -37,6 +37,35 @@ #include "../../c2c.h" #include "hists.h" =20 +struct perf_c2c_ext { + struct c2c_hists function_hists; + /* Cached across all level-1 entries; 0 means "not yet computed". */ + u64 total_cycles; +}; + +static struct perf_c2c_ext c2c_ext __maybe_unused; + +struct c2c_function_browser { + struct hist_browser hb; +}; + +static __maybe_unused inline u64 c2c_hitm_count(const struct c2c_stats *st= ats) +{ + return stats->tot_hitm; +} + +static __maybe_unused inline bool symbol_name_equal(struct symbol *a, stru= ct symbol *b) +{ + return a && b && arch__compare_symbol_names(a->name, b->name) =3D=3D 0; +} + +static __maybe_unused inline u64 hist_entry__iaddr(struct hist_entry *he) +{ + if (he->mem_info) + return mem_info__iaddr(he->mem_info)->addr; + return he->ip; +} + int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) { ui__warning("C2C function view is not implemented yet.\n"); --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 01CF2296BD2; Fri, 10 Jul 2026 08:42:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672975; cv=none; b=ANCnorP7VBjbVR+7yCnN6/oFg4hYDJAgVOpoSZ+FLuHUcmsZShJoJRrwtW3UjbQpjfTRZzBQRLkkHHZcp2pfZAdqq8qvF0k7nT+04WgHkqNBo+2oIjTMylXVzu+8eLT2uGsE/SPbKvvit95pTF/RB1Rx5Sy0Xae6Cohut+RYZXk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672975; c=relaxed/simple; bh=aCOVCEKNtoWzYGR9+mlkMjzBTHh42oLszM4HeGaR9wE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SdWqak8ua2xZwiCDewJSZ5s6TsuXSZ0UB2B1DhrTwTUJgRTkXFv9AHcKtCbCKPC79ElXs5xFi934yaS1JJ8bgrGGjauFIEZZVbAVyvHVee7sDGzUC547HOuX2hhK3dUbGG+OkZ4V8M2mc3/q0QaG4XydNOkY7duB86vybudZZgo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Sscq2Rxm; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Sscq2Rxm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672972; x=1815208972; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=aCOVCEKNtoWzYGR9+mlkMjzBTHh42oLszM4HeGaR9wE=; b=Sscq2RxmQsk3PkuGvBDXXK0QlnWkKuw1G4RCjf8fr8rSJzjP8Arg6AOe TQpD7IEnKpepGXHNNCAIMQaSRXgtVx0fOmhgAT0opkoDWtipri7dqQVoF bP8X50i30w5JErKaJzDbe+uMs2hLO0BRlV/X5aPSrjCKaiySob0JleaQP lE4pe+w8vuxmDFjFlGKeMz370x67hWrJqkqLlvfbRqfQM3t0i//sgNll8 4yPWqo1aVPJiC8bXHzUXI7Ud+G511GZ9kUYz9b8+D6m4EGB7/XeYYVcDP tUDIMZ8bgNaoMKk1hE2J9ZXuVxyO4DyzxaAHzFtOrfraXsVj7+P4zCLIM Q==; X-CSE-ConnectionGUID: +K53cpsuQbSEBTFRmhJYNg== X-CSE-MsgGUID: HOLZ2qerSl2OjrQnNggNFA== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390814" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390814" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:42:52 -0700 X-CSE-ConnectionGUID: amRU1MFvRZOElXwSY83IAA== X-CSE-MsgGUID: mtAk58O4Tv6AF3x6m0x4sQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435344" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:42:47 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 04/14] perf c2c: add column format infrastructure for function view Date: Fri, 10 Jul 2026 16:42:37 +0800 Message-ID: <20260710084247.3576706-5-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- 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(stru= ct hist_entry *he) return he->ip; } =20 +static __maybe_unused int symbol_width(struct hists *hists, struct sort_en= try *se) +{ + int width =3D hists__col_len(hists, se->se_width_idx); + + if (!c2c.symbol_full && width > SYMBOL_WIDTH) + width =3D 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 =3D container_of(fmt, struct c2c_fmt, fmt); + dim =3D c2c_fmt->dim; + + if (dim =3D=3D &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 =3D NULL; + int width =3D c2c_width(fmt, hpp, hists); + + c2c_fmt =3D container_of(fmt, struct c2c_fmt, fmt); + dim =3D c2c_fmt->dim; + + if (dim->se) { + text =3D dim->header.line[line].text; + /* Use the last line from sort_entry if not defined. */ + if (!text && line =3D=3D hists->hpp_list->nr_header_lines - 1) + text =3D dim->se->se_header; + } else { + text =3D dim->header.line[line].text; + + if (span) { + if (*span) { + (*span)--; + return 0; + } + + *span =3D dim->header.line[line].span; + } + } + + if (text =3D=3D NULL) + text =3D ""; + + 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 *c2= c_he) +{ + double cycles_rmt, cycles_lcl, cycles_load; + u64 other_load, total_hitm; + + cycles_rmt =3D avg_stats(&c2c_he->cstats.rmt_hitm) * c2c_he->stats.rmt_hi= tm; + cycles_lcl =3D avg_stats(&c2c_he->cstats.lcl_hitm) * c2c_he->stats.lcl_hi= tm; + total_hitm =3D c2c_he->stats.tot_hitm; + other_load =3D (c2c_he->stats.load >=3D total_hitm) ? c2c_he->stats.load = - total_hitm : 0; + cycles_load =3D 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 =3D 0; + + for (nd =3D rb_first_cached(&c2c_ext.function_hists.hists.entries); nd; + nd =3D rb_next(nd)) { + struct hist_entry *he =3D rb_entry(nd, struct hist_entry, rb_node); + struct c2c_hist_entry *c2c_he =3D container_of(he, struct c2c_hist_entry= , he); + + total +=3D 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 =3D 0; + + for (nd =3D rb_first_cached(&he->hroot_out); nd; nd =3D rb_next(nd)) { + struct hist_entry *child =3D rb_entry(nd, struct hist_entry, rb_node); + struct c2c_hist_entry *c2c_child =3D + container_of(child, struct c2c_hist_entry, he); + + sum +=3D (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"); --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C9E243F23BB; Fri, 10 Jul 2026 08:42:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672981; cv=none; b=ov/UZIPgmH1XTtrl1OJ8oro3tkyKNS7Ft7KoCXTuLiKltulWn26rNQD6w669D+wdUu503b3WNPLDvcLtx7RJQIb4GPUjAZHhY94oJhzVdvJWEG4+oGo6yXD6gdbgx07hJqnh+Y4OGfyttShHR/DAEhvIVFg8QaGLk/95V/IzccE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672981; c=relaxed/simple; bh=lkOjkGYo60jE1HJmYzh6LLi8IAJ+IpegQZfi94hNH2w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mKJ4O4yeJxtwbQlh2iLgW1l1lc/1Ksjx7IuU1sXes7Ah9QPBrt5RteOoDHjB18v5YJU0OzFNn4V2X3tfJkk55EitzacUb30yksMHisnKPzW6oSnazqRXwGvm3uYb3w1Zi8J1mMvUryhTW07yDq8jfKLI5y0F0a6dAQ5CwO4T4hY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=kiqr+XJ/; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="kiqr+XJ/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672977; x=1815208977; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lkOjkGYo60jE1HJmYzh6LLi8IAJ+IpegQZfi94hNH2w=; b=kiqr+XJ/jRRZlKBS1N8LWHUldZ0nj4c2zXIef5egGsxEh4RTVBQ3tG5g xq3hwMEdlb+VeNncUDn6F1+JeyN7nYOVphVd1DP88zYLDok6LHCpX8zfC xMM8kylZ290fGQIZ5/DiaAQut71N+qsyS0LTcSiI5kBGg2kLRTEmvCPKB NpzVWeSj3fuA3EurMFIfYOre2gfe1tZdZSelMiDzCqhDZKn2CkcWK/NJb 2YQ1Hniv78dHT6UyhU5t0Hk2CTwZKs9Qmv1ZD5tcQAyWI9hnVC2cy7+yt wqwhuu3mRtUjcPAqrLObLWgdEJk0FE4msiwBMNo76Jk5Ad9AgMa1h6sRA w==; X-CSE-ConnectionGUID: gd6IqRH5R1C1yu4H5o8+7g== X-CSE-MsgGUID: O+ziC59XSVCcirX5VEU3LQ== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390822" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390822" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:42:56 -0700 X-CSE-ConnectionGUID: yPXsC8CWTeGswzqV25U1pA== X-CSE-MsgGUID: lfJyzT3NRJiSLHEkjFUzCQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435350" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:42:52 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 05/14] perf c2c: add column entry functions for function view Date: Fri, 10 Jul 2026 16:42:38 +0800 Message-ID: <20260710084247.3576706-6-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add rendering functions for each column in the function view: - total_stores_entry(): render store count, summing children for L1 - cacheline_symbol_entry(): render cacheline address for L3 entries - iaddr_symbol_entry(): render code address with fold indicators - symbol_view_entry(): render symbol name with fold indicators - cycles_percent_entry(): render estimated load-cycle percentage for L1 (HITM, peer-snoop and other-load cycles) Each entry function handles the 3-level hierarchy by checking parent_he depth to decide what to display. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 148 ++++++++++++++++++++++++-- 1 file changed, 138 insertions(+), 10 deletions(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index d718cab6537d..0ee5fd571e48 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -167,20 +167,148 @@ static __maybe_unused u64 c2c_ext__total_cycles(void) return total; } =20 -/* Sum child entries' store counts under a level-1 hist_entry. */ +/* + * Sum of the level-2 children's store counts under a level-1 hist_entry. + * Read from the cache populated by the hierarchy builder, so this is O(1) + * and safe to call from the sort comparator. + */ static __maybe_unused u64 hist_entry__child_stores(struct hist_entry *he) { - struct rb_node *nd; - u64 sum =3D 0; + struct c2c_hist_entry *c2c_he =3D container_of(he, struct c2c_hist_entry,= he); =20 - for (nd =3D rb_first_cached(&he->hroot_out); nd; nd =3D rb_next(nd)) { - struct hist_entry *child =3D rb_entry(nd, struct hist_entry, rb_node); - struct c2c_hist_entry *c2c_child =3D - container_of(child, struct c2c_hist_entry, he); + return c2c_he->child_stores; +} =20 - sum +=3D (u64)c2c_child->stats.store; - } - return sum; +static __maybe_unused int +total_stores_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he) +{ + struct c2c_hist_entry *c2c_he =3D container_of(he, struct c2c_hist_entry,= he); + int width =3D c2c_width(fmt, hpp, he->hists); + u64 total; + + /* L1 shows the sum of sharing-function stores; L2/L3 show their own. */ + total =3D he->parent_he ? (u64)c2c_he->stats.store : hist_entry__child_st= ores(he); + + return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, total); +} + +/* + * cacheline_symbol_entry - Render cacheline address for function view + */ +static __maybe_unused int +cacheline_symbol_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he) +{ + int width =3D c2c_width(fmt, hpp, he->hists); + char buf[24]; + u64 addr; + + /* Only show the address on level-3 cacheline entries. */ + if (!he->parent_he || !he->parent_he->parent_he || !he->mem_info) + return scnprintf(hpp->buf, hpp->size, "%*s", width, ""); + + addr =3D cl_address(mem_info__daddr(he->mem_info)->addr, chk_double_cl); + scnprintf(buf, sizeof(buf), "0x%" PRIx64, addr); + + return scnprintf(hpp->buf, hpp->size, "%*s", width, buf); +} + +/* Render the code (instruction) address for level-1 and level-2 entries. = */ +static __maybe_unused int +iaddr_symbol_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he) +{ + int width =3D c2c_width(fmt, hpp, he->hists); + int iaddr_width, ret; + char buf[24]; + u64 addr; + char folded_sign; + + /* Hide for cacheline (level-3) entries. */ + if (he->parent_he && he->parent_he->parent_he) + return scnprintf(hpp->buf, hpp->size, "%*s", width, ""); + + addr =3D hist_entry__iaddr(he); + + folded_sign =3D he->has_children ? (he->unfolded ? '-' : '+') : ' '; + ret =3D scnprintf(hpp->buf, hpp->size, "%c ", folded_sign); + + iaddr_width =3D width - ret; + if (iaddr_width <=3D 0) + return ret; + + scnprintf(buf, sizeof(buf), "0x%" PRIx64, addr); + ret +=3D scnprintf(hpp->buf + ret, hpp->size - ret, "%*.*s", iaddr_width,= iaddr_width, buf); + return ret; +} + +/* + * symbol_view_entry - Render symbol name for function view with expansion= indicators + */ +static __maybe_unused int +symbol_view_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he) +{ + int width =3D c2c_width(fmt, hpp, he->hists); + int sym_width; + int ret; + char symbuf[512]; + char folded_sign; + + /* Hide Symbol for cacheline entries */ + if (he->parent_he && he->parent_he->parent_he) + return scnprintf(hpp->buf, hpp->size, "%*s", width, ""); + + folded_sign =3D he->has_children ? (he->unfolded ? '-' : '+') : ' '; + + ret =3D scnprintf(hpp->buf, hpp->size, "%c ", folded_sign); + + sym_width =3D width - ret; + + if (sym_width <=3D 0) + return ret; + + /* sort_sym.se_snprintf is statically set and never cleared. */ + sort_sym.se_snprintf(he, symbuf, sizeof(symbuf), sym_width); + + ret +=3D scnprintf(hpp->buf + ret, hpp->size - ret, "%-*.*s", sym_width, = sym_width, symbuf); + return ret; +} + +/* + * cycles_percent_entry - Render cycles percentage column + */ +static __maybe_unused int +cycles_percent_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he) +{ + struct c2c_hist_entry *c2c_he; + int width =3D c2c_width(fmt, hpp, he->hists); + u64 fn_cycles, total_cycles; + char folded_sign; + double pct; + int ret, pct_width; + + /* Hide Cycles Percent for child functions and cachelines. */ + if (he->parent_he) + return scnprintf(hpp->buf, hpp->size, "%*s", width, ""); + + c2c_he =3D container_of(he, struct c2c_hist_entry, he); + fn_cycles =3D c2c_hist_entry__cycles(c2c_he); + /* Populated by build_function_view_hierarchy() once the L1 tree is built= . */ + total_cycles =3D c2c_ext.total_cycles; + pct =3D total_cycles > 0 ? (double)fn_cycles / total_cycles * 100.0 : 0.0; + + /* Add folded sign only for level-1 entries */ + folded_sign =3D he->has_children ? (he->unfolded ? '-' : '+') : ' '; + ret =3D scnprintf(hpp->buf, hpp->size, "%c ", folded_sign); + + pct_width =3D width - ret; + if (pct_width <=3D 0) + return ret; + ret +=3D scnprintf(hpp->buf + ret, hpp->size - ret, "%*.2f%%", pct_width = - 1, pct); + return ret; } =20 int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 90AE83F1ACE; Fri, 10 Jul 2026 08:43:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672985; cv=none; b=h7UOx3LgDxoT2LGXI9CTnHUCL8eggP0eDYH/rJbZmoxOoV31SwEY3SBDgFikfMFgl5PZXJMhReHNDA490ROiyKV3us+5cClOG6wv2Mxf4sJiK3avcFSjKzZhuWWNBArlB1yOgMTC5wp8AACfguboIhmQMr7aAoPzO3BTn1z8H0w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672985; c=relaxed/simple; bh=dpE2CHpNbPNW2ZpnqkPf9m/RvQnsOyxkbBr/FIchIeo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MCzE0I2QHYe1Y/C62Qz3jU7pE53iar58JXKYvMvN0a0YjlIx4XmgAPAZHuxcN1Mc5bczJDz/7GgsEJ9+tVgUnkBOfvWcw5tMPa2lAoKpvMKNizb5Qmm7U57sdcJ+qsxaiMBU0XoxoUGsK9NkLIz/tlsSKtwQs41VYMi8hlJYAfU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=HwRun5jP; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="HwRun5jP" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672982; x=1815208982; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=dpE2CHpNbPNW2ZpnqkPf9m/RvQnsOyxkbBr/FIchIeo=; b=HwRun5jPkhFJZyQLAMRoXrtZqZ5uFwLJTR5ycdU18gD3L10oC82A8zjZ CzsZB4jN81mOu7Yq+zYmqFDJkYZjHuBuDp1jREpABj7xAKLAXw7PvBWcV Kc4ZDafwEzUaBMXSO/nBsAox1bOQGqtowEM9e1NzkStmzUjd63QTagtie dQfwuPdgNt8hW5pWGyR9a5lBqgpkSofHBFvqUd0XxW05AB75ZH54uiNie tPfomIgVs8ObxyyvDVth+A4A1rejho8CjUsYZD2VQvzIaQPHJOAtSJask h6qfYDBPHThUnRvGjmfhyAeRJ7Kw+f62n4AxKXRptlYMBRV+In0F74EEu w==; X-CSE-ConnectionGUID: otPQisXgTG2hfRZ20cH8uQ== X-CSE-MsgGUID: 6sTv/w+jSJKheyF1S/SdsA== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390833" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390833" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:01 -0700 X-CSE-ConnectionGUID: IsCa2lYwQkms0b0JLT3lGg== X-CSE-MsgGUID: 7ACnjceaS5KTcEa6Mb64sA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435363" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:42:57 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 06/14] perf c2c: add comparison functions for function view sorting Date: Fri, 10 Jul 2026 16:42:39 +0800 Message-ID: <20260710084247.3576706-7-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add sort comparison functions for the function view columns: - cycles_percent_cmp(): compare by weighted HITM cycle count - iaddr_symbol_cmp(): compare by instruction address - total_stores_cmp(): compare by store count - empty_cmp(): no-op comparator for display-only columns Use overflow-safe (a > b) - (a < b) pattern for unsigned comparisons in cycles_percent_cmp() and total_stores_cmp(). Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 75 +++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 0ee5fd571e48..d5763af307b6 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -311,6 +311,81 @@ cycles_percent_entry(struct perf_hpp_fmt *fmt, struct = perf_hpp *hpp, return ret; } =20 +/* + * cycles_percent_cmp - Comparison function for cycles percentage sorting + */ +static __maybe_unused int64_t +cycles_percent_cmp(struct perf_hpp_fmt *fmt __maybe_unused, + struct hist_entry *left, struct hist_entry *right) +{ + struct c2c_hist_entry *c2c_left =3D container_of(left, struct c2c_hist_en= try, he); + struct c2c_hist_entry *c2c_right =3D container_of(right, struct c2c_hist_= entry, he); + u64 cycles_left, cycles_right; + + /* Cycles Percent is only shown for level-1 entries; others compare equal= . */ + if (left->parent_he || right->parent_he) + return 0; + + cycles_left =3D c2c_hist_entry__cycles(c2c_left); + cycles_right =3D c2c_hist_entry__cycles(c2c_right); + + return (cycles_left > cycles_right) - (cycles_left < cycles_right); +} + +/* + * iaddr_symbol_cmp - Comparison function for instruction address sorting + */ +static __maybe_unused int64_t +iaddr_symbol_cmp(struct perf_hpp_fmt *fmt __maybe_unused, + struct hist_entry *left, struct hist_entry *right) +{ + u64 left_iaddr, right_iaddr; + + /* IAddr is hidden for level-3 cacheline entries; they compare equal. */ + if ((left->parent_he && left->parent_he->parent_he) || + (right->parent_he && right->parent_he->parent_he)) + return 0; + + left_iaddr =3D hist_entry__iaddr(left); + right_iaddr =3D hist_entry__iaddr(right); + + /* + * Order by instruction address, same direction as sort__iaddr_cmp() + * (which returns r - l). Uses hist_entry__iaddr(), which falls back to + * he->ip when mem_info is NULL, so it matches what iaddr_symbol_entry() + * displays. + */ + return (left_iaddr < right_iaddr) - (left_iaddr > right_iaddr); +} + +static __maybe_unused int64_t +empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused, + struct hist_entry *left __maybe_unused, + struct hist_entry *right __maybe_unused) +{ + return 0; +} + +/* + * total_stores_cmp - Comparison function for total stores sorting + */ +static __maybe_unused int64_t +total_stores_cmp(struct perf_hpp_fmt *fmt __maybe_unused, + struct hist_entry *left, struct hist_entry *right) +{ + struct c2c_hist_entry *c2c_left =3D container_of(left, struct c2c_hist_en= try, he); + struct c2c_hist_entry *c2c_right =3D container_of(right, struct c2c_hist_= entry, he); + u64 left_store, right_store; + + /* Match total_stores_entry(): L1 sums child stores, L2/L3 use their own.= */ + left_store =3D left->parent_he ? (u64)c2c_left->stats.store : + hist_entry__child_stores(left); + right_store =3D right->parent_he ? (u64)c2c_right->stats.store : + hist_entry__child_stores(right); + + return (left_store > right_store) - (left_store < right_store); +} + int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) { ui__warning("C2C function view is not implemented yet.\n"); --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70E303F2109; Fri, 10 Jul 2026 08:43:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672990; cv=none; b=SmLnkKavNpGwO+EYzNxDzKL7tWlTo9GkM88cQCj/G4sCvUw0QCLr8xtghaQZrG7M9rQQhSeocK8dN2y+M1kW/C73VxhWQGlEmvoCieBeyObBbpSZKFsQYtnsxDghjlyUthYJURJRXYkMcLhp8fucmu1iOpZfUiHAwJEfgV7Fnjo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672990; c=relaxed/simple; bh=3i7AS7MawqR/TAzu5pR03szQdZCj3QPyajajiaItl2w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tY1gU8GtubsUWgMnpWjBI6Pa3WMjIW1izitOIKtFIrOnDjt2d7FvXEQfze1pPBTKFi0T975gVZ4VgvjWDmkf8wh5+2iQj9wQdOjgzcQumMbg0chCcQ08by0kw+lO08GDRMerjnqzYK1oZS6lQCjQwrnS0Dr4j92KvDFof1j+3Zs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=C1RkmFEw; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="C1RkmFEw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672987; x=1815208987; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3i7AS7MawqR/TAzu5pR03szQdZCj3QPyajajiaItl2w=; b=C1RkmFEwz4rRMHG6BlZ5xMQrh1QA+KjQbUD3Ki3JnXtY4UqWvzSbuQ2/ oNPMwp3mlQ7YBmW/t8RG/YGzg/hetyZ11UVm0v55mt7JhcYufbW5uUtJP G7uF18K0Ted+mT076W17GAIb76x00+Z6zJkTwFlVDa2PDGWWu93jxAcyO fr3I7wxY8i/PAzH1eFOh1SfBJDvNTa2DVcJBqvuE6RQeEBy6PilDfkiSg SuYqYzNfnPv9qxYanyqpogreJhhegpWaw+NgLADNqbwYF7QtV884VnbtT jfFN92/NMan52npLbfKF1OaMW7jpOmNIyxyZJailR+jB/ig2PK5E2QIYF A==; X-CSE-ConnectionGUID: ai07DeWVR328m1vM+siy9g== X-CSE-MsgGUID: gJpq4TQLTO6x5/BmWR933g== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390841" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390841" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:06 -0700 X-CSE-ConnectionGUID: ltcnAZWhTGGVcKeLBeJmWw== X-CSE-MsgGUID: mJ+hFgtLTz2grPfX18lpZg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435374" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:02 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 07/14] perf c2c: add dimension definitions and format creation Date: Fri, 10 Jul 2026 16:42:40 +0800 Message-ID: <20260710084247.3576706-8-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the function view dimension definitions that bind column names to their rendering and comparison functions: - dim_cycles_percent: estimated load-cycles percentage (L1 only) - dim_total_stores: store count per function - dim_cacheline_symbol: cacheline address (L3 only) - dim_iaddr_symbol: instruction code address - dim_symbol_view: symbol name with fold indicators Remove __maybe_unused from the entry and comparison functions now that they are referenced by the dimension structs above. Also add get_function_dimension() and get_function_format() to look up dimensions by name and create perf_hpp_fmt wrappers. These two helpers are intentionally left __maybe_unused here; they are wired into the function view initialization in the following patch. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 143 +++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 12 deletions(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index d5763af307b6..7c2bb8f9e113 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -66,7 +66,7 @@ static __maybe_unused inline u64 hist_entry__iaddr(struct= hist_entry *he) return he->ip; } =20 -static __maybe_unused int symbol_width(struct hists *hists, struct sort_en= try *se) +static int symbol_width(struct hists *hists, struct sort_entry *se) { int width =3D hists__col_len(hists, se->se_width_idx); =20 @@ -81,7 +81,7 @@ 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, +static int c2c_width(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp __maybe_unused, struct hists *hists) { @@ -98,7 +98,7 @@ static __maybe_unused int c2c_width(struct perf_hpp_fmt *= fmt, dim->width; } =20 -static __maybe_unused int c2c_header(struct perf_hpp_fmt *fmt, struct perf= _hpp *hpp, +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; @@ -179,7 +179,7 @@ static __maybe_unused u64 hist_entry__child_stores(stru= ct hist_entry *he) return c2c_he->child_stores; } =20 -static __maybe_unused int +static int total_stores_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { @@ -196,7 +196,7 @@ total_stores_entry(struct perf_hpp_fmt *fmt, struct per= f_hpp *hpp, /* * cacheline_symbol_entry - Render cacheline address for function view */ -static __maybe_unused int +static int cacheline_symbol_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { @@ -215,7 +215,7 @@ cacheline_symbol_entry(struct perf_hpp_fmt *fmt, struct= perf_hpp *hpp, } =20 /* Render the code (instruction) address for level-1 and level-2 entries. = */ -static __maybe_unused int +static int iaddr_symbol_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { @@ -246,7 +246,7 @@ iaddr_symbol_entry(struct perf_hpp_fmt *fmt, struct per= f_hpp *hpp, /* * symbol_view_entry - Render symbol name for function view with expansion= indicators */ -static __maybe_unused int +static int symbol_view_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { @@ -279,7 +279,7 @@ symbol_view_entry(struct perf_hpp_fmt *fmt, struct perf= _hpp *hpp, /* * cycles_percent_entry - Render cycles percentage column */ -static __maybe_unused int +static int cycles_percent_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { @@ -314,7 +314,7 @@ cycles_percent_entry(struct perf_hpp_fmt *fmt, struct p= erf_hpp *hpp, /* * cycles_percent_cmp - Comparison function for cycles percentage sorting */ -static __maybe_unused int64_t +static int64_t cycles_percent_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { @@ -335,7 +335,7 @@ cycles_percent_cmp(struct perf_hpp_fmt *fmt __maybe_unu= sed, /* * iaddr_symbol_cmp - Comparison function for instruction address sorting */ -static __maybe_unused int64_t +static int64_t iaddr_symbol_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { @@ -358,7 +358,7 @@ iaddr_symbol_cmp(struct perf_hpp_fmt *fmt __maybe_unuse= d, return (left_iaddr < right_iaddr) - (left_iaddr > right_iaddr); } =20 -static __maybe_unused int64_t +static int64_t empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left __maybe_unused, struct hist_entry *right __maybe_unused) @@ -369,7 +369,7 @@ empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused, /* * total_stores_cmp - Comparison function for total stores sorting */ -static __maybe_unused int64_t +static int64_t total_stores_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { @@ -386,6 +386,125 @@ total_stores_cmp(struct perf_hpp_fmt *fmt __maybe_unu= sed, return (left_store > right_store) - (left_store < right_store); } =20 +/* + * Function view dimensions + */ +static struct c2c_dimension dim_cycles_percent =3D { + .header =3D HEADER_BOTH("Cycles", "%"), + .name =3D "cycles_percent", + .cmp =3D cycles_percent_cmp, + .entry =3D cycles_percent_entry, + .width =3D 9, +}; + +static struct c2c_dimension dim_total_stores =3D { + .header =3D HEADER_BOTH("Store", "count"), + .name =3D "total_stores", + .cmp =3D total_stores_cmp, + .entry =3D total_stores_entry, + .width =3D 7, +}; + +static struct c2c_dimension dim_cacheline_symbol =3D { + .header =3D HEADER_LOW("Cacheline"), + .name =3D "cacheline_symbol", + .cmp =3D empty_cmp, + .entry =3D cacheline_symbol_entry, + .width =3D 18, +}; + +static struct c2c_dimension dim_iaddr_symbol =3D { + .header =3D HEADER_LOW("Code address"), + .name =3D "iaddr_symbol", + .cmp =3D iaddr_symbol_cmp, + .entry =3D iaddr_symbol_entry, + .width =3D 20, +}; + +static struct c2c_dimension dim_symbol_view =3D { + .header =3D HEADER_LOW("Symbol"), + .name =3D "symbol_view", + .se =3D &sort_sym, + .entry =3D symbol_view_entry, + .width =3D SYMBOL_WIDTH, +}; + +static struct c2c_dimension *function_view_dimensions[] =3D { + &dim_iaddr_symbol, + &dim_cycles_percent, + &dim_total_stores, + &dim_cacheline_symbol, + &dim_symbol_view, + NULL, +}; + +static __maybe_unused struct c2c_dimension *get_function_dimension(const c= har *name) +{ + unsigned int i; + + for (i =3D 0; function_view_dimensions[i]; i++) { + struct c2c_dimension *dim =3D 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 =3D container_of(fmt, struct c2c_fmt, fmt); + struct c2c_dimension *dim =3D 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 =3D container_of(fmt, struct c2c_fmt, fmt); + struct c2c_dimension *dim =3D c2c_fmt->dim; + int64_t (*collapse_fn)(struct hist_entry *a, struct hist_entry *b); + + collapse_fn =3D dim->se->se_collapse ?: dim->se->se_cmp; + return collapse_fn(a, b); +} + +static __maybe_unused struct c2c_fmt *get_function_format(const char *name) +{ + struct c2c_dimension *dim =3D get_function_dimension(name); + struct c2c_fmt *c2c_fmt; + struct perf_hpp_fmt *fmt; + + if (!dim) + return NULL; + + c2c_fmt =3D zalloc(sizeof(*c2c_fmt)); + if (!c2c_fmt) + return NULL; + + fmt =3D &c2c_fmt->fmt; + + c2c_fmt->dim =3D dim; + INIT_LIST_HEAD(&fmt->list); + INIT_LIST_HEAD(&fmt->sort_list); + + fmt->cmp =3D dim->se ? c2c_se_cmp : dim->cmp; + fmt->sort =3D dim->se ? c2c_se_cmp : dim->cmp; + fmt->color =3D dim->color; + fmt->entry =3D dim->entry; + fmt->header =3D c2c_header; + fmt->width =3D c2c_width; + fmt->collapse =3D dim->se ? c2c_se_collapse : dim->cmp; + fmt->equal =3D fmt_equal; + fmt->free =3D fmt_free; + + return c2c_fmt; +} + int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) { ui__warning("C2C function view is not implemented yet.\n"); --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A8143F1ABA; Fri, 10 Jul 2026 08:43:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672997; cv=none; b=oORcq04FW6FZkXT2ZmJdaGPy1NIKPAqpBmhCBQ2FVIpIgMKq7QSAQHS/f7KSPaIzPO7H3ZDNEzHM+QOGoSh2l0PnlC7gDC0fufeydOGLDLfJx2mIzy7/f2svNmEFmrywSukXQz3IYl5wwnuYR/jdA8lXVeBahQREuuhhE8rYZhs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672997; c=relaxed/simple; bh=q6eCvEJCMXKcfuhKVhW/RBzw1J5hSGk4xktrfiIWVcw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=szumMuTYHzXijOtMSZ3sPiBqgmHrlDrkWvIdafXQa2GbL6rjIHDdxF+5FLjZVmFky9OMvl8y4stNcaN68JNHSlrcNDN48ndGfjyRERZ79hbqjGfHKtf7bUJcUA6K6dM+SilybF71eOPVA79M61MsLciKUBZWhzq8evFP1V90cIY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=fWBbbdJt; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="fWBbbdJt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672994; x=1815208994; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=q6eCvEJCMXKcfuhKVhW/RBzw1J5hSGk4xktrfiIWVcw=; b=fWBbbdJt5AD03GnjJmU4foYzKX8gnpJjYRco03C/rVJsTeuJUN83o4aH T4h38H/hUTH1XwS+dj12DMc/QmIypih6wzV8RwuKGYbAiV4F9VRqEoB+s EsdVcTquKIibqvN83WnKTGJqFhVUrQBP5mqDQVhTh4kmuB2G3EAxWLW2j E3I+X9/pbiqz6zVa6Sdz6i3pa1dUwaP3ElhN1j8JbinTGdnyt77my+wfe k16SiCtswBImiXv9ccmUKxY8wWaQZ8FKsaD2RXbsyilzX2urhifnbYjxO vMkqOMy/gf55rN5zSqu+noTLh62sthdEzj1r4rWlKq8teT61m5tf1cxpM Q==; X-CSE-ConnectionGUID: ly5LWzP/R3CqOb2NSQDteg== X-CSE-MsgGUID: CaU3a+IhTbuXS4/DtzVwFQ== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390851" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390851" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:11 -0700 X-CSE-ConnectionGUID: c+Tgk3tXSaysaY49NMxeAw== X-CSE-MsgGUID: f0aZKz4aQV6TrJNuLHX0ag== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435382" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:06 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 08/14] perf c2c: add HPP list parsing for function view histograms Date: Fri, 10 Jul 2026 16:42:41 +0800 Message-ID: <20260710084247.3576706-9-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the histogram initialization and column parsing infrastructure: - c2c_function_hists__init_output(): register output columns - c2c_function_hists__init_sort(): register sort columns - function_hpp_list__parse(): parse comma-separated column strings - c2c_function_hists__init(): initialize function histograms with sort - c2c_function_hists__reinit(): reinitialize with new output/sort These functions bridge the function view's custom dimensions with the perf HPP list infrastructure, enabling dynamic column configuration during hierarchy construction. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 170 +++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 7c2bb8f9e113..0f21cf39f0ce 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -438,7 +438,7 @@ static struct c2c_dimension *function_view_dimensions[]= =3D { NULL, }; =20 -static __maybe_unused struct c2c_dimension *get_function_dimension(const c= har *name) +static struct c2c_dimension *get_function_dimension(const char *name) { unsigned int i; =20 @@ -473,18 +473,29 @@ static int64_t c2c_se_collapse(struct perf_hpp_fmt *f= mt, return collapse_fn(a, b); } =20 -static __maybe_unused struct c2c_fmt *get_function_format(const char *name) +/* + * Build the c2c_fmt for @name. Returns: + * 0 and *fmtp set on success; + * -ENOENT and *fmtp =3D NULL if @name is not a function-view dimensi= on + * (caller should fall back to the generic f= ield); + * -ENOMEM if allocation failed (distinct from -ENOE= NT 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 =3D get_function_dimension(name); struct c2c_fmt *c2c_fmt; struct perf_hpp_fmt *fmt; =20 + *fmtp =3D NULL; + if (!dim) - return NULL; + return -ENOENT; =20 c2c_fmt =3D zalloc(sizeof(*c2c_fmt)); if (!c2c_fmt) - return NULL; + return -ENOMEM; =20 fmt =3D &c2c_fmt->fmt; =20 @@ -502,7 +513,156 @@ static __maybe_unused struct c2c_fmt *get_function_fo= rmat(const char *name) fmt->equal =3D fmt_equal; fmt->free =3D fmt_free; =20 - return c2c_fmt; + *fmtp =3D 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 level =3D 0; + int ret; + + ret =3D get_function_format(name, &c2c_fmt); + if (ret =3D=3D -ENOMEM) + return ret; + if (ret =3D=3D -ENOENT) { + reset_dimensions(); + return output_field_add(hpp_list, name, &level); + } + + /* + * 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 =3D=3D &sort_sym) + hpp_list->sym =3D 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) +{ + struct c2c_fmt *c2c_fmt; + int ret; + + ret =3D get_function_format(name, &c2c_fmt); + if (ret =3D=3D -ENOMEM) + return ret; + if (ret =3D=3D -ENOENT) { + reset_dimensions(); + return sort_dimension__add(hpp_list, name, /*evlist=3D*/NULL, env, /*lev= el=3D*/0); + } + + /* Mark symbol-backed sort keys so hists__has(hists, sym) is correct. */ + if (c2c_fmt->dim->se =3D=3D &sort_sym) + hpp_list->sym =3D 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, c= har *list, + struct perf_env *env, hpp_list_add_fn add) +{ + char *tok, *tmp; + int ret; + + if (!list) + return 0; + + for (tok =3D strtok_r(list, ", ", &tmp); tok; tok =3D strtok_r(NULL, ", "= , &tmp)) { + ret =3D add(hpp_list, tok, env); + if (ret) { + if (ret =3D=3D -EINVAL || ret =3D=3D -ESRCH) + pr_err("Invalid c2c function-view field: %s", tok); + return ret; + } + } + return 0; +} + +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 =3D output_str ? strdup(output_str) : NULL; + char *sort =3D sort_str ? strdup(sort_str) : NULL; + int ret =3D 0; + + if ((output_str && !output) || (sort_str && !sort)) { + ret =3D -ENOMEM; + goto out; + } + + ret =3D function_hpp_list__add_tokens(hpp_list, output, env, + c2c_function_hists__init_output); + if (ret) + goto out; + + ret =3D function_hpp_list__add_tokens(hpp_list, sort, env, + c2c_function_hists__init_sort); + if (ret) + goto out; + + perf_hpp__setup_output_field(hpp_list); +out: + free(output); + free(sort); + return ret; +} + +static __maybe_unused int +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 =3D nr_header_lines; + + return function_hpp_list__parse(&hists->list, /*output=3D*/NULL, sort, en= v); +} + +static __maybe_unused int +c2c_function_hists__reinit(struct c2c_hists *c2c_hists, + const char *output, + const char *sort, + struct perf_env *env) +{ + int nr_header_lines =3D c2c_hists->list.nr_header_lines; + + perf_hpp__reset_output_field(&c2c_hists->list); + INIT_LIST_HEAD(&c2c_hists->list.sorts); + + /* Clear stale state flags so a different output/sort set starts fresh. */ + c2c_hists->list.need_collapse =3D 0; + c2c_hists->list.parent =3D 0; + c2c_hists->list.sym =3D 0; + c2c_hists->list.dso =3D 0; + c2c_hists->list.socket =3D 0; + c2c_hists->list.thread =3D 0; + c2c_hists->list.comm =3D 0; + c2c_hists->list.comm_nodigit =3D 0; + c2c_hists->list.nr_header_lines =3D nr_header_lines; + + return function_hpp_list__parse(&c2c_hists->list, output, sort, env); } =20 int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) --=20 2.52.0 From nobody Sun Jul 26 01:47:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C6F313F1AC8; Fri, 10 Jul 2026 08:43:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672998; cv=none; b=AOxzqFIkd/wH7XEA0HSpop283w3ykOR5jbWXDnXZlU6tZsialiNGlPIYV2AuTTydiBeZNj81M8Th/PPNlbAe3yJ+ak6fTDoWCaRgovxFfQkuDoGiHHo1iS/MUEZTWHiwR0/HLt/nb6BEYRjBWtPtQxQiSxspZ6S1HDwF+N9pPKU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783672998; c=relaxed/simple; bh=/c03sACpXNnDzjGc0BRBHbnCoiMBhDvHWXmtggqyd18=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Mltdi4qio/WFVsInfvfRyHcPKLDIJyxzApdFIqoPRjJW2M4yxK3O1jB8dMQOsrmqPbCn0rvVYBi6isvSG7eUAEiARCbxV1gWWARJg/sX5pheOrJ2hkb3jEch8BRCAjFPsiVPhKdqV6b7nev2MnanQ8z7ugeJ+rfdYo7ufUQuLBY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=FEbGiYl0; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="FEbGiYl0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783672996; x=1815208996; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=/c03sACpXNnDzjGc0BRBHbnCoiMBhDvHWXmtggqyd18=; b=FEbGiYl0gjEeagx0/KsOvnLo+UkC+TuQKlTcDg0mviY4u8wecDOdLSnk zQHrM7YLpkEQlLduMpIHu88UfxB+3gALJn7LKNoauy+QK4YZRxH/+Yfb+ fBAaP++D61LQ8BZxiPIkSoQ8h9IjVJ9LhXgzMlLxvEZm5h5oQGDSzJR3n aP9xvcrP1Yb1T2LLsMeqFz91slYG4LwZQ/JnMCIGe2uF0RmzmxDXOUos5 3x6J1iIqnTQwS4Epc6Gp3OeKJnC4iEHZ2MJ21BuMS1+xla+JokFcFHpuz rVvUMvIZZxASjgxfCIyGNYbEkMxV7kjeX7MtE/AGmMSh4tqui8u4cNAYI g==; X-CSE-ConnectionGUID: SJD7AV9MRYqud5MYwHZEYw== X-CSE-MsgGUID: cuuzhcgsTqquIauhJoEkgA== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390859" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390859" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:16 -0700 X-CSE-ConnectionGUID: z/F0LUASSdy6k9kj8F2Wdw== X-CSE-MsgGUID: 3IXcd4ehRJeZBA4hr8xrgA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435403" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:11 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 09/14] perf c2c: add stats merging and memory management helpers Date: Fri, 10 Jul 2026 16:42:42 +0800 Message-ID: <20260710084247.3576706-10-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add statistics aggregation and memory management functions for function view histogram entries: Stats merging: - c2c_stats_merge(): combine two stats structs (Welford online merge) - c2c_add_cstats(): merge all compute_stats sub-fields - hist_entry__add_c2c_stats(): update hist_entry stat counters Memory management: - c2c_function_he_free(): free entry and recursively free children - c2c_he__free_hierarchy(): recursive cleanup of hroot_out tree Entry allocation reuses c2c_he_zalloc(), which was made shared via c2c.h in an earlier patch. These are used during hierarchy construction to allocate entries and aggregate C2C statistics across cacheline-function pairs. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 158 ++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 0f21cf39f0ce..6afcb1e156c6 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -665,6 +665,164 @@ c2c_function_hists__reinit(struct c2c_hists *c2c_hist= s, return function_hpp_list__parse(&c2c_hists->list, output, sort, env); } =20 +/* Welford online merge of two "stats" (from util/stat.h) accumulators. */ +static void c2c_stats_merge(struct stats *dest, const struct stats *src) +{ + double delta; + + if (src->n =3D=3D 0) + return; + + if (dest->n =3D=3D 0) { + *dest =3D *src; + return; + } + + delta =3D src->mean - dest->mean; + dest->M2 +=3D src->M2 + delta * delta * dest->n * src->n / (dest->n + src= ->n); + dest->mean =3D (dest->mean * dest->n + src->mean * src->n) / (dest->n + s= rc->n); + dest->n +=3D src->n; + + /* Update min/max */ + if (src->max > dest->max) + dest->max =3D src->max; + if (src->min < dest->min) + dest->min =3D src->min; +} + +/* Merge compute_stats during function aggregation. */ +static __maybe_unused void c2c_add_cstats(struct compute_stats *dest, + const struct compute_stats *src) +{ + c2c_stats_merge(&dest->rmt_hitm, &src->rmt_hitm); + c2c_stats_merge(&dest->lcl_hitm, &src->lcl_hitm); + c2c_stats_merge(&dest->rmt_peer, &src->rmt_peer); + c2c_stats_merge(&dest->lcl_peer, &src->lcl_peer); + c2c_stats_merge(&dest->load, &src->load); +} + +static __maybe_unused bool hist_entry__add_c2c_stats(struct hist_entry *he, + const struct c2c_stats *stats) +{ + u64 nr_events =3D c2c_hitm_count(stats) + stats->rmt_peer + stats->lcl_pe= er; + u64 weight1 =3D c2c_hitm_count(stats); + + he->stat.nr_events +=3D nr_events; + he->stat.period +=3D nr_events; + he->stat.weight1 +=3D weight1; + + if (!symbol_conf.cumulate_callchain) + return true; + + if (!he->stat_acc) { + he->stat_acc =3D calloc(1, sizeof(struct he_stat)); + if (!he->stat_acc) + return false; + } + + he->stat_acc->nr_events +=3D nr_events; + he->stat_acc->period +=3D nr_events; + he->stat_acc->weight1 +=3D weight1; + + return true; +} + +static void c2c_he__free_hierarchy(struct hist_entry *he); + +/* + * Free a function-view histogram entry (hist_entry_ops::free). + */ +static void c2c_function_he_free(void *ptr) +{ + struct hist_entry *he =3D ptr; + struct c2c_hist_entry *c2c_he; + + c2c_he =3D container_of(he, struct c2c_hist_entry, he); + + if (c2c_he->hists) { + perf_hpp__reset_output_field(&c2c_he->hists->list); + hists__delete_all_entries(&c2c_he->hists->hists); + zfree(&c2c_he->hists); + } + + c2c_he__free_hierarchy(he); + + zfree(&c2c_he->nodeset); + zfree(&c2c_he->cpuset); + zfree(&c2c_he->nodestr); + zfree(&c2c_he->node_stats); + + free(c2c_he); +} + +/* + * Free all child entries under @he, recursively (hroot_out sub-tree). + * + * Children are built by c2c_child_entry__alloc(), which BORROWS thread and + * ms (plain copy, no thread__get()/map__get()) and OWNS only mem_info (a + * clone), stat_acc and the c2c-specific fields (hists, cpuset, nodeset, + * nodestr, node_stats). We therefore must NOT call hist_entry__delete() + * here: it would thread__zput()/map_symbol__exit() the borrowed refs and + * underflow their refcounts. Free exactly the owned resources instead. + */ +static void c2c_he__free_hierarchy(struct hist_entry *he) +{ + struct rb_node *nd; + struct hist_entry *child_he; + struct c2c_hist_entry *child_c2c; + + /* + * Leaf entries alias hroot_out with sorted_chain (callchains) in a + * union, so they have no child hierarchy to free here. + */ + if (he->leaf) + return; + + if (RB_EMPTY_ROOT(&he->hroot_out.rb_root)) + return; + + nd =3D rb_first_cached(&he->hroot_out); + while (nd) { + struct rb_node *next =3D rb_next(nd); + + child_he =3D rb_entry(nd, struct hist_entry, rb_node); + child_c2c =3D container_of(child_he, struct c2c_hist_entry, he); + + if (child_he->stat_acc) + zfree(&child_he->stat_acc); + + if (child_he->mem_info) + mem_info__put(child_he->mem_info); + + if (child_c2c->hists) { + perf_hpp__reset_output_field(&child_c2c->hists->list); + hists__delete_all_entries(&child_c2c->hists->hists); + zfree(&child_c2c->hists); + } + + zfree(&child_c2c->cpuset); + zfree(&child_c2c->nodeset); + zfree(&child_c2c->nodestr); + zfree(&child_c2c->node_stats); + + c2c_he__free_hierarchy(child_he); + + rb_erase_cached(&child_he->rb_node, &he->hroot_out); + free(child_c2c); + + nd =3D next; + } + + /* All children erased; clear the tree (and its cached leftmost). */ + he->hroot_out =3D RB_ROOT_CACHED; +} + +/* Entry operations for function view */ +static struct hist_entry_ops c2c_function_entry_ops __maybe_unused =3D { + .new =3D c2c_he_zalloc, + .free =3D c2c_function_he_free, +}; + int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) { ui__warning("C2C function view is not implemented yet.\n"); --=20 2.52.0 From nobody Sun Jul 26 01:47:32 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0B7C43F44C1; Fri, 10 Jul 2026 08:43:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673002; cv=none; b=c3ZsDVuKzZoYvkXqMP9zvUrWoBsQbPMPh8YYOCxLhwYrGFRKzQ1KHWiZRiEE6WbEmOLBuSww+NydqaTtZjfyhscxGCdrxF0HJCuO4JbIdOCegR/Jy2gc9bm/I5IVBykbFD6/MFpvtBTHoT93SDi5YPatXOa5N0Ad+bo1I4+MJIM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673002; c=relaxed/simple; bh=A0n/6tlwU+bqztkNZJt6ZEMPvNNRJCRlrShHtyygwro=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JQTRzCZQNi0oWae1hAbCaWpo0XwLgbKOfM3u7bxLUpAlEQt0FyTz+LEChqm0e+s6ApFugo56Vi1SNmb5YqKQfcXLs4FM91Rnq2m8HFnE64YWstS9fS8q2glNcPs+5OetlI7iNyLnN0f31In6U1SWYdRHN6ygNEhXOt9rJ7iQGjA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Culil1s9; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Culil1s9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783673001; x=1815209001; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=A0n/6tlwU+bqztkNZJt6ZEMPvNNRJCRlrShHtyygwro=; b=Culil1s9FE0KAH1f7H+x+Z4DeDaCNxu31xSgoR6k+K9ge16wrCsNFMAf AKE52tIcgMP123VAi9lu2E7q/yVNaSAorGONjYp+desecl5lwbCDnSSgf tJSliPv0/Z2sJxlng+Em1cYLcPdKewHt3j61m7PmE1O2s1U2vuJQPQuhO gRdK6JoNPvZQc8nSC+awPmiu3AwOA7J6n0yVEc3Vmg5OyEBRNojKDn4os TPMuFgA9EiR7mVMhj8ITo8BmC7u83flMbRVueIdKtqf674tRUsb/uEBUJ dSI2qpzDDdy6KWGC/+ZAz+R/5RBU3SOsZaVkAy+7LNir4S8k+gZxV2sLx Q==; X-CSE-ConnectionGUID: 8/vkIhKsQT2Z2y6FhETXDg== X-CSE-MsgGUID: KIlwACA9T9yEbZaL33w2Yw== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390867" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390867" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:21 -0700 X-CSE-ConnectionGUID: IKTs24WoSrGbuiwIdgyNUQ== X-CSE-MsgGUID: g3yzDyJ4SJeUnNyjJOnIjw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435419" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:16 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 10/14] perf c2c: add hierarchy entry creation and lookup functions Date: Fri, 10 Jul 2026 16:42:43 +0800 Message-ID: <20260710084247.3576706-11-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add functions for creating and finding entries at each level of the 3-level function view hierarchy: - c2c_child_entry__alloc(): allocate a child hist_entry with all fields initialized from a source entry - c2c_child_entry__insert(): insert a child into the parent's hroot_out tree - c2c_function_hists__level1_entry(): find/create primary function entry using hists__add_entry_ops() for automatic deduplication - c2c_function_hists__level2_entry(): find/create sharing function entry as child of level 1, keyed by (iaddr, symbol) - c2c_function_hists__level3_entry(): find/create cacheline entry as child of level 2, keyed by cacheline address Also add c2c_function_entry_ops binding the custom allocator/free functions for function view histogram entries. These helpers are introduced with __maybe_unused; the annotation is removed in the following patch once the hierarchy builder calls them. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 249 +++++++++++++++++++++++++- 1 file changed, 248 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 6afcb1e156c6..47d6fdf66b47 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -818,11 +818,258 @@ static void c2c_he__free_hierarchy(struct hist_entry= *he) } =20 /* Entry operations for function view */ -static struct hist_entry_ops c2c_function_entry_ops __maybe_unused =3D { +static struct hist_entry_ops c2c_function_entry_ops =3D { .new =3D c2c_he_zalloc, .free =3D c2c_function_he_free, }; =20 +static struct c2c_hist_entry * +c2c_child_entry__alloc(struct hist_entry *parent_he, struct hist_entry *sr= c_he, + int depth, u64 ip) +{ + struct c2c_hist_entry *child_c2c; + struct hist_entry *child_he; + size_t callchain_size; + + callchain_size =3D symbol_conf.use_callchain ? sizeof(struct callchain_ro= ot) : 0; + child_he =3D c2c_he_zalloc(callchain_size); + if (!child_he) + return NULL; + + child_c2c =3D container_of(child_he, struct c2c_hist_entry, he); + child_he->callchain_size =3D callchain_size; + if (callchain_size) + callchain_init(child_he->callchain); + + memcpy(&child_he->ms, &src_he->ms, sizeof(struct map_symbol)); + + if (src_he->mem_info) { + child_he->mem_info =3D mem_info__clone(src_he->mem_info); + if (!child_he->mem_info) + goto out_free; + } + + child_he->thread =3D src_he->thread; + child_he->cpumode =3D src_he->cpumode; + child_he->cpu =3D src_he->cpu; + child_he->socket =3D src_he->socket; + child_he->level =3D src_he->level; + child_he->ip =3D ip; + + child_he->parent_he =3D parent_he; + child_he->depth =3D depth; + child_he->leaf =3D (depth >=3D 2); + child_he->hists =3D &c2c_ext.function_hists.hists; + child_he->filtered =3D false; + child_he->unfolded =3D false; + child_he->has_children =3D false; + child_he->has_no_entry =3D false; + child_he->nr_rows =3D 0; + child_he->row_offset =3D 0; + + memset(&child_he->stat, 0, sizeof(child_he->stat)); + child_he->hroot_in =3D RB_ROOT_CACHED; + child_he->hroot_out =3D RB_ROOT_CACHED; + INIT_LIST_HEAD(&child_he->pairs.node); + child_he->hpp_list =3D &c2c_ext.function_hists.list; + if (symbol_conf.cumulate_callchain) { + child_he->stat_acc =3D 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 *c= hild_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, leftmos= t); + + parent_he->has_children =3D true; + parent_he->leaf =3D false; +} + +static __maybe_unused struct hist_entry * +c2c_function_hists__level1_entry(struct symbol *sym, u64 iaddr, + struct hist_entry *detail_he, + struct thread *synthetic_thread) +{ + struct addr_location al; + struct perf_sample sample =3D {}; + struct mem_info *mi; + struct hist_entry *he; + + mi =3D mem_info__new(); + if (mi) { + mem_info__iaddr(mi)->addr =3D iaddr; + /* mem_info__put() will map_symbol__exit() these, so take refs. */ + mem_info__iaddr(mi)->ms.thread =3D thread__get(detail_he->ms.thread); + mem_info__iaddr(mi)->ms.map =3D map__get(detail_he->ms.map); + mem_info__iaddr(mi)->ms.sym =3D sym; + mem_info__daddr(mi)->addr =3D 0; + } + + addr_location__init(&al); + al.thread =3D thread__get(synthetic_thread); + al.map =3D map__get(detail_he->ms.map); + al.sym =3D sym; + al.addr =3D iaddr; + al.level =3D detail_he->level; + al.cpumode =3D detail_he->cpumode; + al.cpu =3D 0; + al.socket =3D 0; + al.filtered =3D 0; + al.latency =3D 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 =3D 1; + sample.weight =3D 1; + sample.ip =3D iaddr; + sample.pid =3D thread__pid(synthetic_thread); + sample.tid =3D thread__tid(synthetic_thread); + sample.cpu =3D 0; + + /* Add entry - histogram handles dedup */ + he =3D 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 =3D &c2c_ext.function_hists.list; + + return he; +} + +static __maybe_unused struct c2c_hist_entry * +c2c_function_hists__level2_entry(struct c2c_hist_entry *level1_c2c, + struct symbol *sym, u64 iaddr, + struct hist_entry *detail_he) +{ + struct hist_entry *level1_he =3D &level1_c2c->he; + struct rb_node **p =3D &level1_he->hroot_out.rb_root.rb_node; + struct rb_node *parent =3D NULL; + struct c2c_hist_entry *level2_c2c; + bool leftmost =3D true; + + /* + * Order by (iaddr, symbol name). Symbols are looked up by name to + * coalesce identically-named symbols from different DSO/JIT copies, + * which matches the dedup policy used when building the hierarchy. + */ + while (*p) { + struct hist_entry *iter =3D rb_entry(*p, struct hist_entry, rb_node); + u64 iter_iaddr =3D hist_entry__iaddr(iter); + int cmp; + + parent =3D *p; + if (iaddr < iter_iaddr) { + p =3D &parent->rb_left; + continue; + } + if (iaddr > iter_iaddr) { + p =3D &parent->rb_right; + leftmost =3D false; + continue; + } + + if (!sym || !iter->ms.sym) + /* Order NULL-symbol entries deterministically (NULL last). */ + cmp =3D (iter->ms.sym ? 1 : 0) - (sym ? 1 : 0); + else + cmp =3D arch__compare_symbol_names(sym->name, iter->ms.sym->name); + + if (cmp < 0) { + p =3D &parent->rb_left; + } else if (cmp > 0) { + p =3D &parent->rb_right; + leftmost =3D false; + } else { + return container_of(iter, struct c2c_hist_entry, he); + } + } + + level2_c2c =3D c2c_child_entry__alloc(level1_he, detail_he, 1, iaddr); + if (!level2_c2c) + return NULL; + + /* Key this level by the looked-up symbol, not detail_he's. */ + level2_c2c->he.ms.sym =3D sym; + + /* Override iaddr (and symbol) in cloned mem_info for level 2 */ + if (level2_c2c->he.mem_info) { + mem_info__iaddr(level2_c2c->he.mem_info)->addr =3D iaddr; + mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym =3D sym; + } + + c2c_child_entry__insert(level1_he, &level2_c2c->he, p, parent, leftmost); + + return level2_c2c; +} + +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 =3D &level2_c2c->he; + struct rb_node **p =3D &level2_he->hroot_out.rb_root.rb_node; + struct rb_node *parent =3D NULL; + struct c2c_hist_entry *level3_c2c; + bool leftmost =3D true; + + while (*p) { + struct hist_entry *iter =3D rb_entry(*p, struct hist_entry, rb_node); + u64 iter_addr =3D 0; + + if (iter->mem_info) { + u64 daddr =3D mem_info__daddr(iter->mem_info)->addr; + + iter_addr =3D cl_address(daddr, chk_double_cl); + } + + parent =3D *p; + if (cl_addr < iter_addr) { + p =3D &parent->rb_left; + } else if (cl_addr > iter_addr) { + p =3D &parent->rb_right; + leftmost =3D false; + } else { + return container_of(iter, struct c2c_hist_entry, he); + } + } + + level3_c2c =3D 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"); --=20 2.52.0 From nobody Sun Jul 26 01:47:32 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C5D03F1AD3; Fri, 10 Jul 2026 08:43:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673008; cv=none; b=LVT8zK6eJrBxV0Y7KrV1HPVm9CMPGYegPzun4xqdi/7N9z4+mNQ9yH8/xcMJJwPXM3ootd+KlIbrOOg81DXDoCWWOKBUxhiArFiRZbEel31uF41ACDQTskP+oGrtjIyJAPxNJALlLneKJlvO3KRLr6SPOz4MH/a0F9RTmigv8LM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673008; c=relaxed/simple; bh=bjAW978TZziWCNCdY4GRXx5+wARYRW24uxSfANqv9wg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QIA3zMvbWhPmTX8eMk49eM93YURgch0H5kplFkv/iA9tusWCG/gZR61kOnItFN+q2UuHrqSiNI59qfU6GrxZFK7coQXBjV3wl92fiHUlFbOkxIABsTfP381xEridPY/mENnFyQWLV4AAlfr4lGgWq3aqfSwSnFrOxsqEg7jxHK4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=QY2iLuw3; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="QY2iLuw3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783673007; x=1815209007; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bjAW978TZziWCNCdY4GRXx5+wARYRW24uxSfANqv9wg=; b=QY2iLuw3HXjWSNpLUkZ0TIeknkeYbh/xLyoPyKomxF5tFoNyMGrlnzah LYbT6uUJud1+7uQOVwd/j2GwN7CHOT0NP3Jt2vawCkjUmZIyI3Q2klH/R OvRVLwRlRQzEfC1IvNfv0VDNGNaZyEmaKVFELpDGeIbANjgINBUlQY4sQ n22Pa5Jej7rctAYCA7YzF8Amm/XRM8cNk1beHM8kjfb3n5rwNibw2k3me sDEMW7tzyqlJgDYzrTK+k6clVOUVQiCHksm0lCOLxIqPFYGW05jK3Akep 37ZqbLYaY+uvdSOB/87nXK681VzGp7hfb9Jv41WHMPxBPO2DsIoltLW5R A==; X-CSE-ConnectionGUID: cUW8XOWaQjSEv+kcojf56w== X-CSE-MsgGUID: JkXpXXshTRenaRM+9aZmxA== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390877" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390877" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:26 -0700 X-CSE-ConnectionGUID: ACfqkGSuRfW+kV1xDYn3lQ== X-CSE-MsgGUID: 9Sz+b3hsTqy73aF1JM9FBg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435445" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:21 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 11/14] perf c2c: add function view hierarchy builder Date: Fri, 10 Jul 2026 16:42:44 +0800 Message-ID: <20260710084247.3576706-12-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the core algorithm that constructs the 3-level function view: - c2c_he__resort_by_stores(): re-sort children by store count - build_function_view_hierarchy(): single-pass hierarchy construction The builder traverses all cacheline entries and for each pair of functions (A, B) sharing a cacheline: 1. Creates/finds Level 1 entry for function A 2. Creates/finds Level 2 entry for function B under A 3. Creates/finds Level 3 cacheline entry under B 4. Aggregates C2C stats at all levels After construction, it configures output columns, sorts Level 1 by cycles percentage, and re-sorts Level 2/3 by store count. A per-cacheline set (function_seen[], heap-allocated and grown on demand) tracks already-processed functions to prevent duplicate parent processing when the same function appears multiple times within a single cacheline. Remove __maybe_unused from all helper functions now called by the hierarchy builder. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 375 ++++++++++++++++++++++++-- 1 file changed, 357 insertions(+), 18 deletions(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 47d6fdf66b47..80e032d5e31c 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -14,6 +14,7 @@ #include #include #include +#include /* reallocarray */ #include #include #include @@ -49,17 +50,17 @@ struct c2c_function_browser { struct hist_browser hb; }; =20 -static __maybe_unused inline u64 c2c_hitm_count(const struct c2c_stats *st= ats) +static inline u64 c2c_hitm_count(const struct c2c_stats *stats) { return stats->tot_hitm; } =20 -static __maybe_unused inline bool symbol_name_equal(struct symbol *a, stru= ct symbol *b) +static inline bool symbol_name_equal(struct symbol *a, struct symbol *b) { return a && b && arch__compare_symbol_names(a->name, b->name) =3D=3D 0; } =20 -static __maybe_unused inline u64 hist_entry__iaddr(struct hist_entry *he) +static inline u64 hist_entry__iaddr(struct hist_entry *he) { if (he->mem_info) return mem_info__iaddr(he->mem_info)->addr; @@ -137,22 +138,34 @@ static int c2c_header(struct perf_hpp_fmt *fmt, struc= t perf_hpp *hpp, * 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 *c2= c_he) +static u64 c2c_hist_entry__cycles(struct c2c_hist_entry *c2c_he) { - double cycles_rmt, cycles_lcl, cycles_load; - u64 other_load, total_hitm; + double cycles_rmt, cycles_lcl, cycles_rmt_peer, cycles_lcl_peer, cycles_l= oad; + u64 categorized, other_load; =20 + /* + * compute_stats() in builtin-c2c.c assigns each load sample to exactly + * one cstats bucket (rmt_hitm, lcl_hitm, rmt_peer, lcl_peer or load), + * while stats.load counts every load. Weight each category by its own + * average and treat only the uncategorized remainder as plain loads, so + * peer-snoop cycles are neither dropped nor charged the load average. + */ cycles_rmt =3D avg_stats(&c2c_he->cstats.rmt_hitm) * c2c_he->stats.rmt_hi= tm; cycles_lcl =3D avg_stats(&c2c_he->cstats.lcl_hitm) * c2c_he->stats.lcl_hi= tm; - total_hitm =3D c2c_he->stats.tot_hitm; - other_load =3D (c2c_he->stats.load >=3D total_hitm) ? c2c_he->stats.load = - total_hitm : 0; + cycles_rmt_peer =3D avg_stats(&c2c_he->cstats.rmt_peer) * c2c_he->stats.r= mt_peer; + cycles_lcl_peer =3D avg_stats(&c2c_he->cstats.lcl_peer) * c2c_he->stats.l= cl_peer; + + categorized =3D (u64)c2c_he->stats.tot_hitm + c2c_he->stats.tot_peer; + other_load =3D (c2c_he->stats.load >=3D categorized) ? + c2c_he->stats.load - categorized : 0; cycles_load =3D avg_stats(&c2c_he->cstats.load) * other_load; =20 - return (u64)(cycles_rmt + cycles_lcl + cycles_load); + return (u64)(cycles_rmt + cycles_lcl + cycles_rmt_peer + + cycles_lcl_peer + cycles_load); } =20 /* Sum c2c_hist_entry__cycles() across all level-1 entries. */ -static __maybe_unused u64 c2c_ext__total_cycles(void) +static u64 c2c_ext__total_cycles(void) { struct rb_node *nd; u64 total =3D 0; @@ -172,7 +185,7 @@ static __maybe_unused u64 c2c_ext__total_cycles(void) * Read from the cache populated by the hierarchy builder, so this is O(1) * and safe to call from the sort comparator. */ -static __maybe_unused u64 hist_entry__child_stores(struct hist_entry *he) +static u64 hist_entry__child_stores(struct hist_entry *he) { struct c2c_hist_entry *c2c_he =3D container_of(he, struct c2c_hist_entry,= he); =20 @@ -625,7 +638,7 @@ function_hpp_list__parse(struct perf_hpp_list *hpp_list, return ret; } =20 -static __maybe_unused int +static int c2c_function_hists__init(struct c2c_hists *hists, const char *sort, int nr_header_lines, @@ -640,7 +653,7 @@ c2c_function_hists__init(struct c2c_hists *hists, return function_hpp_list__parse(&hists->list, /*output=3D*/NULL, sort, en= v); } =20 -static __maybe_unused int +static int c2c_function_hists__reinit(struct c2c_hists *c2c_hists, const char *output, const char *sort, @@ -691,7 +704,7 @@ static void c2c_stats_merge(struct stats *dest, const s= truct stats *src) } =20 /* Merge compute_stats during function aggregation. */ -static __maybe_unused void c2c_add_cstats(struct compute_stats *dest, +static void c2c_add_cstats(struct compute_stats *dest, const struct compute_stats *src) { c2c_stats_merge(&dest->rmt_hitm, &src->rmt_hitm); @@ -701,7 +714,7 @@ static __maybe_unused void c2c_add_cstats(struct comput= e_stats *dest, c2c_stats_merge(&dest->load, &src->load); } =20 -static __maybe_unused bool hist_entry__add_c2c_stats(struct hist_entry *he, +static bool hist_entry__add_c2c_stats(struct hist_entry *he, const struct c2c_stats *stats) { u64 nr_events =3D c2c_hitm_count(stats) + stats->rmt_peer + stats->lcl_pe= er; @@ -901,7 +914,7 @@ c2c_child_entry__insert(struct hist_entry *parent_he, s= truct hist_entry *child_h parent_he->leaf =3D false; } =20 -static __maybe_unused struct hist_entry * +static struct hist_entry * c2c_function_hists__level1_entry(struct symbol *sym, u64 iaddr, struct hist_entry *detail_he, struct thread *synthetic_thread) @@ -963,7 +976,7 @@ c2c_function_hists__level1_entry(struct symbol *sym, u6= 4 iaddr, return he; } =20 -static __maybe_unused struct c2c_hist_entry * +static struct c2c_hist_entry * c2c_function_hists__level2_entry(struct c2c_hist_entry *level1_c2c, struct symbol *sym, u64 iaddr, struct hist_entry *detail_he) @@ -1029,7 +1042,7 @@ c2c_function_hists__level2_entry(struct c2c_hist_entr= y *level1_c2c, return level2_c2c; } =20 -static __maybe_unused struct c2c_hist_entry * +static 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) { @@ -1070,6 +1083,332 @@ c2c_function_hists__level3_entry(struct c2c_hist_en= try *level2_c2c, u64 cl_addr, return level3_c2c; } =20 +/* + * Re-sort child entries of @parent_he by total store count, descending. + */ +static void c2c_he__resort_by_stores(struct hist_entry *parent_he) +{ + struct rb_root_cached new_root =3D RB_ROOT_CACHED; + struct rb_node *nd; + + if (!parent_he->has_children) + return; + + /* Extract all nodes and re-insert sorted by total_stores */ + while ((nd =3D rb_first_cached(&parent_he->hroot_out))) { + struct hist_entry *he =3D rb_entry(nd, struct hist_entry, rb_node); + struct c2c_hist_entry *c2c_he =3D container_of(he, struct c2c_hist_entry= , he); + struct rb_node **p =3D &new_root.rb_root.rb_node; + struct rb_node *parent =3D NULL; + bool leftmost =3D true; + int cmp; + + /* Remove from current tree */ + rb_erase_cached(&he->rb_node, &parent_he->hroot_out); + + /* Insert sorted by store count, descending. */ + while (*p) { + struct hist_entry *iter =3D rb_entry(*p, struct hist_entry, rb_node); + struct c2c_hist_entry *c2c_iter =3D container_of(iter, + struct c2c_hist_entry, + he); + + parent =3D *p; + if (c2c_he->stats.store !=3D c2c_iter->stats.store) { + cmp =3D c2c_he->stats.store > c2c_iter->stats.store ? -1 : 1; + } else { + /* Stable tie-break: instruction address, then name. */ + u64 a =3D hist_entry__iaddr(he), b =3D hist_entry__iaddr(iter); + + if (a !=3D b) + cmp =3D a < b ? -1 : 1; + else if (he->ms.sym && iter->ms.sym) + cmp =3D arch__compare_symbol_names(he->ms.sym->name, + iter->ms.sym->name); + else + cmp =3D (iter->ms.sym ? 1 : 0) - (he->ms.sym ? 1 : 0); + } + + if (cmp < 0) { + p =3D &parent->rb_left; + } else { + p =3D &parent->rb_right; + leftmost =3D false; + } + } + + rb_link_node(&he->rb_node, parent, p); + rb_insert_color_cached(&he->rb_node, &new_root, leftmost); + } + + parent_he->hroot_out =3D new_root; +} + +/* Initial per-cacheline capacity for the seen[] set; grown on demand. */ +#define DEFAULT_SYMBOLS_PER_CL 64 + +struct function_seen { + struct symbol *sym; + u64 iaddr; +}; + +static bool function_seen__find(const struct function_seen *seen, int nr, + struct symbol *sym, u64 iaddr) +{ + int i; + + for (i =3D 0; i < nr; i++) { + if (seen[i].iaddr =3D=3D iaddr && + symbol_name_equal(seen[i].sym, sym)) + return true; + } + return false; +} + +/* Aggregate stats from the cacheline-side entry @c2c_b into level 2/3 @ds= t. */ +static bool c2c_he__add_sharing(struct c2c_hist_entry *dst, struct c2c_his= t_entry *src) +{ + /* Do the fallible update first so a failure leaves dst unmodified. */ + if (!hist_entry__add_c2c_stats(&dst->he, &src->stats)) + return false; + + c2c_add_stats(&dst->stats, &src->stats); + c2c_add_cstats(&dst->cstats, &src->cstats); + return true; +} + +/* + * Process one cacheline and create/update the level-1/2/3 hierarchy entri= es + * for every pair of functions sharing it. + */ +static int c2c_function__process_cl(struct c2c_hist_entry *cacheline_he, u= 64 cl_addr, + struct thread *synthetic_thread) +{ + struct rb_node *nd_a, *nd_b; + struct function_seen *seen =3D NULL; + int nr_seen =3D 0, nr_alloc =3D 0; + int ret =3D 0; + + for (nd_a =3D rb_first_cached(&cacheline_he->hists->hists.entries); nd_a; + nd_a =3D rb_next(nd_a)) { + struct hist_entry *he_a =3D rb_entry(nd_a, struct hist_entry, rb_node); + struct c2c_hist_entry *c2c_a; + struct hist_entry *level1_he; + struct c2c_hist_entry *level1_c2c; + u64 iaddr_a; + + if (!he_a->ms.sym || he_a->filtered) + continue; + + c2c_a =3D container_of(he_a, struct c2c_hist_entry, he); + iaddr_a =3D hist_entry__iaddr(he_a); + + level1_he =3D c2c_function_hists__level1_entry(he_a->ms.sym, iaddr_a, + he_a, synthetic_thread); + if (!level1_he) { + ret =3D -ENOMEM; + goto out; + } + + level1_c2c =3D container_of(level1_he, struct c2c_hist_entry, he); + + /* + * Aggregate every source entry into its level-1 (sym, iaddr) + * parent. level1_he is keyed by (sym, iaddr), so all siblings + * collapse into the same parent. When the cacheline view splits + * one (sym, iaddr) into siblings (only under -d pid/tid/dso), + * each sibling holds a DISJOINT slice of the traffic, so summing + * them here is correct accumulation, not double counting. The + * seen[] set below therefore guards only the inner B-loop (to + * avoid building a level-2 subtree twice), never this L1 update. + * Update he->stat first; on failure leave the aggregates untouched. + */ + if (!hist_entry__add_c2c_stats(level1_he, &c2c_a->stats)) { + ret =3D -ENOMEM; + goto out; + } + c2c_add_stats(&level1_c2c->stats, &c2c_a->stats); + c2c_add_cstats(&level1_c2c->cstats, &c2c_a->cstats); + c2c_add_stats(&c2c_ext.function_hists.stats, &c2c_a->stats); + + /* Skip the inner loop when this (symbol, iaddr) is already a parent. */ + if (function_seen__find(seen, nr_seen, he_a->ms.sym, iaddr_a)) + continue; + + if (nr_seen =3D=3D nr_alloc) { + struct function_seen *tmp; + int new_alloc =3D nr_alloc ? nr_alloc * 2 : DEFAULT_SYMBOLS_PER_CL; + + tmp =3D reallocarray(seen, new_alloc, sizeof(*seen)); + if (!tmp) { + ret =3D -ENOMEM; + goto out; + } + seen =3D tmp; + nr_alloc =3D new_alloc; + } + seen[nr_seen].sym =3D he_a->ms.sym; + seen[nr_seen].iaddr =3D iaddr_a; + nr_seen++; + + for (nd_b =3D rb_first_cached(&cacheline_he->hists->hists.entries); nd_b; + nd_b =3D rb_next(nd_b)) { + struct hist_entry *he_b =3D rb_entry(nd_b, struct hist_entry, rb_node); + struct c2c_hist_entry *c2c_b, *level2_c2c, *level3_c2c; + u64 iaddr_b; + + if (!he_b->ms.sym || he_b->filtered) + continue; + + c2c_b =3D container_of(he_b, struct c2c_hist_entry, he); + iaddr_b =3D hist_entry__iaddr(he_b); + + /* Skip self. */ + if (iaddr_a =3D=3D iaddr_b && + symbol_name_equal(he_a->ms.sym, he_b->ms.sym)) + continue; + + level2_c2c =3D c2c_function_hists__level2_entry(level1_c2c, he_b->ms.sy= m, + iaddr_b, he_b); + if (!level2_c2c || !c2c_he__add_sharing(level2_c2c, c2c_b)) { + ret =3D -ENOMEM; + goto out; + } + + /* + * Cache the running sum of level-2 store counts on the + * level-1 parent, mirroring c2c_he__add_sharing() above, + * so hist_entry__child_stores() stays O(1). + */ + level1_c2c->child_stores +=3D c2c_b->stats.store; + + level3_c2c =3D c2c_function_hists__level3_entry(level2_c2c, cl_addr, + cacheline_he); + if (!level3_c2c) { + ret =3D -ENOMEM; + goto out; + } + + if (!c2c_he__add_sharing(level3_c2c, c2c_b)) { + ret =3D -ENOMEM; + goto out; + } + } + } + +out: + free(seen); + return ret; +} + +/* Sort level-2/3 children by store count, then compute the global total. = */ +static void c2c_function__finalize(void) +{ + struct rb_node *nd_l1; + + for (nd_l1 =3D rb_first_cached(&c2c_ext.function_hists.hists.entries); nd= _l1; + nd_l1 =3D rb_next(nd_l1)) { + struct hist_entry *he_l1 =3D rb_entry(nd_l1, struct hist_entry, rb_node); + struct rb_node *nd_l2; + + if (!he_l1->has_children) + continue; + + c2c_he__resort_by_stores(he_l1); + + for (nd_l2 =3D rb_first_cached(&he_l1->hroot_out); nd_l2; + nd_l2 =3D rb_next(nd_l2)) { + struct hist_entry *he_l2 =3D rb_entry(nd_l2, struct hist_entry, rb_node= ); + + if (he_l2->has_children) + c2c_he__resort_by_stores(he_l2); + } + } + + c2c_ext.total_cycles =3D c2c_ext__total_cycles(); +} + +/* + * Build the three-level function view in a single pass over the cacheline + * entries: + * L1: aggregate stats per primary function + * L2: sharing functions referenced from each L1 function + * L3: cachelines that pair L1 with L2 + */ +static __maybe_unused int build_function_view_hierarchy(void) +{ + static const char output_fields[] =3D + "cycles_percent,total_stores,iaddr_symbol,symbol_view,cacheline_symbol"; + struct rb_node *nd_cl; + int ret; + + c2c_ext.total_cycles =3D 0; + memset(&c2c_ext.function_hists.stats, 0, + sizeof(c2c_ext.function_hists.stats)); + + hists__delete_entries(&c2c_ext.function_hists.hists); + if (c2c_ext.function_hists.list.fields.next) + perf_hpp__reset_output_field(&c2c_ext.function_hists.list); + + ret =3D c2c_function_hists__init(&c2c_ext.function_hists, + "iaddr_symbol,symbol_view", 2, NULL); + if (ret) + return ret; + + nd_cl =3D rb_first_cached(&c2c.hists.hists.entries); + + /* An empty C2C report yields an empty (but valid) function view. */ + for (; nd_cl; nd_cl =3D rb_next(nd_cl)) { + struct hist_entry *he_cl =3D rb_entry(nd_cl, struct hist_entry, rb_node); + struct c2c_hist_entry *cacheline_he =3D container_of(he_cl, + struct c2c_hist_entry, he); + struct thread *synthetic_thread =3D he_cl->thread; + u64 cl_addr; + + /* + * Include any cacheline with sharing activity (HITM, peer, + * stores or loads), not just HITM, so totals/sorting reflect + * all aggregated traffic surfaced by the function view. + */ + if ((c2c_hitm_count(&cacheline_he->stats) =3D=3D 0 && + cacheline_he->stats.tot_peer =3D=3D 0 && + cacheline_he->stats.store =3D=3D 0 && + cacheline_he->stats.load =3D=3D 0) || + !cacheline_he->hists || + RB_EMPTY_ROOT(&cacheline_he->hists->hists.entries.rb_root) || + !he_cl->mem_info || !synthetic_thread) + continue; + + cl_addr =3D cl_address(mem_info__daddr(he_cl->mem_info)->addr, chk_doubl= e_cl); + ret =3D c2c_function__process_cl(cacheline_he, cl_addr, synthetic_thread= ); + if (ret) + goto out_err; + } + + ret =3D c2c_function_hists__reinit(&c2c_ext.function_hists, output_fields, + "cycles_percent", NULL); + if (ret) + goto out_err; + + hists__collapse_resort(&c2c_ext.function_hists.hists, NULL); + hists__output_resort(&c2c_ext.function_hists.hists, NULL); + + c2c_function__finalize(); + + return 0; + +out_err: + /* + * On error, migrate any entries still in entries_in to entries and + * delete them, so a later rebuild does not strand them (the top-level + * __hists__init() memset would otherwise lose the pointers). + */ + hists__collapse_resort(&c2c_ext.function_hists.hists, NULL); + hists__output_resort(&c2c_ext.function_hists.hists, NULL); + hists__delete_entries(&c2c_ext.function_hists.hists); + return ret; +} + int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) { ui__warning("C2C function view is not implemented yet.\n"); --=20 2.52.0 From nobody Sun Jul 26 01:47:32 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2AA383F39E9; Fri, 10 Jul 2026 08:43:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673016; cv=none; b=WQiggOjCbXN8Ew6nfZVZvkzKL8Dt+RjovMceO47P1AoX3NPSOZhOuLx8HHW/vmDgF09A57PeQvlwEaHZxXPk+F+YbzzKaFMwWj5385f6tu84vWZwAEr6WKXcsO5Cqt3cJe/ug0xNCdfhOQKvWJIBr0Vkbtcvv2GG94eYXGXAtg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673016; c=relaxed/simple; bh=R5NEIwYZSgdrWu8wKRE5gn3sFWfLGw/F3DJGjMofMCw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oLUDb8q4UXfLjwhU0n2JKI6MX+1F/LKQxpi5nlOodVvs/TztMIhem3xYAQQKMsixYXi6FvYeBAgcqVum99JtGYGfDN8FWNemXbr3L7Os/zjPB5KJdwFJhfEXHA4cQgrTulpiOoL2gKVRJwc6uvGnscJfe/lStvsSBQN/iRUEYjQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=T0vk3SGF; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="T0vk3SGF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783673012; x=1815209012; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=R5NEIwYZSgdrWu8wKRE5gn3sFWfLGw/F3DJGjMofMCw=; b=T0vk3SGFfRPTYH27qt7ZX7ZKBhgMLNMgFKtBC8yyl071jpPwA+UuXzvj ztf1uqd5e7OvSKtBhCMalzVpeEFiO+xmYbwhegj37YjfZwZ5p2OntZtLN bTHZE3X+BZrLP1UJP8hTod7wuDH7LCSct7+PIZvZV1+cFsy+2lwYSKX75 +Cl+rI0wFHDajz+CoDUPpG85a/laSXlz8s8yEJplhWZG5VBXPjs3IO4+m j+Mn3YT85EjyZ5U5WZuyH+Z7CApv9Dp9ifSV/fMZJYUPrhZb3a31MZBBH FRjcLp2dFUeq6fquWPVCVv5WRKUTij1eUuKugWGVKD2by5Sd359UUcMEg w==; X-CSE-ConnectionGUID: UKr+ScjsR+K8MbCBvGV34A== X-CSE-MsgGUID: worGNcExTL6PBMGqG6Sd2Q== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390899" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390899" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:31 -0700 X-CSE-ConnectionGUID: yYdJpvf0RbaICg6wVRuoiA== X-CSE-MsgGUID: EHre6RuQR0id7FpeGZYuTg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435462" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:26 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 12/14] perf c2c: add function view browser UI Date: Fri, 10 Jul 2026 16:42:45 +0800 Message-ID: <20260710084247.3576706-13-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace the stub perf_c2c__browse_function_view() with the full interactive browser implementation: - c2c_function_browser__new(): create browser with hierarchy support, disabling callchains for clean function-level display - c2c_function_browser__browse_cacheline_detail(): drill into cacheline detail view via 'd' key - c2c_function_browser__title(): display entry count in title bar - c2c_function_browser__delete(): cleanup on exit The browser saves/restores symbol_conf.use_callchain to avoid corrupting the callchain display in the cacheline view after returning from the function view. The browser entry point perf_c2c__browse_function_view() is wired up by the next patch, which adds the TAB key in the cacheline view to switch into the function view. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/ui/browsers/c2c-function.c | 159 +++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 6 deletions(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 80e032d5e31c..e23f90ec282c 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -2,7 +2,7 @@ /* * C2C Function Browser - function-level cacheline sharing analysis * - * Planned UI: 3-level hierarchy showing which functions share cachelines = (not implemented yet): + * Displays a 3-level hierarchy showing which functions share cachelines: * Level 1: Primary functions sorted by Cycles % (estimated load cycles) * Level 2: Other functions sharing cachelines with the level-1 function * Level 3: Specific shared cachelines between each pair of functions @@ -44,7 +44,7 @@ struct perf_c2c_ext { u64 total_cycles; }; =20 -static struct perf_c2c_ext c2c_ext __maybe_unused; +static struct perf_c2c_ext c2c_ext; =20 struct c2c_function_browser { struct hist_browser hb; @@ -1335,7 +1335,7 @@ static void c2c_function__finalize(void) * L2: sharing functions referenced from each L1 function * L3: cachelines that pair L1 with L2 */ -static __maybe_unused int build_function_view_hierarchy(void) +static int build_function_view_hierarchy(void) { static const char output_fields[] =3D "cycles_percent,total_stores,iaddr_symbol,symbol_view,cacheline_symbol"; @@ -1409,8 +1409,155 @@ static __maybe_unused int build_function_view_hiera= rchy(void) return ret; } =20 -int perf_c2c__browse_function_view(struct hists *hists __maybe_unused) +static int c2c_function_browser__title(struct hist_browser *browser, + char *bf, size_t size) { - ui__warning("C2C function view is not implemented yet.\n"); - return -ENOSYS; + scnprintf(bf, size, + "Shared Data Functions Table (%" PRIu64 " entries, sorted on Cycle= s %%)", + browser->nr_non_filtered_entries); + return 0; +} + +static struct c2c_function_browser *c2c_function_browser__new(struct hists= *hists) +{ + struct c2c_function_browser *browser; + + if (!hists) + return NULL; + + browser =3D zalloc(sizeof(*browser)); + if (!browser) + return NULL; + + hist_browser__init(&browser->hb, hists); + + browser->hb.title =3D c2c_function_browser__title; + browser->hb.c2c_filter =3D true; + browser->hb.show_headers =3D true; + /* Keep title line count consistent with forcing headers on. */ + browser->hb.b.extra_title_lines =3D hists->hpp_list->nr_header_lines; + browser->hb.min_pcnt =3D 0.0; + + /* + * Note: symbol_conf.report_hierarchy is deliberately left unset. + * The generic browser still descends into hroot_out children via + * rb_hierarchy_next()/can_goto_child(), which key off he->unfolded, + * so 'e'/'+' expands L1 -> L2 -> L3 correctly. Setting the flag would + * additionally make hist_entry__delete() recurse hroot_out and free + * each child, but our children borrow thread/ms (see + * c2c_child_entry__alloc()), so that would underflow their refcounts. + * Teardown is handled by c2c_he__free_hierarchy() instead. + */ + return browser; +} + +/* + * c2c_function_browser__delete - Free function browser + */ +static void c2c_function_browser__delete(struct c2c_function_browser *brow= ser) +{ + free(browser); +} + +static int c2c_function_browser__browse_cacheline_detail(struct hist_entry= *he_selection, + struct hists *hists) +{ + struct rb_node *nd; + u64 cl_addr; + + if (!he_selection || !he_selection->parent_he || + !he_selection->parent_he->parent_he || !he_selection->mem_info) + return -1; + + cl_addr =3D cl_address(mem_info__daddr(he_selection->mem_info)->addr, chk= _double_cl); + + for (nd =3D rb_first_cached(&hists->entries); nd; nd =3D rb_next(nd)) { + struct hist_entry *he_cl =3D rb_entry(nd, struct hist_entry, rb_node); + u64 this_cl; + + if (!he_cl->mem_info) + continue; + + this_cl =3D cl_address(mem_info__daddr(he_cl->mem_info)->addr, chk_doubl= e_cl); + if (this_cl =3D=3D cl_addr) + return perf_c2c__browse_cacheline(he_cl); + } + + return -1; +} + +/* + * perf_c2c__browse_function_view - Browse function view with TAB key supp= ort + * @hists: Main cacheline histograms + * + * Returns: 0 on success, negative error code on failure + */ +int perf_c2c__browse_function_view(struct hists *hists) +{ + struct c2c_function_browser *sym_browser; + bool saved_use_callchain =3D symbol_conf.use_callchain; + int key, ret; + static const char help[] =3D + " d Display cacheline details for the selected entry\n" + " e/+ Expand/collapse the selected entry\n" + " TAB/ESC/q Return to the cacheline view\n"; + + if (!hists) + return -EINVAL; + + /* Disable callchain before building so no callchain structs are allocate= d. */ + symbol_conf.use_callchain =3D false; + + ret =3D build_function_view_hierarchy(); + if (ret) { + ui__error("Failed to build function view hierarchy (ret=3D%d)\n", ret); + goto out; + } + + sym_browser =3D c2c_function_browser__new(&c2c_ext.function_hists.hists); + if (!sym_browser) { + ret =3D -ENOMEM; + goto out; + } + + /* Reset abort key so we can receive Ctrl-C as a key. */ + SLang_reset_tty(); + SLang_init_tty(0, 0, 0); + SLtty_set_suspend_state(true); + + sym_browser->hb.nr_non_filtered_entries =3D + c2c_ext.function_hists.hists.nr_non_filtered_entries; + + while (1) { + key =3D hist_browser__run(&sym_browser->hb, "? - help", true, 0); + + switch (key) { + case 'q': + case K_TAB: + case K_ESC: + goto browser_done; + case 'd': + /* Cacheline detail honors the user's callchain setting. */ + symbol_conf.use_callchain =3D saved_use_callchain; + c2c_function_browser__browse_cacheline_detail(sym_browser->hb.he_select= ion, + hists); + /* Preserve any toggle made in the detail view, then + * re-disable callchain for the function view. + */ + saved_use_callchain =3D symbol_conf.use_callchain; + symbol_conf.use_callchain =3D false; + break; + case '?': + ui_browser__help_window(&sym_browser->hb.b, help); + break; + default: + break; + } + } + +browser_done: + c2c_function_browser__delete(sym_browser); +out: + symbol_conf.use_callchain =3D saved_use_callchain; + return ret; } --=20 2.52.0 From nobody Sun Jul 26 01:47:32 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 99CFD3F1ACF; Fri, 10 Jul 2026 08:43:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673022; cv=none; b=Cp4Q2iRIScDJswYdMGBMDEc+SGqNFB28+rZKpqHgWAY7s3mbpA1+Je67IQgqnc+Eo+WOBUmRZC0hTK+YOLrXcEACsuDdg6+Jr0HTB8JyYDRqOAd/MkIgzRkyOBpzMbLIrVJq4Frn5ebwc8txnYfMKi/BHmHRyQtTYmJTOsP4GlI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673022; c=relaxed/simple; bh=Ewfnh6yrSu/plgJzPF6dpQ01/Es2m2b+1MNzDAzcV6s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=spWjr7LdtzRRRw/TDhrYYmRY6DEQxzXO4UOb+pRjVC10xuQkCyJuBA1dCOxgDKEhZ2z+mktgudQJF4DCFwp8GOiWoCcijAel/cIeE2tmShIrHF65TYK7/k5ovZHE5Nk9mOE7OyraSJdYQ1TmpWzI4I567obcEFpcf8Aw30c6IKY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=bqzTDXyk; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="bqzTDXyk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783673021; x=1815209021; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Ewfnh6yrSu/plgJzPF6dpQ01/Es2m2b+1MNzDAzcV6s=; b=bqzTDXykZyVofOI43MeCTZO0bcOoVFxtg18OHXvUcuwZEWGoRo+rABJH LM7GFQLZ0bsrFlVRWF/eBlWpXStaGLqY0d6JhmYIO49XJEzkGxrG75LHC /1WiD6G3fuhHzyU1Z7wkN6kcOhqobaqlqSUZmBS1oNx79TJR88rHZpuQA uBkbfd/TGN3oKrxpxUB8D2t2PRVX+MaEdrVVcJVV4n20swOt2sFnyVoyi NYIOY2DrTShjoZ/WePUpzlUXiZbzjLCIQ+3gyPpNty+6B91ndDRHxNaGF CLYXbXEzxQT5/KgxWtIhJCR8/C0pnRfICNLHV3h5goc3BV6KKzp39vyap w==; X-CSE-ConnectionGUID: XW8dw8SnQZyre2oMq8rZMA== X-CSE-MsgGUID: jXdPQ0fFQUaEdCjAjVKFHA== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390915" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390915" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:35 -0700 X-CSE-ConnectionGUID: 1dLcrXI4QCSF3qaKP9o1Tg== X-CSE-MsgGUID: KXB6ZY6hSg+9LpH9FPkp5g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435472" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:31 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 13/14] perf c2c: add TAB key to switch to function view Date: Fri, 10 Jul 2026 16:42:46 +0800 Message-ID: <20260710084247.3576706-14-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Wire up the TAB key in the cacheline browser to launch the function view browser via perf_c2c__browse_function_view(). This allows users to switch between the traditional cacheline view and the new function-level sharing analysis view. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/builtin-c2c.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 33271554e354..a924948bc507 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2693,6 +2693,7 @@ static int perf_c2c__hists_browse(struct hists *hists) static const char help[] =3D " d Display cacheline details \n" " ENTER Toggle callchains (if present) \n" + " TAB Switch to function view\n" " q Quit \n"; =20 browser =3D perf_c2c_browser__new(hists); @@ -2714,6 +2715,9 @@ static int perf_c2c__hists_browse(struct hists *hists) case 'd': perf_c2c__browse_cacheline(browser->he_selection); break; + case '\t': + perf_c2c__browse_function_view(hists); + break; case '?': ui_browser__help_window(&browser->b, help); break; --=20 2.52.0 From nobody Sun Jul 26 01:47:32 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 073063F20F4; Fri, 10 Jul 2026 08:43:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673023; cv=none; b=QbcFr2Mz5q2zE0/xXsPcOifEQ8ixRqgePVYp378xL08GLhAMa/MFIqAodsWA6ovGuYq7EG96MD/baMM8S2anzKSNZOXP8esKflJyXC+xRvfOU7cLEFfcRuVFPhj1Zmt8f7qi53CEQ/kyPlAoagyEok0FXyPSpsWhzo/HxQ3ts70= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673023; c=relaxed/simple; bh=Mm/vrSGZHFmbT5s4VKo2mi6DurGi7q5CM4ASEQyOr9c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LLdGd7PDf67xGa74u7pp0yp12rrNJypxqQt8trsAj/JJAqk/bbtmsgCqtzAPykLfT57fOpoCFRuYOebB+/LomHN5LgO1WDUy86G8ftkL/zhVl4cKDWqQ5FM1jPBESxFOMJQ5bdvrHKNFs7a6U8O6zZayvKKUwvhE0+EHDWrTIqg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Bj7LXhrO; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Bj7LXhrO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783673021; x=1815209021; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Mm/vrSGZHFmbT5s4VKo2mi6DurGi7q5CM4ASEQyOr9c=; b=Bj7LXhrOLaBuyo3B0Spx5OAeTbAsktyU8QmT+fh5xtbS/V3a1T1+bPk0 ETELNE6zOBq5zhOEPufW0CnEHNbUdXCDGDO6BPeWEjCL9P1oJsnfeYu35 NbOKJVy7jUp9N4opJ7kyu01LcqG8ZDMe/wP1gTlaMztDxYsMelwS3p5Sr OVGKmSco2TXjCUTM6z5FGg6Pdyzo/6Bsjw6H6Z0H8kEyrmmzTcG87A2xl lPt13DFfkdF6OsawLEadh22Fs9h685CC38ZT66V3ugza7WjG01BFpcf9t JeNZowF7d2WVz3v2bqI3mWUN24CD14zVQoq6JluulmSOzrxx2qkOfATNx g==; X-CSE-ConnectionGUID: 461TuO4XT96jAB0FUlksPQ== X-CSE-MsgGUID: nv2lZMwqQTSknlXZpt5UnA== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84390928" X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="84390928" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2026 01:43:40 -0700 X-CSE-ConnectionGUID: YB/7jqPwRoeBECB+LLRoGw== X-CSE-MsgGUID: jQpiTLV4SHW3m1F3j/0Fag== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,154,1779174000"; d="scan'208";a="258435503" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by orviesa003.jf.intel.com with ESMTP; 10 Jul 2026 01:43:36 -0700 From: Jiebin Sun To: Namhyung Kim , Arnaldo Carvalho de Melo , Ingo Molnar , Peter Zijlstra Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun , Adrian Hunter , Alexander Shishkin , Dapeng Mi , Ian Rogers , James Clark , Jiri Olsa , Mark Rutland , Thomas Falcon , Tianyou Li , Wangyang Guo Subject: [PATCH v2 14/14] perf c2c: document function view in perf-c2c man page Date: Fri, 10 Jul 2026 16:42:47 +0800 Message-ID: <20260710084247.3576706-15-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260710084247.3576706-1-jiebin.sun@intel.com> References: <20260626070355.1556721-1-jiebin.sun@intel.com> <20260710084247.3576706-1-jiebin.sun@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Describe the three-level function-view hierarchy (primary function, sharing functions, shared cachelines) and the TAB/ESC/d/e key bindings that drive it. Signed-off-by: Jiebin Sun Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Dapeng Mi Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Reviewed-by: Tianyou Li Reviewed-by: Wangyang Guo --- tools/perf/Documentation/perf-c2c.txt | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/perf/Documentation/perf-c2c.txt b/tools/perf/Documentati= on/perf-c2c.txt index e57a122b8719..43a3f195048a 100644 --- a/tools/perf/Documentation/perf-c2c.txt +++ b/tools/perf/Documentation/perf-c2c.txt @@ -365,6 +365,39 @@ TUI OUTPUT The TUI output provides interactive interface to navigate through cachelines list and to display offset details. =20 +Pressing the 'TAB' key in the cacheline view switches to the function +view. The function view shows a three-level hierarchy of the same data, +organized around functions rather than cachelines: + + Level 1: primary functions, sorted by Cycles % (estimated load cycles: + HITM, peer-snoop and other-load cycles -- on systems whose + default display mode is peer, such as Arm64, the peer-snoop + component dominates) + Level 2: other functions that share cachelines with the level-1 function + Level 3: the specific shared cachelines for each function pair + +In the function view the 'd' key opens the detail view of the selected +cacheline, 'e'/'+' expands or collapses the current entry, and 'TAB', +'ESC' or 'q' returns to the cacheline view. + +For example, expanding a level-1 function reveals the functions it shares +cachelines with, and expanding one of those reveals the specific shared +cachelines: + + Shared Data Functions Table (27 entries, sorted on Cycles %) + Cycles Store + % count Code address Symbol Cacheline + ---------------------------------------------------------------------- + - 39.03% 541 - 0xffffffffa2fc5b08 - [k] cpupri_set + 450 - 0xffffffffa2fa28a5 - [k] pull_rt_task + 450 0xff2d0082809da080 + +Here cpupri_set is the most contended function (39.03% of the estimated +load cycles); it shares data with pull_rt_task (450 stores into the shared +data); and the contention is on the single cacheline 0xff2d0082809da080. +This is the false-sharing chain that the cacheline view otherwise leaves +to be reconstructed by hand. + For details please refer to the help window by pressing '?' key. =20 CREDITS --=20 2.52.0