From nobody Sat Oct 4 08:05:09 2025 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (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 B0A9726462E; Tue, 19 Aug 2025 07:05:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755587124; cv=none; b=WV2YLYyVYsbjObuvmrQ16SC3gk4JM4C+Dx8i7IWHedHuKxOn/Tz+G3uas+QmcPwehj1Qt+CsFcfw88dNIYh4DnDcmJuuL5UoD2nSqd0YVptISIG/dFrv7vG3z6itqSnGY4cntUEdQZx1A+MG5/S9TMopQCyxRV+wkaMEB7mGygY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755587124; c=relaxed/simple; bh=9G9tGGyQmr/MDJge5iaxFeXyY0yzy1HSC4+NdvqVV7g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=S63hjUKtabfYfCwKVVW9tqW0GcOox8jH5k51cAHep2qVltt2SkF0YWvJRwNu120bIAGoZv+Y15ggZCkTxgBHl3SJG65z6a8kpFRfYWUrzC83dVGWwZfIiDazY44Er9K+QH4vp6Z+2LR6RuLC6X/yf3kfM/Rz6EAfTX5TOJTkKx4= 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=llh0+IG2; arc=none smtp.client-ip=192.198.163.19 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="llh0+IG2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1755587122; x=1787123122; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9G9tGGyQmr/MDJge5iaxFeXyY0yzy1HSC4+NdvqVV7g=; b=llh0+IG2Ozio4CxKhU+DZfdPPuRzJ1VEDlIPVCDE4OGd3YN0g7qJ7sSg lXSxDsklnXwaRgndr2wNmgae59GyctnfBXXpC6ST5rxhdWy/VEjI9p+TY qDArSbEQuFoK5y2fGdm7vUzHWoU5S968JImvDFQ6g+z11bRBSTEd+3mlI DYkR1Dg/LfIKEgoKFJx567wJUxmn7plpJhnwhWCWXpjpvL5BENXr/TeJz ni98MMNpYDJILCJcIgZ3w6chX6vZjvcsRmyqcOOZbJfIyTaEoF1q4uce5 V9MpvGdzFH/BHzJnHtpMLeinRHeODKIOZ904FeE5dE0xGO756ovbhZ7oy w==; X-CSE-ConnectionGUID: gwrGBeBzQL2wAgE2Isa0RQ== X-CSE-MsgGUID: zWH8kvX5R86ilEl/aM5aBg== X-IronPort-AV: E=McAfee;i="6800,10657,11526"; a="56849775" X-IronPort-AV: E=Sophos;i="6.17,300,1747724400"; d="scan'208";a="56849775" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Aug 2025 00:05:22 -0700 X-CSE-ConnectionGUID: g/agoKxjQGe5cTnx9hMEEw== X-CSE-MsgGUID: OLBE13eNTWaktTaEGZ7CsA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.17,300,1747724400"; d="scan'208";a="168134505" Received: from linux-pnp-server-27.sh.intel.com ([10.239.147.41]) by fmviesa008.fm.intel.com with ESMTP; 19 Aug 2025 00:05:17 -0700 From: Tianyou Li To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim Cc: Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang , tianyou.li@intel.com, wangyang.guo@intel.com, pan.deng@intel.com, zhiguo.zhou@intel.com, jiebin.sun@intel.com, thomas.falcon@intel.com, dapeng1.mi@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2] perf tools c2c: Add annotation support to perf c2c report Date: Tue, 19 Aug 2025 16:00:14 +0800 Message-ID: <20250819080014.515277-1-tianyou.li@intel.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250801075158.218441-1-tianyou.li@intel.com> References: <20250801075158.218441-1-tianyou.li@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" Perf c2c report currently specified the code address and source:line information in the cacheline browser, while it is lack of annotation support like perf report to directly show the disassembly code for the particular symbol shared that same cacheline. This patches add a key 'a' binding to the cacheline browser which reuse the annotation browser to show the disassembly view for easier analysis of cacheline contentions. By default, the 'TAB' key navigate to the code address where the contentions detected. Signed-off-by: Tianyou Li Reviewed-by: Dapeng Mi Reviewed-by: Thomas Falcon Reviewed-by: Jiebin Sun Reviewed-by: Pan Deng Reviewed-by: Zhiguo Zhou Reviewed-by: Wangyang Guo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-c2c.c | 124 ++++++++++++++++++++++++++++-- tools/perf/ui/browsers/annotate.c | 30 ++++++-- tools/perf/ui/browsers/hists.c | 2 +- tools/perf/util/annotate.c | 2 +- tools/perf/util/annotate.h | 4 +- tools/perf/util/hist.h | 6 +- 7 files changed, 153 insertions(+), 17 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5d57d2913f3d..8c896fbe76b7 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -519,7 +519,7 @@ static void hists__find_annotations(struct hists *hists, /* skip missing symbols */ nd =3D rb_next(nd); } else if (use_browser =3D=3D 1) { - key =3D hist_entry__tui_annotate(he, evsel, NULL); + key =3D hist_entry__tui_annotate(he, evsel, NULL, NO_INITIAL_IP); =20 switch (key) { case -1: diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 9e9ff471ddd1..f753ec50b967 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -45,6 +45,8 @@ #include "pmus.h" #include "string2.h" #include "util/util.h" +#include "util/symbol.h" +#include "util/annotate.h" =20 struct c2c_hists { struct hists hists; @@ -62,6 +64,7 @@ struct compute_stats { =20 struct c2c_hist_entry { struct c2c_hists *hists; + struct evsel *evsel; struct c2c_stats stats; unsigned long *cpuset; unsigned long *nodeset; @@ -225,6 +228,12 @@ he__get_c2c_hists(struct hist_entry *he, return hists; } =20 +static void c2c_he__set_evsel(struct c2c_hist_entry *c2c_he, + struct evsel *evsel) +{ + c2c_he->evsel =3D evsel; +} + static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he, struct perf_sample *sample) { @@ -334,6 +343,7 @@ static int process_sample_event(const struct perf_tool = *tool __maybe_unused, =20 c2c_he__set_cpu(c2c_he, sample); c2c_he__set_node(c2c_he, sample); + c2c_he__set_evsel(c2c_he, evsel); =20 hists__inc_nr_samples(&c2c_hists->hists, he->filtered); ret =3D hist_entry__append_callchain(he, sample); @@ -371,6 +381,7 @@ static int process_sample_event(const struct perf_tool = *tool __maybe_unused, =20 c2c_he__set_cpu(c2c_he, sample); c2c_he__set_node(c2c_he, sample); + c2c_he__set_evsel(c2c_he, evsel); =20 hists__inc_nr_samples(&c2c_hists->hists, he->filtered); ret =3D hist_entry__append_callchain(he, sample); @@ -2606,6 +2617,28 @@ c2c_cacheline_browser__new(struct hists *hists, stru= ct hist_entry *he) return browser; } =20 +static int perf_c2c__toggle_annotation(struct hist_browser *browser) +{ + struct hist_entry *he =3D browser->he_selection; + struct symbol *sym =3D NULL; + struct c2c_hist_entry *c2c_he =3D NULL; + + if (!he) { + ui_browser__help_window(&browser->b, "No entry selected for annotation"); + return 0; + } + sym =3D (&he->ms)->sym; + + if (sym =3D=3D NULL) { + ui_browser__help_window(&browser->b, "Can not annotate, no symbol found"= ); + return 0; + } + + symbol__hists(sym, 0); + c2c_he =3D container_of(he, struct c2c_hist_entry, he); + return hist_entry__tui_annotate(he, c2c_he->evsel, NULL, he->ip); +} + static int perf_c2c__browse_cacheline(struct hist_entry *he) { struct c2c_hist_entry *c2c_he; @@ -2617,6 +2650,7 @@ static int perf_c2c__browse_cacheline(struct hist_ent= ry *he) " ENTER Toggle callchains (if present) \n" " n Toggle Node details info \n" " s Toggle full length of symbol and source line columns \n" + " a Toggle annotation view \n" " q Return back to cacheline list \n"; =20 if (!he) @@ -2651,6 +2685,9 @@ static int perf_c2c__browse_cacheline(struct hist_ent= ry *he) c2c.node_info =3D (c2c.node_info + 1) % 3; setup_nodes_header(); break; + case 'a': + perf_c2c__toggle_annotation(browser); + break; case 'q': goto out; case '?': @@ -2989,6 +3026,11 @@ static int setup_coalesce(const char *coalesce, bool= no_source) return 0; } =20 +static bool perf_c2c__has_annotation(void) +{ + return use_browser =3D=3D 1; +} + static int perf_c2c__report(int argc, const char **argv) { struct itrace_synth_opts itrace_synth_opts =3D { @@ -3006,6 +3048,8 @@ static int perf_c2c__report(int argc, const char **ar= gv) const char *display =3D NULL; const char *coalesce =3D NULL; bool no_source =3D false; + const char *disassembler_style =3D NULL, *objdump_path =3D NULL, *addr2li= ne_path =3D NULL; + const struct option options[] =3D { OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), @@ -3033,6 +3077,12 @@ static int perf_c2c__report(int argc, const char **a= rgv) OPT_BOOLEAN(0, "stitch-lbr", &c2c.stitch_lbr, "Enable LBR callgraph stitching approach"), OPT_BOOLEAN(0, "double-cl", &chk_double_cl, "Detect adjacent cacheline fa= lse sharing"), + OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler = style", + "Specify disassembler style (e.g. -M intel for intel syntax)"), + OPT_STRING(0, "objdump", &objdump_path, "path", + "objdump binary to use for disassembly and annotations"), + OPT_STRING(0, "addr2line", &addr2line_path, "path", + "addr2line binary to use for line numbers"), OPT_PARENT(c2c_options), OPT_END() }; @@ -3040,6 +3090,12 @@ static int perf_c2c__report(int argc, const char **a= rgv) const char *output_str, *sort_str =3D NULL; struct perf_env *env; =20 + annotation_options__init(); + + err =3D hists__init(); + if (err < 0) + goto out; + argc =3D parse_options(argc, argv, options, report_c2c_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (argc) @@ -3052,6 +3108,36 @@ static int perf_c2c__report(int argc, const char **a= rgv) if (c2c.stats_only) c2c.use_stdio =3D true; =20 + /** + * Annotation related options + * disassembler_style, objdump_path, addr2line_path + * are set in the c2c_options, so we can use them here. + */ + if (disassembler_style) { + annotate_opts.disassembler_style =3D strdup(disassembler_style); + if (!annotate_opts.disassembler_style) { + err =3D -ENOMEM; + pr_err("Failed to allocate memory for annotation options\n"); + goto out; + } + } + if (objdump_path) { + annotate_opts.objdump_path =3D strdup(objdump_path); + if (!annotate_opts.objdump_path) { + err =3D -ENOMEM; + pr_err("Failed to allocate memory for annotation options\n"); + goto out; + } + } + if (addr2line_path) { + symbol_conf.addr2line_path =3D strdup(addr2line_path); + if (!symbol_conf.addr2line_path) { + err =3D -ENOMEM; + pr_err("Failed to allocate memory for annotation options\n"); + goto out; + } + } + err =3D symbol__validate_sym_arguments(); if (err) goto out; @@ -3126,6 +3212,38 @@ static int perf_c2c__report(int argc, const char **a= rgv) if (err) goto out_mem2node; =20 + if (c2c.use_stdio) + use_browser =3D 0; + else + use_browser =3D 1; + + /* + * Only in the TUI browser we are doing integrated annotation, + * so don't allocate extra space that won't be used in the stdio + * implementation. + */ + if (perf_c2c__has_annotation()) { + int ret =3D symbol__annotation_init(); + + if (ret < 0) + goto out_mem2node; + /* + * For searching by name on the "Browse map details". + * providing it only in verbose mode not to bloat too + * much struct symbol. + */ + if (verbose > 0) { + /* + * XXX: Need to provide a less kludgy way to ask for + * more space per symbol, the u32 is for the index on + * the ui browser. + * See symbol__browser_index. + */ + symbol_conf.priv_size +=3D sizeof(u32); + } + annotation_config__init(); + } + if (symbol__init(env) < 0) goto out_mem2node; =20 @@ -3135,11 +3253,6 @@ static int perf_c2c__report(int argc, const char **a= rgv) goto out_mem2node; } =20 - if (c2c.use_stdio) - use_browser =3D 0; - else - use_browser =3D 1; - setup_browser(false); =20 err =3D perf_session__process_events(session); @@ -3210,6 +3323,7 @@ static int perf_c2c__report(int argc, const char **ar= gv) out_session: perf_session__delete(session); out: + annotation_options__exit(); return err; } =20 diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/ann= otate.c index 183902dac042..7eb659c76b53 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -557,7 +557,7 @@ static bool annotate_browser__callq(struct annotate_bro= wser *browser, target_ms.map =3D ms->map; target_ms.sym =3D dl->ops.target.sym; annotation__unlock(notes); - symbol__tui_annotate(&target_ms, evsel, hbt); + symbol__tui_annotate(&target_ms, evsel, hbt, NO_INITIAL_IP); sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_t= ype); ui_browser__show_title(&browser->b, title); return true; @@ -814,6 +814,11 @@ static int annotate_browser__run(struct annotate_brows= er *browser, =20 annotate_browser__calc_percent(browser, evsel); =20 + if (browser->curr_hot =3D=3D NULL && browser->selection) { + disasm_rb_tree__insert(browser, browser->selection); + browser->curr_hot =3D rb_last(&browser->entries); + } + if (browser->curr_hot) { annotate_browser__set_rb_top(browser, browser->curr_hot); browser->b.navkeypressed =3D false; @@ -1033,27 +1038,28 @@ static int annotate_browser__run(struct annotate_br= owser *browser, } =20 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt) + struct hist_browser_timer *hbt, u64 init_ip) { - return symbol__tui_annotate(ms, evsel, hbt); + return symbol__tui_annotate(ms, evsel, hbt, init_ip); } =20 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, - struct hist_browser_timer *hbt) + struct hist_browser_timer *hbt, u64 init_ip) { /* reset abort key so that it can get Ctrl-C as a key */ SLang_reset_tty(); SLang_init_tty(0, 0, 0); SLtty_set_suspend_state(true); =20 - return map_symbol__tui_annotate(&he->ms, evsel, hbt); + return map_symbol__tui_annotate(&he->ms, evsel, hbt, init_ip); } =20 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt) + struct hist_browser_timer *hbt, u64 init_ip) { struct symbol *sym =3D ms->sym; struct annotation *notes =3D symbol__annotation(sym); + struct disasm_line *dl =3D NULL; struct annotate_browser browser =3D { .b =3D { .refresh =3D annotate_browser__refresh, @@ -1093,6 +1099,18 @@ int symbol__tui_annotate(struct map_symbol *ms, stru= ct evsel *evsel, } } =20 + /* + * If init_ip is set, it means that there should be a line + * intentionally selected, not based on the percentages + * which caculated by the event sampling. In this case, we + * convey this information into the browser selection, where + * the selection in other cases should be empty. + */ + if (init_ip !=3D NO_INITIAL_IP) { + dl =3D find_disasm_line(sym, init_ip, false); + browser.selection =3D &dl->al; + } + ui_helpline__push("Press ESC to exit"); =20 browser.b.width =3D notes->src->widths.max_line_len; diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index d9d3fb44477a..eec1b5c12a28 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2484,7 +2484,7 @@ do_annotate(struct hist_browser *browser, struct popu= p_action *act) else evsel =3D hists_to_evsel(browser->hists); =20 - err =3D map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); + err =3D map_symbol__tui_annotate(&act->ms, evsel, browser->hbt, NO_INITIA= L_IP); he =3D hist_browser__selected_entry(browser); /* * offer option to annotate the other branch source or target diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0dd475a744b6..682100196134 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2544,7 +2544,7 @@ int annotate_get_insn_location(struct arch *arch, str= uct disasm_line *dl, return 0; } =20 -static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, +struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, bool allow_update) { struct disasm_line *dl; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8b5131d257b0..c4c897745698 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -170,6 +170,8 @@ static inline struct disasm_line *disasm_line(struct an= notation_line *al) return al ? container_of(al, struct disasm_line, al) : NULL; } =20 +struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, + bool allow_update); /* * Is this offset in the same function as the line it is used? * asm functions jump to other functions, for instance. @@ -473,7 +475,7 @@ int hist_entry__tty_annotate2(struct hist_entry *he, st= ruct evsel *evsel); =20 #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt); + struct hist_browser_timer *hbt, u64 init_ip); #else static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unuse= d, struct evsel *evsel __maybe_unused, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 70438d03ca9c..aca1e3151bcc 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -713,11 +713,13 @@ struct block_hist { #include "../ui/keysyms.h" void attr_to_script(char *buf, struct perf_event_attr *attr); =20 +#define NO_INITIAL_IP 0 + int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt); + struct hist_browser_timer *hbt, u64 init_ip); =20 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, - struct hist_browser_timer *hbt); + struct hist_browser_timer *hbt, u64 init_ip); =20 int evlist__tui_browse_hists(struct evlist *evlist, const char *help, stru= ct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, bool warn_lost_event); --=20 2.47.1