From nobody Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 E9267332909; Fri, 17 Jul 2026 02:05:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253942; cv=none; b=JmU26X9T17UGtITpICi5jx7nLqOehlKzJ/uSxcK2Z/MjmTKd2uy75huetM1EB1m3G97OnNlCjajoJyWNBQo5RNSvd+6OdTnwxbBWis3htEGVkZtA1P2CgTfrPbQa3Hr9pWCzcb1O7UC57Dd1WlyfNcaFpV3VxIIG1r9ANo7nkbA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253942; c=relaxed/simple; bh=O+pc0eKofkHxpCHKLWDrDTMDDylWJRrpM5TzaSPkn6w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NDi+m9cu2PWlnHhLAVApJdHLf+jWlaEzCcF3eS3UfBxcf83wuaGFFxlIOhnKptQcuzt8o5PbC90omTLmNkmtICGPUSEQMbyWnw1safRoqYHVVSiDdaHFkVNQDLWjLF430YNNcnvrKqarg4nf8HCTTrlLbYQN8+khfZi7eCTH56A= 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=g/e8gxYH; arc=none smtp.client-ip=198.175.65.9 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="g/e8gxYH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253938; x=1815789938; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=O+pc0eKofkHxpCHKLWDrDTMDDylWJRrpM5TzaSPkn6w=; b=g/e8gxYHk/cfsaVmrRxrfhWaxV6VWqGpGjUIda+8PzbEVY8y0Rsd2paL 4ShMoN3z0+D8pJKgkHNP6jOg6t+Uwl67/9juQnvcDjJZ/likyuNqt/a0/ AswrVd1fp5UGON+ywG8/pZKqTq8qhBnhYElyUmGFehPc9e7IamPsK1eMq 0QhgI+ulxRn/DfAlkocPPDJpcTESx8IVAn79kgRj4qrZ0+1a50ZbfRtbb UsN2uy3z+e9MeTQVKxZREp2OCFUPsKOsmL8vUmWFvQSdpYG7ZD7WG7UZR 9KYuzUBXW8uR8opbTiNNYfm2XUu5XXi2Knuh7Mce1240wLGilswSrGACf A==; X-CSE-ConnectionGUID: DoPusM8kTwik8vS5vUN3jQ== X-CSE-MsgGUID: Ve7UVwzdQWmXYVxhO7yu3Q== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107719984" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107719984" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:05:35 -0700 X-CSE-ConnectionGUID: SSGxH8qJTg6xv346l1kwpw== X-CSE-MsgGUID: in5qTazOSMmE5gcDYPrQSQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952731" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:27 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 01/14] perf c2c: extract shared data structures into c2c.h Date: Fri, 17 Jul 2026 10:05:17 +0800 Message-ID: <20260717020530.1645123-2-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 | 128 +++------------------------------- tools/perf/c2c.h | 147 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 120 deletions(-) create mode 100644 tools/perf/c2c.h diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index c9584dbedf77..f1dd9d8699cb 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 c2c_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 c2c_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); @@ -2021,8 +1909,8 @@ static struct c2c_fmt *get_format(const char *name) 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; + fmt->equal =3D c2c_fmt_equal; + fmt->free =3D c2c_fmt_free; =20 return c2c_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..79dbd35184ed --- /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 c2c_fmt_free(struct perf_hpp_fmt *fmt); +bool c2c_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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 739643271FD; Fri, 17 Jul 2026 02:05:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253944; cv=none; b=Xmk9sKx6Px/VgUAp+QLLHEvFvqQ/sXv5gQJ1jbzLIvuL/+To9RBdAqGi/T2zSSbff9q1OKNqBaY2YJhWTRnGLdtzgBxU02+IyZp9xc0YPz+JWJNHkQUQW7BVjXnJetm+0Guw2mViDZBd4KB/pZiL0YjVLzeIh6uM5e482A22NLs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253944; c=relaxed/simple; bh=SVTH4lvkuQDkOiwt+MperC8LbMMI/0PCO+ivJQcBkyc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X3rTymTVs3DXwOJvrBDMVlkE7HgZg3ul3lde6YiRpBfGOWXAGT7Yjqs0cQixCuHAy7895r5HTV9TPWBfN+iFmEGUATPDD0ky69ytb6VTXHW14iAWJowye/GkB/Dnm28RNtlmrAwdJ9Al00N3k227pv/KDIDVney0X0+JOL8XsUQ= 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=OWuBXZVH; arc=none smtp.client-ip=198.175.65.9 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="OWuBXZVH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253939; x=1815789939; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SVTH4lvkuQDkOiwt+MperC8LbMMI/0PCO+ivJQcBkyc=; b=OWuBXZVHFqoNKCdofEoFMn0o4fMYKpT6+h0pm3Z/WOUhNVRxAzFORkxq LtyPSHqm2uWpPq/Lqg5Q3iqJgIGOOYgO8+2C8W42ubOWF76bNVFxlMdvy C8EdbXMqIl0B3jjxiPyGyFRhGCU6SS57Pjz6t5YHLDmSYrepcbBZxVjJl g9Fd2XvGxMkXj6uinBVGViEq1iTh8llTnoEDSj+dBIdHzI0hzdSwOWo9U snmIBmMhX4mUgnfV0RxdD0jJ4qM44iSY+H386vz0i9s6GFHwXOcDqTLMT KgdU/BvfGfOFq3pBqOcDhsyMhNkjZNiBY3isPf9ISPYSc2w6mmmY6rOp2 A==; X-CSE-ConnectionGUID: PawUhYSYTr6+4PcX7OSFzw== X-CSE-MsgGUID: 8jb70teUQlqrD4SGNLEejw== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107719993" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107719993" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:05:36 -0700 X-CSE-ConnectionGUID: 0/AWS3IkTn2ynMna5QJAJQ== X-CSE-MsgGUID: QiXC+gkTQ0ixKX8XvpkUlw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952747" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:32 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 02/14] perf c2c: add function view browser skeleton Date: Fri, 17 Jul 2026 10:05:18 +0800 Message-ID: <20260717020530.1645123-3-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 79dbd35184ed..6fc3fda40fb6 100644 --- a/tools/perf/c2c.h +++ b/tools/perf/c2c.h @@ -142,6 +142,7 @@ bool c2c_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..c50c8ca825c1 --- /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 0; +} --=20 2.52.0 From nobody Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 2FC5C331EDA; Fri, 17 Jul 2026 02:05:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253945; cv=none; b=hLnpqiOipIZoExnPB/lCkVXPfUrOB0+YB6xjDvTy4Y12UKN8TgVWV+Ey/iLLcXuhr52LktxMSedPPq6zfQTTkO1Fs2xmMpCW1uCd2YQq1mZY2Grl7yMZkN1W+/odQ3aeivtpBteChDOeJvB+WVomAPj1ZrU1yDNXZZgRcGBUEz4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253945; c=relaxed/simple; bh=qjvtMCb2GkiOYLLPFMLPERHeA7OneW9Ey6hkcxCafnk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=R/iiOPxlQG4DGbFSjBRnXLouDkK9P8mU2jqwd64VYDWBAsenJR8IsOWh33xx/z+2F3merTyI70RyQiaDyCoQYXnoiFD5Rbm2Pr+Vr9BRqHARlo30A6xn0uPrlwl/UVX9M6jinoYj768r7PjkMrL8OGmdbmb+WEUU5qJDizhfOvg= 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=Bq+xuqBB; arc=none smtp.client-ip=198.175.65.9 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="Bq+xuqBB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253943; x=1815789943; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qjvtMCb2GkiOYLLPFMLPERHeA7OneW9Ey6hkcxCafnk=; b=Bq+xuqBBFrkc0H3ObzvNGFT3vhWhB302TL8/HA4qXRzJxyyCcKABecQS vEgwHPMQ/55Mc/Cqrqle6ku8/GXBPUJ9hAPsOsNf1A1UQzqx6vv0o7FZC 2a/7ASbPDLksjqTPbX5a2aSCiO3agtfntUGbLvjka87o3xtDYLGSQv9Hx rhv13H4gUPRLRAA0gPWzVyAiPsQ6EFOYZqWZnj0wMBoeQYa7vHQcsVtYg kRfGmP8Ni+4V02smayqjBFSeo/sK7n8gJG9dcfF3z7jVkRgePC7dc8BUb vT0bZbxbyEreImPbZJNO2HWM2qNlqO4+VtZF2mTT5UH5u+CADT/OTBKMO A==; X-CSE-ConnectionGUID: xEZri94CTTSE/JVfJY0sAw== X-CSE-MsgGUID: UeGmLLJOR4qSdnrQtbZBaw== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720004" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720004" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:05:41 -0700 X-CSE-ConnectionGUID: jJqBcsiiTL+0IHAEmFiuFg== X-CSE-MsgGUID: E1ydT2RxSWmExfyHvugHbQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952770" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:36 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 03/14] perf c2c: add function view type definitions and helpers Date: Fri, 17 Jul 2026 10:05:19 +0800 Message-ID: <20260717020530.1645123-4-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 c50c8ca825c1..1ef5d08e81c3 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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 78E0332E692; Fri, 17 Jul 2026 02:05:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253949; cv=none; b=DxTkQpnBUblIHvd53gvxWX1GrOWbiJUF5yhN1nCOvZN0yHS6kTHgNWQjGyRJjkZ3Zg9w4qyax/qon+ZyF78Z4foc/mUpDfd5FYObaKWD7UecQJdMmWGO/SqKr55JU4jYLarp2X/Dc9VXau27mb18Kt3i7Zl1qR7QvceIUp/nMr4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253949; c=relaxed/simple; bh=C4nE69A6b95ym88LWiJH0K1yJS2wEOWkXhNLUfCRMK4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DQf7XM8HJWd+PbbeZoxov3h2ZtdFLmWz8tcPBLQE+R2N51eRPx8oSSG21YdZK3nFpMj6fO3BiLRAgm39wYWp3q34fPQrE6ynyQX2tkKZA8h+t4KV5dzVIDtM6Um5Ywpknj1M8F7XM1hz9BTHoh5YHLKKz0eGOdZE+jrFbyPJlIU= 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=RsIphQ0g; arc=none smtp.client-ip=198.175.65.9 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="RsIphQ0g" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253946; x=1815789946; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=C4nE69A6b95ym88LWiJH0K1yJS2wEOWkXhNLUfCRMK4=; b=RsIphQ0gmATgLSEX1fjd/JOVgOrjKZhK9lOVMwS+o2BhOomR2yiMuCwh o9aWzl7I5PHT2OfpQzId7vA6fJZ15Yja2nRDJ7yN/TpybNdZ0TRWFU7/n SJlL0yNdPViOKDH23S7wDREpOFN7Sdfxm0CtTG8upN81ATQ08xIiQB/pD 3zPkeQq0V+JQlgyD5T8+DgJHM45yMc7MhwdZa+u93yp0xrA/dj/G2IYid iUlAnO/ne40QG5bD/Hnzz70cpC/uIhy4xD2FqYf0vXgf19m8rkuQkBICL KnT6JrE4qJGOLR779PNUMRyskI71f44OjehqatdPSSiLpQlhviUGULxUF Q==; X-CSE-ConnectionGUID: KskI98wLRkGc/95EkhKwvQ== X-CSE-MsgGUID: 8NDHK4HWSw+Gh9M9sy+CBA== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720014" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720014" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:05:45 -0700 X-CSE-ConnectionGUID: 6E9Oc9M4ShCKKnK+sYuAww== X-CSE-MsgGUID: Et1n+DJxSK6SIqBCbAKfVQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952796" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:40 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 04/14] perf c2c: add column format infrastructure for function view Date: Fri, 17 Jul 2026 10:05:20 +0800 Message-ID: <20260717020530.1645123-5-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 1ef5d08e81c3..ace7e3f27b55 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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 775F8331A48; Fri, 17 Jul 2026 02:05:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253952; cv=none; b=kIJdbhX76wk9RkbJTNSI3xPBxorb/aPxsjVCVhkQMzuVYogXjtSBwidjmgBZ54JqZcGkahILsd8RndWS0JW3s0MO9/d2LLfH9Uorps11DRypG/stwV8mbva3Dh2YW8l/eJBB8PpfDyq7J9QAop3sUNEN4fbo4aO5hHz7AJ35VG0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253952; c=relaxed/simple; bh=dzpqP9yppOzeSTqgR5R7a0x7rcylJY76yHgWAl2tHP0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uQtIwitdh6vO//dvcofImLEjmXiwh+R41XB+aqfRsGKUPWbhGvoADH9Nw2yHcxd4JG/2SNM0+zG0TfvjDU1cEkyKzAH+t8QXeirIUQaR7zlmgIPRICkLkt8fm+G48xWVhM2P0HpAWAQoHo7eANP1yvSquKK9M3EPFabV61s1KJo= 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=Lqu1Nu+q; arc=none smtp.client-ip=198.175.65.9 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="Lqu1Nu+q" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253949; x=1815789949; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=dzpqP9yppOzeSTqgR5R7a0x7rcylJY76yHgWAl2tHP0=; b=Lqu1Nu+qNCYPmPA+JibU8+ptYd/RRNKzU9OoDyjDWYlIkvpPfM0X2Bfj Zm5+H6wvVmej9cRmi0LWjSq7AgwtzRfEMaxj4kWSe3+U9zTJa0i7phG59 yq33IUYOqAjkk5+/lvTuGg4uQ5WGnvWcC47sXVDiuGM6jt3+sNNuLd4i6 ojYsbYaf6z441O/cVPfsLL72e426t4v9P1yu9acaEDfirRprGB9lZfmMh sxrc69mXwXysT5Fmbjboz0rjGG60DdCGle8BigPxK3HVK6FMg0KAQibFN vtM8isjQBKjF6ZWh+YyF91PubHufNt3r9wwmjwZEcgzIA/24OoE4dlX5a Q==; X-CSE-ConnectionGUID: 2HcO9TDHTgK+cKFzfrKTEg== X-CSE-MsgGUID: n+pyzjGDReuZl5YqdVbCWw== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720022" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720022" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:05:49 -0700 X-CSE-ConnectionGUID: CA4i0GPYSBON9xUnrkLQPQ== X-CSE-MsgGUID: ba//qIrYTrOsyB0wLFK0lA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952804" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:44 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 05/14] perf c2c: add column entry functions for function view Date: Fri, 17 Jul 2026 10:05:21 +0800 Message-ID: <20260717020530.1645123-6-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 ace7e3f27b55..a9add0ba4cda 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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 A948733D6F9; Fri, 17 Jul 2026 02:05:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253956; cv=none; b=lFSyis9j1/0k9HPWipFA8HOpzjYcU4eSmjoXo9Ff2F0MMTS2wpOzwTzeuy8792MG2g18obfxE6vgPbDYAg/dGOQRZ7CehPX+eWasnXGrxreHFhLvhiR6bfFUepjekSlO3c80ptgPe8etuvQg1utHIxv9ef5gMAgirsM5qRr2cx4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253956; c=relaxed/simple; bh=oyPN9WrRcFZ0FqXaoaYkwU84/LrJt2ctmrX7oqWOoGM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ewCp+wOWfap0p92dwDhazNlNzbLpEWISDqspScoO3Ughz5cZILUSJIm5cnU8wXNODVb2eG4t0U3JaQRNIULE0rGkyznjZIsjUpJNM9iZyeTM9iN/QTPy3UP8bkYJ2kfekbh1B0pCYmy5ZPC1gD8PN04abec4d2nBWd4Wbb39YuE= 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=QH6LsH8f; arc=none smtp.client-ip=198.175.65.9 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="QH6LsH8f" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253954; x=1815789954; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oyPN9WrRcFZ0FqXaoaYkwU84/LrJt2ctmrX7oqWOoGM=; b=QH6LsH8fOq+CGpYzm8iWoLPxIjqkBtdmovfM9tBWkO2tpgWvXcRSnUQM IZtm1PXPqbglrEIaO5EMyFuovs+S4GbY13BASsgF1ljMh3zOLljbiC0md I++629VhZ/auQR3rmWgLH855UG5LSvpT8Pf3rltd83sbM7Piz2h31ReKN UjIi1bmYoqj2G/wRr9PSPfF5qfGOYdTyDLLlEVCBQJ+Ldvs0T2i+40iWn Yw9/l5KgcXFLmzg//MVFqX9YzlSdjNSWZF7iwd3lQhXsSuIreNE+HXQBg Uk/ysthoJZgO+BQP9tTyZ4Lj3fUTuubpU+FTsnBOb94FSdfPoCPzNS5zk A==; X-CSE-ConnectionGUID: oJsEWL22QYSU/k2JhT8kfQ== X-CSE-MsgGUID: j6Aiu4C1TYmC55ZSt/25bQ== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720030" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720030" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:05:53 -0700 X-CSE-ConnectionGUID: DlKJrmLyT3ubOXexMrykkw== X-CSE-MsgGUID: EgV28CCHTbCR7RGwrQbgpA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952818" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:48 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 06/14] perf c2c: add comparison functions for function view sorting Date: Fri, 17 Jul 2026 10:05:22 +0800 Message-ID: <20260717020530.1645123-7-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 a9add0ba4cda..75c0a390c283 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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 97C953438BC; Fri, 17 Jul 2026 02:05:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253961; cv=none; b=b5uOdbHogQ4gk/fCsCVZM/PeguBoNgs6uDj/gvIZZzeNs15pE7+HqdyjPA+wNUVZ8rBR7absIQB1TotsLzZvLMo8vKBF2ZmRdVbtfyqWC+lCLvs7+YfBuGlkxnsbt3tGg8BCjmtE4qCTLN1ZqWLSdfNALTIG35B4uR1jOVMqfhI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253961; c=relaxed/simple; bh=myaAQtkh7el4HmIBnSb3I/kdJvDeQN5g++ph5INYnhc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Rn8sFuhQlHPXVXisaFzfxT3ka3hzbYcB7C05b32O59Y4fwfuLQBPVNByWvOjPUVvC1AeJJoAj3PvpNtX6cscw2mDMIFRK176NEyFhtFV9YKV9etBqY5IebW6JKkJRsy8Ei3i4brFGJXJXqSmr5ERA9UmzZVriBKuKzNeEyW7VI0= 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=dXLHJhOb; arc=none smtp.client-ip=198.175.65.9 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="dXLHJhOb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253958; x=1815789958; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=myaAQtkh7el4HmIBnSb3I/kdJvDeQN5g++ph5INYnhc=; b=dXLHJhOb8il0kpUCNEhUX1G5ZAOTFUi0qC/aNd+O/gxdRDv8LgpkkDQG nHozfaNgerzTtmlwIPvdK7kccFwW9lb6q8Jq+ZP7lbpEqdJBgrKEsC/5+ s9eEfCGqw4kOyP9Ba2a328Sx7a3p90O55vA3iKKA4TgMpD/uoQ7ywMt4D KG2nNzTxFWMNZPBB9z2GlkgHrceDGdX5BV6ABeFz45sK6hvE65mFty1/i avaTvOkHi+q/04BNjL9jrvBcQiqWvjHBe2X20RJOQOoXlazvvVNIRQpbb nf1pCRY5f5mDjq/IBcLTzJg42Gva+afFK0PSKEm3danb1mVm9ko831InJ w==; X-CSE-ConnectionGUID: G/vnLN+tRkuqqvMO0tPXtA== X-CSE-MsgGUID: qpqbbv6ARxyBTbFv8I8BAg== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720037" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720037" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:05:57 -0700 X-CSE-ConnectionGUID: tpk+qgqkQ+WFksCX1MvX6A== X-CSE-MsgGUID: VCa32aPjSgafmpFouCpruA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952831" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:52 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 07/14] perf c2c: add dimension definitions and format creation Date: Fri, 17 Jul 2026 10:05:23 +0800 Message-ID: <20260717020530.1645123-8-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 75c0a390c283..d79d131b1f18 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 c2c_fmt_equal; + fmt->free =3D c2c_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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 7D699332EAD; Fri, 17 Jul 2026 02:06:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253962; cv=none; b=emOezmWDnhGe9aT+RDN3/fszG/G/+3a8ngDzmoosRcZ9e7xZZRX5Xq19bcBorahJmq4sd6vUnRV2r+Ine0VRlbb1z95XVJRiCKWwf+0P9hXq50gw3K3pG65aM5NphWVE6C4PGmJfx6cCLMGQYIE4LUDov22878JfOsK2Btx5WlE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253962; c=relaxed/simple; bh=9Jc05xq51CBwiaQIykAVlRAzMyll9r0HRID+8HHqmD0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Dr7nO7aeRPr383KRB9OgrDLhU2c0bzYzNytJ0BzYMspLbMITZjl4qK4jsr62tgQpLFyArAOmwWEBBJGTPvPkGKlfoUmqTy7Ia/QCk27BZzXNJWevPVpa1BmQNCESxNYJqK6TK5YBrm6NaXaPxeUZ6kMKIEZjXvg/BYMTAJsW8tE= 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=AIrfqnPZ; arc=none smtp.client-ip=198.175.65.9 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="AIrfqnPZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253961; x=1815789961; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9Jc05xq51CBwiaQIykAVlRAzMyll9r0HRID+8HHqmD0=; b=AIrfqnPZlF2FKAaQidUXwULmWm/Hni+pVcoRcFh11oJzAoC5K5CNnqJH NSTaX7vbFozPfeEbR6QknbE97M0G2qEyLfhAaRLnmi4krnL2cQ7VDfD0o FRIQDQyXiqFked8l+p89LcbXuWfPuAcx6Ia5gn2R29GJ6K1qF0IPfMEpx VoVhXkQ6D/Kt2TfqSer6shh7xDAi+KLH3T5FH9m8aQod9QfUI1WxX6DMA HEaPmzyV2yWf1WW0BefHXIRcwzYy4ax2+f1nsU6jX7SnconfNgarsBGwZ Klc8Mqzy8pEzhUOridGvAj7E/P7m8iAd4dNOVIsm13BfC7Fc06FENjvsQ A==; X-CSE-ConnectionGUID: H4dbYNjcR2aab0n6yZ8i9Q== X-CSE-MsgGUID: xVfIxey3Q+6D6I1iJ5dfUg== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720045" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720045" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:06:00 -0700 X-CSE-ConnectionGUID: ce2WxVyFSKOYF+mItLKyuQ== X-CSE-MsgGUID: SyJb3DUmR3us5DJ0zBhIAQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952836" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:05:56 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 08/14] perf c2c: add HPP list parsing for function view histograms Date: Fri, 17 Jul 2026 10:05:24 +0800 Message-ID: <20260717020530.1645123-9-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 | 169 +++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index d79d131b1f18..487f9a68d4a4 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,155 @@ static __maybe_unused struct c2c_fmt *get_function_fo= rmat(const char *name) fmt->equal =3D c2c_fmt_equal; fmt->free =3D c2c_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 ret; + + ret =3D get_function_format(name, &c2c_fmt); + if (ret =3D=3D -ENOMEM) + return ret; + /* The function view only accepts its own dimensions. */ + if (ret =3D=3D -ENOENT) + return -EINVAL; + + /* + * Mark symbol-backed columns so hists__has(hists, sym) is correct. + * Only dim_symbol_view carries a sort_entry (.se); the function + * view's field strings are fixed and always include symbol_view, so + * this single check is sufficient (unlike the user-configurable + * cacheline view, which must also test dim_iaddr). + */ + if (c2c_fmt->dim->se =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 __maybe_unused) +{ + struct c2c_fmt *c2c_fmt; + int ret; + + ret =3D get_function_format(name, &c2c_fmt); + if (ret =3D=3D -ENOMEM) + return ret; + /* The function view only accepts its own dimensions. */ + if (ret =3D=3D -ENOENT) + return -EINVAL; + + /* 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\n", 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: + if (ret) + perf_hpp__reset_output_field(hpp_list); + 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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 8EFED33B6DA; Fri, 17 Jul 2026 02:06:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253966; cv=none; b=tlQQCfyYIU8fzLMbngaPnzuQnwgu6EPV4r+KMLhD3BZgXQI4wXlgZDKJljEu3aLTxcT7U8335CC46lAKcPwOAORDqcaQsFX9VazMx1kt4eUGbdzPf0ej8VsN+JQNhf550jaew0ov6ouW20rP4LRFbW4gkSslEWCGGQflOHNl4r8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253966; c=relaxed/simple; bh=WR6vhOAN34mFlZB0xXYVKXC+lALFiuOnd3nm7t51gvo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lSg52s21sfvivlX8H9MHAeN+uOcrQx0rpcW+1kyzz6ueRmG7kawPSbg7FxtPRviqtbOly7ie/TR/gP5YWEQzzNyzdDJFE+sRAMo9oA2iVKSBHBiZOcTZ5RxSltaqyR4dS/I0+sNs6pYNxlYfY2OBBGTCfVahXhYklW3CPt1H2rU= 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=g9HT5hiD; arc=none smtp.client-ip=198.175.65.9 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="g9HT5hiD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253965; x=1815789965; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WR6vhOAN34mFlZB0xXYVKXC+lALFiuOnd3nm7t51gvo=; b=g9HT5hiDZhJsVfRLhUu8oKd6YYxJFr7d2UL529Tz8fI/3SyNBLE09Q+v rpUmrlBRZBPiDtjxJvc1C+eauahHDQvHPlMqWanscbQEBsyZNGS7QUcRT W5PaBNHyiYXfGPanIkpSi53b+HgIWbZRjmrUYrV8crHW262fVPh8vcO+u 3ZOQjoRX4+D090bAQ/9RCaiXAtGXxJ8VmyyOvv7ZqCMgbxuvOcSHicoLc dFSmvXRr5C+qrMfiIlNbiiGPG37MsvcJKJJzlLdefEiJm7MHizIuLV3H4 SVOpY8oyQDLxYC7VD3DTlLq3Z//OZpKIj8riX2X8I2VxnNsIM2em8ZuVD Q==; X-CSE-ConnectionGUID: Hm0ajqcJRQa0/M1tmA7DHw== X-CSE-MsgGUID: ScphJAatSZOuJVVcjkQFlA== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720055" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720055" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:06:05 -0700 X-CSE-ConnectionGUID: os3VdMGzQdyR7KjGLSnleA== X-CSE-MsgGUID: la7tibrsR0KbbPBu3ZmWhg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952861" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:06:00 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 09/14] perf c2c: add stats merging and memory management helpers Date: Fri, 17 Jul 2026 10:05:25 +0800 Message-ID: <20260717020530.1645123-10-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 487f9a68d4a4..8459a1c82f29 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -664,6 +664,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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 7508633EAED; Fri, 17 Jul 2026 02:06:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253971; cv=none; b=cSbceLWAMytODVG6nP+IK1tIhhmQRJadJhs1tfvEyafcM/R62WT6m/0W6qIrrvzkMgmHfBoBSzKKQmIKpVO6nzAfHDlah+v/nFuiqD6b2WKVjDHsDYwaCM3x5QNazoOFhdPojhjd2U02tQ3xfGnipnM/kD8ANeamkfTm3eJIwFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253971; c=relaxed/simple; bh=SJWDrqqN+96MKIQcfLeA9hKku+NJ+B1SEv4IDZKVraw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TP0zVASq795AroMIOmoC9i2eaait67/RA39RVmb+Y58w2th6zRt9IKjFBSTrCWH4QSXexzJfj5uV/wujEKRuKLNJfzcDDgQwjEYNByWzOOv3O1qWGMJmPPgbzQijUhJsPdZGeZZNBahxwf6//kHqfIoNczp+8dNw8zgT0NRYVjs= 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=h36hvlY2; arc=none smtp.client-ip=198.175.65.9 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="h36hvlY2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253969; x=1815789969; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SJWDrqqN+96MKIQcfLeA9hKku+NJ+B1SEv4IDZKVraw=; b=h36hvlY2nAul+UqPEivpDSHqvfXSm3ToMXbiFb4xluUiRXKSuBML0ITs T0vTT9klHwoYf3WV6YUYPXKeod4Gji/BdzFmXdpg6qjqvAMANYxbx6Jjk 1QPoxeWURmKYQkzy20Ls3P1mJ6Pzyn9gieF7Lnd7Xct7fE2WmMyf03kSy IZ5DihacI2y3B+zLbuAmKcOcpiDr5Paigvh+OjkDyngr2ufngC9tF0uP6 Loh3m+f7AuxNi//HRaWEmkhCLE+edoNWXEcUhfyBwD8TCk9DrRt8PUJBw YpG7FpQwq8zBemfmSvaSYeTipLQ/sN96lAfUhsOLVEpEBYV88fdT5S+iA A==; X-CSE-ConnectionGUID: aN8qcx8qRW+9OJ+M/vCtxA== X-CSE-MsgGUID: GDN15cEXToS2FRTXkUMS7Q== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720063" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720063" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:06:09 -0700 X-CSE-ConnectionGUID: DBbZrA3ORluB10ehYem30A== X-CSE-MsgGUID: d7mi6XmiRK6M0k0mSMsfVQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952877" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:06:04 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 10/14] perf c2c: add hierarchy entry creation and lookup functions Date: Fri, 17 Jul 2026 10:05:26 +0800 Message-ID: <20260717020530.1645123-11-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 8459a1c82f29..34c627876d87 100644 --- a/tools/perf/ui/browsers/c2c-function.c +++ b/tools/perf/ui/browsers/c2c-function.c @@ -817,11 +817,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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 AB6D1349CDF; Fri, 17 Jul 2026 02:06:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253975; cv=none; b=ggR3KOdX5DSJPxiUBaYu+sqlmfxVxtWNBScJvVPI+em1+GDa8s4hUKqn5dbN8qgpnIxbl7jdqozvi0PJH/5Q8lOpYXkX4N92LpEbTWPpepr76PwOdsBB5c5sbZrMgNZjU7mmy3TO80gdbEGvv8NCdLZ+Sy0KCPQiK62a3i4ZrHE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253975; c=relaxed/simple; bh=gpThcGf31Ymc+W8+FJ1Xp2zWfG1Fow8zZuf6NNWV+NM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=agMt6xq9MH96EHMe/q+pb+ezmpSGsjEO4JJ1ymhkyMSmrJbw4z0ltd3L17f8Pb9bRIrZt0Rnp5BpMLCU2yD/rLW+eqjswQnvjHTHbC5mZuwshmdGhMJt2FQJMpBF4QvZYoyaDNC+Meq5hlHSDmnDS8HFiZzDsiYL0X0hD6p5KyM= 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=B8DtwCfc; arc=none smtp.client-ip=198.175.65.9 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="B8DtwCfc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253973; x=1815789973; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gpThcGf31Ymc+W8+FJ1Xp2zWfG1Fow8zZuf6NNWV+NM=; b=B8DtwCfcyRRm60qf8C14WKWo8atoFXUHG10vpGsSEl3IaJYFMMhelt73 eXY8rSJn0s1iWc4HtVKYBALJOejZqym++lR7pUm5mGglwDdt67/hVXOeE JVGbN9ytECf5dws/EGesYQ7pDiCkzblqChFVvoQX37zz6Yl5JLN7xhhce PjCSQF94HzpMpA+3SrqmRVhYrEWvGWJVv/CIiiWEgCujcRxFwXt62fRhf gVj0KQvzdqzlCloU/6uM8Nm+bl01Gh9CsOXESwgWI1QI+WWqmRPLMUNcV rRnJ88qzLnnsKtlnh9H2s1ywaclwSPmx1y74bFiSMxoW8DiCU5bxoCb40 g==; X-CSE-ConnectionGUID: oCGg1RnHTCqqrU6rKyMvcg== X-CSE-MsgGUID: vCSEXjaaRUeZ2eAxDct5/A== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720075" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720075" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:06:13 -0700 X-CSE-ConnectionGUID: blNqnnkrTcS6/9NZN7Dy7w== X-CSE-MsgGUID: v1cP2zTYRUaJMttW20bRxA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952882" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:06:08 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 11/14] perf c2c: add function view hierarchy builder Date: Fri, 17 Jul 2026 10:05:27 +0800 Message-ID: <20260717020530.1645123-12-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 34c627876d87..31f1626559cd 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 @@ -624,7 +637,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, @@ -639,7 +652,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, @@ -690,7 +703,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); @@ -700,7 +713,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; @@ -900,7 +913,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) @@ -962,7 +975,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) @@ -1028,7 +1041,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) { @@ -1069,6 +1082,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_all_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_all_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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 A0CEA33AD9A; Fri, 17 Jul 2026 02:06:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253978; cv=none; b=CpuFsObtL6ZCe/EPFd8FCjdtcTynK5SQj+oPM4q/vtjVDlCkeWLxgA8YIwmcZI8q6mnTENc5rQlNKdNaa1wLxx4t+s/9rFTAmR5LWyQ2GGc+EF2uErri9ObWKvDbDtU4+I+GMaZ5hmeWcOniID5oQJMvsMBtjHuDoZnqPKnvoEY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253978; c=relaxed/simple; bh=yh6XazmLhFMw3Cs/tgHrBl3t7OrSgwaIiTGyi9e5QMQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KZrFCyDaaNDviq2RaPjR1KhMsLb1WtPEWqrRyCcoBYeUyVi4fESrapJe+gQmhPJjjt+BbBYpy93e0D8wm95YTAK5A4tSx3xB1+Az8Bsi56I6Y6bMuCxw9LMx3ifTe5ijHRMohOSGeghTqi4SxlSngZ5//ioeZJuFikKk+qKpy4c= 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=ZO9ZqN3V; arc=none smtp.client-ip=198.175.65.9 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="ZO9ZqN3V" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253977; x=1815789977; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yh6XazmLhFMw3Cs/tgHrBl3t7OrSgwaIiTGyi9e5QMQ=; b=ZO9ZqN3VEmsDKJuCZfWCoyJCTAaY0jGA0HxsQFWbrCErkREn5SLGlnky B8QHBxxvcEPX4q+Kq1FhdXTEGldEHedXSduFVNxeOndwkPzB9zKrhu2Zj 4lXgYO/U3kgD886ilTIhYDweiEQdcXu5qabpx+fGOnAT+fjJaSsY2+3yw zvpaT8bUTaxBHK/KaC6wmW6QiwTKPym5kXzjiEeTNzdWFLpz7lXuE0vOH W4FirVzD9pBEzkzKJbFZ3swDtAw4uYERI0vBbCt4bRCGGGj95Fnj6Ga+W xGKgOjNiELoY42bA/tgDmcRf8M+66NOy2OPVrwpQGh1oheJjxGGcGLPPF A==; X-CSE-ConnectionGUID: ejjUusBaQgSa5tr+ZjST5A== X-CSE-MsgGUID: 5QCOx7dcSjqSFrVJqzGhow== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720084" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720084" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:06:17 -0700 X-CSE-ConnectionGUID: jaGeZ4XeTsy+1g9GHiB1Ug== X-CSE-MsgGUID: zQNoNbLnQAyjAU7Iq5yjLQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952885" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:06:12 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 12/14] perf c2c: add function view browser UI Date: Fri, 17 Jul 2026 10:05:28 +0800 Message-ID: <20260717020530.1645123-13-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 | 157 +++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers= /c2c-function.c index 31f1626559cd..fb6673ab410e 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; @@ -1334,7 +1334,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"; @@ -1408,8 +1408,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"); + 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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 673D4331202; Fri, 17 Jul 2026 02:06:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253982; cv=none; b=OpxCy2e8Ssn5WVh3GuQf4NkOxxKZcBMwiEjx6E8BM/g3QluwzAUftFNJsBjfZe481hTrMD7wzDNpu3C8mRa+4iUJdnRMrqiOkb1temD4PnxoccCDmOjZrtrSny1B5YsETB84hqZYUe0lSvIihgNO5guMrAKud00ENj7XlNAGUAA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253982; c=relaxed/simple; bh=VxumeM2X7wfXjXb2RbnqOV4BcLwA9OBmfvijtV5OWDE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FOBTL1vBxZOFVA59HCwhSAWj57K/mhhnNboCQBxoHBE35sOtN/v50KM1kVesUbKG6459pudblUK72VGD96wxYxJ78+mp8owkI0Uh3SdWVeuCFD+8HFwnOc2SObXuxMJXKovTDD5NpRTMhX+EVpzplRr+I2RMxHAjbYIOFq7lysw= 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=F0jctI0V; arc=none smtp.client-ip=198.175.65.9 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="F0jctI0V" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253981; x=1815789981; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VxumeM2X7wfXjXb2RbnqOV4BcLwA9OBmfvijtV5OWDE=; b=F0jctI0Vta6UhdY9AL4r2m+PjcHTbc9CZKBZTx8MdaiTlhqzMpgyc4uk zCJYTH3j5LX+3KWjbXsHNKudGYB/K9Wq+PHxtgwdOhfhugIpAeLQEdRFJ Mp/r2JFV+eDOqs1S3NR1A66XPM22L4WYiEhFa0iQRzVq/xHc/4XebGbLu pKeNd1bYD2WR5ZHA7oO8ASy8l8f+/uy/6hftmzbFZClFSqLpD9XXHS2V6 Ag8Z9I3rZndaE0gqACsuzCxh9zM3B0MyF2o1S54U60EXDwE8bF65T8XMA BWihHeacLJe6hK2E8Zt4EzJDMIe+B/ySY6mFuCCKShZ7mhreb13sbWDYP g==; X-CSE-ConnectionGUID: kHhTLARhQh2Hl56c9Bj9oA== X-CSE-MsgGUID: IstgLpx5T/ir3gpis2Wd0Q== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720103" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720103" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:06:21 -0700 X-CSE-ConnectionGUID: c53pXVr3QKiPBKTgu8lCzg== X-CSE-MsgGUID: zfcB7oceTZ2Zuzqo6nKQYg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952890" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:06:16 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 13/14] perf c2c: add TAB key to switch to function view Date: Fri, 17 Jul 2026 10:05:29 +0800 Message-ID: <20260717020530.1645123-14-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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 f1dd9d8699cb..23c58eba415a 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 Sat Jul 25 06:09:17 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 65C1832B10B; Fri, 17 Jul 2026 02:06:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253985; cv=none; b=pojqDdIXC0vDB2wI2qwWG0gWcTgG4gY7tVJy0w6xsjR9T5+CmGg72P4grIw+85bo0AWiLWyXjOEt5zMvM7glfBbAflhJZsFI5TZiGeo3NujzIccSLNpyPQ/VPRjo1ZcpgOChnXzLciqq3ukwsCdC9sMBUepWd7LDDpVuGlK/Dh4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784253985; c=relaxed/simple; bh=Mm/vrSGZHFmbT5s4VKo2mi6DurGi7q5CM4ASEQyOr9c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dvK6ZXDbqO2MUw/dGLybsTazfGkouMOYiC65wxtioZl0BqdDfhRN4W9CZsEDQhb1yNLY8hqYXn9zEmAsvym64aMoPlO74K/jTmIa/ZGpi6AzOzKEH7MVv+RR1TFinD925I1hzvhd3oQNHxzUrNZfTfsG7ClXjaDbyp/dF8mpX6A= 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=OeaUhLrm; arc=none smtp.client-ip=198.175.65.9 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="OeaUhLrm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784253985; x=1815789985; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Mm/vrSGZHFmbT5s4VKo2mi6DurGi7q5CM4ASEQyOr9c=; b=OeaUhLrmBjPN6Ikrd/fpWq2hqbhCal913Jg3C505oRfm80SeAT0xcPZh hTeKOWmiGcxAJ3XhSv1x2H8bIA+lV7YHImKkdhYvtzDYXepMksZvTu8yc Ct505y22ugZ9ZRE6XuGOI3OhKwaA9YbR1l+6dd3gfnGSk3GngdTJgijyG ELBNm6qVuukIffaDxG9NytbIWsIqHDGy7ci7/4FQfEssY8M4596LA9PcU 1jZmSxT1jegv6IMrZ2/iczkXLg9ve5k9yde0frU8vqYlu5NROO8+QGLtf AkQLKeZ6X4fzcZVaWQMpapzK7PDAhSg8VgVhts6gDbJ9tcM7w5siTAeIK Q==; X-CSE-ConnectionGUID: SR2rQ5r/RQu3PBWWMPr9rQ== X-CSE-MsgGUID: yssBE7DSQLGPnMwAY1bttw== X-IronPort-AV: E=McAfee;i="6800,10657,11848"; a="107720112" X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="107720112" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2026 19:06:25 -0700 X-CSE-ConnectionGUID: FwVKMJqUS0i2tUOs5CVMQA== X-CSE-MsgGUID: UrPZgMYCSs2ylDsg1ydbQw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,168,1779174000"; d="scan'208";a="279952893" Received: from linux-pnp-gnr-1.sh.intel.com ([10.239.83.186]) by fmviesa002.fm.intel.com with ESMTP; 16 Jul 2026 19:06:20 -0700 From: Jiebin Sun To: namhyung@kernel.org, acme@kernel.org, mingo@redhat.com, peterz@infradead.org Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, james.clark@linaro.org, tianyou.li@intel.com, wangyang.guo@intel.com, dapeng1.mi@linux.intel.com, thomas.falcon@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Jiebin Sun Subject: [PATCH v3 14/14] perf c2c: document function view in perf-c2c man page Date: Fri, 17 Jul 2026 10:05:30 +0800 Message-ID: <20260717020530.1645123-15-jiebin.sun@intel.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260717020530.1645123-1-jiebin.sun@intel.com> References: <20260710084247.3576706-1-jiebin.sun@intel.com> <20260717020530.1645123-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