Commit f37c5d91 authored by Leo Yan's avatar Leo Yan Committed by Arnaldo Carvalho de Melo

perf c2c: Sort on peer snooping for load operations

This patch adds a new option 'peer' so can sort on the cache hit for
peer snooping.

For displaying with option 'peer', the "Shared Data Cache Line Table"
and "Shared Cache Line Distribution Pareto" both sort with the metrics
"tot_peer".

As result, we can get the 'peer' display:

  # perf c2c report -d peer --coalesce tid,pid,iaddr,dso -N --stdio

  =================================================
             Shared Data Cache Line Table
  =================================================
  #
  #        ----------- Cacheline ----------     Peer  ------- Load Peer -------    Total    Total    Total  --------- Stores --------  ----- Core Load Hit -----  - LLC Load Hit --  - RMT Load Hit --  --- Load Dram ----
  # Index             Address  Node  PA cnt    Snoop    Total    Local   Remote  records    Loads   Stores    L1Hit   L1Miss      N/A       FB       L1       L2    LclHit  LclHitm    RmtHit  RmtHitm       Lcl       Rmt
  # .....  ..................  ....  ......  .......  .......  .......  .......  .......  .......  .......  .......  .......  .......  .......  .......  .......  ........  .......  ........  .......  ........  ........
  #
        0      0xaaaac17d6000   N/A       0  100.00%       99       99        0    18851    18851        0        0        0        0        0    18752        0        99        0         0        0         0         0

  =================================================
        Shared Cache Line Distribution Pareto
  =================================================
  #
  #        -- Peer Snoop --  ------- Store Refs ------  --------- Data address ---------                                                  ---------- cycles ----------    Total       cpu                                    Shared
  #   Num      Rmt      Lcl   L1 Hit  L1 Miss      N/A              Offset  Node  PA cnt      Pid                Tid        Code address  rmt peer  lcl peer      load  records       cnt                  Symbol            Object      Source:Line  Node{cpus %peers %stores}
  # .....  .......  .......  .......  .......  .......  ..................  ....  ......  .......  .................  ..................  ........  ........  ........  .......  ........  ......................  ................  ...............  ....
  #
    ----------------------------------------------------------------------
        0        0       99        0        0        0      0xaaaac17d6000
    ----------------------------------------------------------------------
             0.00%    3.03%    0.00%    0.00%    0.00%                0x20   N/A       0     3603     3603:memstress      0xaaaac17c25ac         0       376        41     9314         2  [.] 0x00000000000025ac  memstress         memstress[25ac]   0{ 2 100.0%    n/a}
             0.00%    3.03%    0.00%    0.00%    0.00%                0x20   N/A       0     3603     3606:memstress      0xaaaac17c25ac         0       375        44     9155         1  [.] 0x00000000000025ac  memstress         memstress[25ac]   0{ 1 100.0%    n/a}
             0.00%   48.48%    0.00%    0.00%    0.00%                0x29   N/A       0     3603     3606:memstress      0xaaaac17c3e88         0       180       170       65         1  [.] 0x0000000000003e88  memstress         memstress[3e88]   0{ 1 100.0%    n/a}
             0.00%   45.45%    0.00%    0.00%    0.00%                0x29   N/A       0     3603     3603:memstress      0xaaaac17c3e88         0       180       175       70         2  [.] 0x0000000000003e88  memstress         memstress[3e88]   0{ 2 100.0%    n/a}
Reviewed-by: default avatarAli Saidi <alisaidi@amazon.com>
Signed-off-by: default avatarLeo Yan <leo.yan@linaro.org>
Tested-by: default avatarAli Saidi <alisaidi@amazon.com>
Acked-by: default avatarIan Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: German Gomez <german.gomez@arm.com>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Like Xu <likexu@tencent.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Timothy Hayes <timothy.hayes@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20220811062451.435810-14-leo.yan@linaro.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent faa30dfa
...@@ -118,6 +118,7 @@ enum { ...@@ -118,6 +118,7 @@ enum {
DISPLAY_LCL_HITM, DISPLAY_LCL_HITM,
DISPLAY_RMT_HITM, DISPLAY_RMT_HITM,
DISPLAY_TOT_HITM, DISPLAY_TOT_HITM,
DISPLAY_SNP_PEER,
DISPLAY_MAX, DISPLAY_MAX,
}; };
...@@ -125,6 +126,7 @@ static const char *display_str[DISPLAY_MAX] = { ...@@ -125,6 +126,7 @@ static const char *display_str[DISPLAY_MAX] = {
[DISPLAY_LCL_HITM] = "Local HITMs", [DISPLAY_LCL_HITM] = "Local HITMs",
[DISPLAY_RMT_HITM] = "Remote HITMs", [DISPLAY_RMT_HITM] = "Remote HITMs",
[DISPLAY_TOT_HITM] = "Total HITMs", [DISPLAY_TOT_HITM] = "Total HITMs",
[DISPLAY_SNP_PEER] = "Peer Snoop",
}; };
static const struct option c2c_options[] = { static const struct option c2c_options[] = {
...@@ -822,6 +824,11 @@ static double percent_costly_snoop(struct c2c_hist_entry *c2c_he) ...@@ -822,6 +824,11 @@ static double percent_costly_snoop(struct c2c_hist_entry *c2c_he)
case DISPLAY_TOT_HITM: case DISPLAY_TOT_HITM:
st = stats->tot_hitm; st = stats->tot_hitm;
tot = total->tot_hitm; tot = total->tot_hitm;
break;
case DISPLAY_SNP_PEER:
st = stats->tot_peer;
tot = total->tot_peer;
break;
default: default:
break; break;
} }
...@@ -1229,6 +1236,10 @@ node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, ...@@ -1229,6 +1236,10 @@ node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
ret = display_metrics(hpp, stats->tot_hitm, ret = display_metrics(hpp, stats->tot_hitm,
c2c_he->stats.tot_hitm); c2c_he->stats.tot_hitm);
break; break;
case DISPLAY_SNP_PEER:
ret = display_metrics(hpp, stats->tot_peer,
c2c_he->stats.tot_peer);
break;
default: default:
break; break;
} }
...@@ -1609,6 +1620,7 @@ static struct c2c_header percent_costly_snoop_header[] = { ...@@ -1609,6 +1620,7 @@ static struct c2c_header percent_costly_snoop_header[] = {
[DISPLAY_LCL_HITM] = HEADER_BOTH("Lcl", "Hitm"), [DISPLAY_LCL_HITM] = HEADER_BOTH("Lcl", "Hitm"),
[DISPLAY_RMT_HITM] = HEADER_BOTH("Rmt", "Hitm"), [DISPLAY_RMT_HITM] = HEADER_BOTH("Rmt", "Hitm"),
[DISPLAY_TOT_HITM] = HEADER_BOTH("Tot", "Hitm"), [DISPLAY_TOT_HITM] = HEADER_BOTH("Tot", "Hitm"),
[DISPLAY_SNP_PEER] = HEADER_BOTH("Peer", "Snoop"),
}; };
static struct c2c_dimension dim_percent_costly_snoop = { static struct c2c_dimension dim_percent_costly_snoop = {
...@@ -2107,6 +2119,10 @@ static bool he__display(struct hist_entry *he, struct c2c_stats *stats) ...@@ -2107,6 +2119,10 @@ static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
he->filtered = filter_display(c2c_he->stats.tot_hitm, he->filtered = filter_display(c2c_he->stats.tot_hitm,
stats->tot_hitm); stats->tot_hitm);
break; break;
case DISPLAY_SNP_PEER:
he->filtered = filter_display(c2c_he->stats.tot_peer,
stats->tot_peer);
break;
default: default:
break; break;
} }
...@@ -2135,6 +2151,8 @@ static inline bool is_valid_hist_entry(struct hist_entry *he) ...@@ -2135,6 +2151,8 @@ static inline bool is_valid_hist_entry(struct hist_entry *he)
case DISPLAY_TOT_HITM: case DISPLAY_TOT_HITM:
has_record = !!c2c_he->stats.tot_hitm; has_record = !!c2c_he->stats.tot_hitm;
break; break;
case DISPLAY_SNP_PEER:
has_record = !!c2c_he->stats.tot_peer;
default: default:
break; break;
} }
...@@ -2224,7 +2242,10 @@ static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused) ...@@ -2224,7 +2242,10 @@ static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
} }
static struct c2c_header header_node_0 = HEADER_LOW("Node"); static struct c2c_header header_node_0 = HEADER_LOW("Node");
static struct c2c_header header_node_1 = HEADER_LOW("Node{cpus %hitms %stores}"); static struct c2c_header header_node_1_hitms_stores =
HEADER_LOW("Node{cpus %hitms %stores}");
static struct c2c_header header_node_1_peers_stores =
HEADER_LOW("Node{cpus %peers %stores}");
static struct c2c_header header_node_2 = HEADER_LOW("Node{cpu list}"); static struct c2c_header header_node_2 = HEADER_LOW("Node{cpu list}");
static void setup_nodes_header(void) static void setup_nodes_header(void)
...@@ -2234,7 +2255,10 @@ static void setup_nodes_header(void) ...@@ -2234,7 +2255,10 @@ static void setup_nodes_header(void)
dim_node.header = header_node_0; dim_node.header = header_node_0;
break; break;
case 1: case 1:
dim_node.header = header_node_1; if (c2c.display == DISPLAY_SNP_PEER)
dim_node.header = header_node_1_peers_stores;
else
dim_node.header = header_node_1_hitms_stores;
break; break;
case 2: case 2:
dim_node.header = header_node_2; dim_node.header = header_node_2;
...@@ -2308,13 +2332,14 @@ static int setup_nodes(struct perf_session *session) ...@@ -2308,13 +2332,14 @@ static int setup_nodes(struct perf_session *session)
} }
#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm) #define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
#define HAS_PEER(__h) ((__h)->stats.lcl_peer || (__h)->stats.rmt_peer)
static int resort_shared_cl_cb(struct hist_entry *he, void *arg __maybe_unused) static int resort_shared_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
{ {
struct c2c_hist_entry *c2c_he; struct c2c_hist_entry *c2c_he;
c2c_he = container_of(he, struct c2c_hist_entry, he); c2c_he = container_of(he, struct c2c_hist_entry, he);
if (HAS_HITMS(c2c_he)) { if (HAS_HITMS(c2c_he) || HAS_PEER(c2c_he)) {
c2c.shared_clines++; c2c.shared_clines++;
c2c_add_stats(&c2c.shared_clines_stats, &c2c_he->stats); c2c_add_stats(&c2c.shared_clines_stats, &c2c_he->stats);
} }
...@@ -2447,13 +2472,22 @@ static void print_pareto(FILE *out) ...@@ -2447,13 +2472,22 @@ static void print_pareto(FILE *out)
int ret; int ret;
const char *cl_output; const char *cl_output;
cl_output = "cl_num," if (c2c.display != DISPLAY_SNP_PEER)
"cl_rmt_hitm," cl_output = "cl_num,"
"cl_lcl_hitm," "cl_rmt_hitm,"
"cl_stores_l1hit," "cl_lcl_hitm,"
"cl_stores_l1miss," "cl_stores_l1hit,"
"cl_stores_na," "cl_stores_l1miss,"
"dcacheline"; "cl_stores_na,"
"dcacheline";
else
cl_output = "cl_num,"
"cl_rmt_peer,"
"cl_lcl_peer,"
"cl_stores_l1hit,"
"cl_stores_l1miss,"
"cl_stores_na,"
"dcacheline";
perf_hpp_list__init(&hpp_list); perf_hpp_list__init(&hpp_list);
ret = hpp_list__parse(&hpp_list, cl_output, NULL); ret = hpp_list__parse(&hpp_list, cl_output, NULL);
...@@ -2852,6 +2886,8 @@ static int setup_display(const char *str) ...@@ -2852,6 +2886,8 @@ static int setup_display(const char *str)
c2c.display = DISPLAY_RMT_HITM; c2c.display = DISPLAY_RMT_HITM;
else if (!strcmp(display, "lcl")) else if (!strcmp(display, "lcl"))
c2c.display = DISPLAY_LCL_HITM; c2c.display = DISPLAY_LCL_HITM;
else if (!strcmp(display, "peer"))
c2c.display = DISPLAY_SNP_PEER;
else { else {
pr_err("failed: unknown display type: %s\n", str); pr_err("failed: unknown display type: %s\n", str);
return -1; return -1;
...@@ -2898,10 +2934,12 @@ static int build_cl_output(char *cl_sort, bool no_source) ...@@ -2898,10 +2934,12 @@ static int build_cl_output(char *cl_sort, bool no_source)
} }
if (asprintf(&c2c.cl_output, if (asprintf(&c2c.cl_output,
"%s%s%s%s%s%s%s%s%s%s", "%s%s%s%s%s%s%s%s%s%s%s%s",
c2c.use_stdio ? "cl_num_empty," : "", c2c.use_stdio ? "cl_num_empty," : "",
"percent_rmt_hitm," c2c.display == DISPLAY_SNP_PEER ? "percent_rmt_peer,"
"percent_lcl_hitm," "percent_lcl_peer," :
"percent_rmt_hitm,"
"percent_lcl_hitm,",
"percent_stores_l1hit," "percent_stores_l1hit,"
"percent_stores_l1miss," "percent_stores_l1miss,"
"percent_stores_na," "percent_stores_na,"
...@@ -2909,8 +2947,10 @@ static int build_cl_output(char *cl_sort, bool no_source) ...@@ -2909,8 +2947,10 @@ static int build_cl_output(char *cl_sort, bool no_source)
add_pid ? "pid," : "", add_pid ? "pid," : "",
add_tid ? "tid," : "", add_tid ? "tid," : "",
add_iaddr ? "iaddr," : "", add_iaddr ? "iaddr," : "",
"mean_rmt," c2c.display == DISPLAY_SNP_PEER ? "mean_rmt_peer,"
"mean_lcl," "mean_lcl_peer," :
"mean_rmt,"
"mean_lcl,",
"mean_load," "mean_load,"
"tot_recs," "tot_recs,"
"cpucnt,", "cpucnt,",
...@@ -2931,6 +2971,7 @@ static int build_cl_output(char *cl_sort, bool no_source) ...@@ -2931,6 +2971,7 @@ static int build_cl_output(char *cl_sort, bool no_source)
static int setup_coalesce(const char *coalesce, bool no_source) static int setup_coalesce(const char *coalesce, bool no_source)
{ {
const char *c = coalesce ?: coalesce_default; const char *c = coalesce ?: coalesce_default;
const char *sort_str = NULL;
if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0) if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)
return -ENOMEM; return -ENOMEM;
...@@ -2938,12 +2979,16 @@ static int setup_coalesce(const char *coalesce, bool no_source) ...@@ -2938,12 +2979,16 @@ static int setup_coalesce(const char *coalesce, bool no_source)
if (build_cl_output(c2c.cl_sort, no_source)) if (build_cl_output(c2c.cl_sort, no_source))
return -1; return -1;
if (asprintf(&c2c.cl_resort, "offset,%s", if (c2c.display == DISPLAY_TOT_HITM)
c2c.display == DISPLAY_TOT_HITM ? sort_str = "tot_hitm";
"tot_hitm" : else if (c2c.display == DISPLAY_RMT_HITM)
c2c.display == DISPLAY_RMT_HITM ? sort_str = "rmt_hitm,lcl_hitm";
"rmt_hitm,lcl_hitm" : else if (c2c.display == DISPLAY_LCL_HITM)
"lcl_hitm,rmt_hitm") < 0) sort_str = "lcl_hitm,rmt_hitm";
else if (c2c.display == DISPLAY_SNP_PEER)
sort_str = "tot_peer";
if (asprintf(&c2c.cl_resort, "offset,%s", sort_str) < 0)
return -ENOMEM; return -ENOMEM;
pr_debug("coalesce sort fields: %s\n", c2c.cl_sort); pr_debug("coalesce sort fields: %s\n", c2c.cl_sort);
...@@ -2989,7 +3034,7 @@ static int perf_c2c__report(int argc, const char **argv) ...@@ -2989,7 +3034,7 @@ static int perf_c2c__report(int argc, const char **argv)
"print_type,threshold[,print_limit],order,sort_key[,branch],value", "print_type,threshold[,print_limit],order,sort_key[,branch],value",
callchain_help, &parse_callchain_opt, callchain_help, &parse_callchain_opt,
callchain_default_opt), callchain_default_opt),
OPT_STRING('d', "display", &display, "Switch HITM output type", "lcl,rmt"), OPT_STRING('d', "display", &display, "Switch HITM output type", "tot,lcl,rmt,peer"),
OPT_STRING('c', "coalesce", &coalesce, "coalesce fields", OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
"coalesce fields: pid,tid,iaddr,dso"), "coalesce fields: pid,tid,iaddr,dso"),
OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
...@@ -3084,20 +3129,36 @@ static int perf_c2c__report(int argc, const char **argv) ...@@ -3084,20 +3129,36 @@ static int perf_c2c__report(int argc, const char **argv)
goto out_mem2node; goto out_mem2node;
} }
output_str = "cl_idx," if (c2c.display != DISPLAY_SNP_PEER)
"dcacheline," output_str = "cl_idx,"
"dcacheline_node," "dcacheline,"
"dcacheline_count," "dcacheline_node,"
"percent_costly_snoop," "dcacheline_count,"
"tot_hitm,lcl_hitm,rmt_hitm," "percent_costly_snoop,"
"tot_recs," "tot_hitm,lcl_hitm,rmt_hitm,"
"tot_loads," "tot_recs,"
"tot_stores," "tot_loads,"
"stores_l1hit,stores_l1miss,stores_na," "tot_stores,"
"ld_fbhit,ld_l1hit,ld_l2hit," "stores_l1hit,stores_l1miss,stores_na,"
"ld_lclhit,lcl_hitm," "ld_fbhit,ld_l1hit,ld_l2hit,"
"ld_rmthit,rmt_hitm," "ld_lclhit,lcl_hitm,"
"dram_lcl,dram_rmt"; "ld_rmthit,rmt_hitm,"
"dram_lcl,dram_rmt";
else
output_str = "cl_idx,"
"dcacheline,"
"dcacheline_node,"
"dcacheline_count,"
"percent_costly_snoop,"
"tot_peer,lcl_peer,rmt_peer,"
"tot_recs,"
"tot_loads,"
"tot_stores,"
"stores_l1hit,stores_l1miss,stores_na,"
"ld_fbhit,ld_l1hit,ld_l2hit,"
"ld_lclhit,lcl_hitm,"
"ld_rmthit,rmt_hitm,"
"dram_lcl,dram_rmt";
if (c2c.display == DISPLAY_TOT_HITM) if (c2c.display == DISPLAY_TOT_HITM)
sort_str = "tot_hitm"; sort_str = "tot_hitm";
...@@ -3105,6 +3166,8 @@ static int perf_c2c__report(int argc, const char **argv) ...@@ -3105,6 +3166,8 @@ static int perf_c2c__report(int argc, const char **argv)
sort_str = "rmt_hitm"; sort_str = "rmt_hitm";
else if (c2c.display == DISPLAY_LCL_HITM) else if (c2c.display == DISPLAY_LCL_HITM)
sort_str = "lcl_hitm"; sort_str = "lcl_hitm";
else if (c2c.display == DISPLAY_SNP_PEER)
sort_str = "tot_peer";
c2c_hists__reinit(&c2c.hists, output_str, sort_str); c2c_hists__reinit(&c2c.hists, output_str, sort_str);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment