diff options
Diffstat (limited to 'tools/perf/builtin-c2c.c')
| -rw-r--r-- | tools/perf/builtin-c2c.c | 452 | 
1 files changed, 351 insertions, 101 deletions
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 4898ee57d156..653e13b5037e 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -55,6 +55,8 @@ struct c2c_hists {  struct compute_stats {  	struct stats		 lcl_hitm;  	struct stats		 rmt_hitm; +	struct stats		 lcl_peer; +	struct stats		 rmt_peer;  	struct stats		 load;  }; @@ -113,16 +115,18 @@ struct perf_c2c {  };  enum { -	DISPLAY_LCL, -	DISPLAY_RMT, -	DISPLAY_TOT, +	DISPLAY_LCL_HITM, +	DISPLAY_RMT_HITM, +	DISPLAY_TOT_HITM, +	DISPLAY_SNP_PEER,  	DISPLAY_MAX,  };  static const char *display_str[DISPLAY_MAX] = { -	[DISPLAY_LCL] = "Local", -	[DISPLAY_RMT] = "Remote", -	[DISPLAY_TOT] = "Total", +	[DISPLAY_LCL_HITM] = "Local HITMs", +	[DISPLAY_RMT_HITM] = "Remote HITMs", +	[DISPLAY_TOT_HITM] = "Total HITMs", +	[DISPLAY_SNP_PEER] = "Peer Snoop",  };  static const struct option c2c_options[] = { @@ -154,6 +158,8 @@ static void *c2c_he_zalloc(size_t size)  	init_stats(&c2c_he->cstats.lcl_hitm);  	init_stats(&c2c_he->cstats.rmt_hitm); +	init_stats(&c2c_he->cstats.lcl_peer); +	init_stats(&c2c_he->cstats.rmt_peer);  	init_stats(&c2c_he->cstats.load);  	return &c2c_he->he; @@ -253,6 +259,10 @@ static void compute_stats(struct c2c_hist_entry *c2c_he,  		update_stats(&cstats->rmt_hitm, weight);  	else if (stats->lcl_hitm)  		update_stats(&cstats->lcl_hitm, weight); +	else if (stats->rmt_peer) +		update_stats(&cstats->rmt_peer, weight); +	else if (stats->lcl_peer) +		update_stats(&cstats->lcl_peer, weight);  	else if (stats->load)  		update_stats(&cstats->load, weight);  } @@ -650,6 +660,9 @@ __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused,			\  STAT_FN(rmt_hitm)  STAT_FN(lcl_hitm) +STAT_FN(rmt_peer) +STAT_FN(lcl_peer) +STAT_FN(tot_peer)  STAT_FN(store)  STAT_FN(st_l1hit)  STAT_FN(st_l1miss) @@ -787,7 +800,7 @@ percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,  	return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);  } -static double percent_hitm(struct c2c_hist_entry *c2c_he) +static double percent_costly_snoop(struct c2c_hist_entry *c2c_he)  {  	struct c2c_hists *hists;  	struct c2c_stats *stats; @@ -800,17 +813,22 @@ static double percent_hitm(struct c2c_hist_entry *c2c_he)  	total = &hists->stats;  	switch (c2c.display) { -	case DISPLAY_RMT: +	case DISPLAY_RMT_HITM:  		st  = stats->rmt_hitm;  		tot = total->rmt_hitm;  		break; -	case DISPLAY_LCL: +	case DISPLAY_LCL_HITM:  		st  = stats->lcl_hitm;  		tot = total->lcl_hitm;  		break; -	case DISPLAY_TOT: +	case DISPLAY_TOT_HITM:  		st  = stats->tot_hitm;  		tot = total->tot_hitm; +		break; +	case DISPLAY_SNP_PEER: +		st  = stats->tot_peer; +		tot = total->tot_peer; +		break;  	default:  		break;  	} @@ -827,8 +845,8 @@ static double percent_hitm(struct c2c_hist_entry *c2c_he)  })  static int -percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, -		   struct hist_entry *he) +percent_costly_snoop_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, +			   struct hist_entry *he)  {  	struct c2c_hist_entry *c2c_he;  	int width = c2c_width(fmt, hpp, he->hists); @@ -836,20 +854,20 @@ percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,  	double per;  	c2c_he = container_of(he, struct c2c_hist_entry, he); -	per = percent_hitm(c2c_he); +	per = percent_costly_snoop(c2c_he);  	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));  }  static int -percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, -		   struct hist_entry *he) +percent_costly_snoop_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, +			   struct hist_entry *he)  { -	return percent_color(fmt, hpp, he, percent_hitm); +	return percent_color(fmt, hpp, he, percent_costly_snoop);  }  static int64_t -percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused, -		 struct hist_entry *left, struct hist_entry *right) +percent_costly_snoop_cmp(struct perf_hpp_fmt *fmt __maybe_unused, +			 struct hist_entry *left, struct hist_entry *right)  {  	struct c2c_hist_entry *c2c_left;  	struct c2c_hist_entry *c2c_right; @@ -859,8 +877,8 @@ percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,  	c2c_left  = container_of(left, struct c2c_hist_entry, he);  	c2c_right = container_of(right, struct c2c_hist_entry, he); -	per_left  = percent_hitm(c2c_left); -	per_right = percent_hitm(c2c_right); +	per_left  = percent_costly_snoop(c2c_left); +	per_right = percent_costly_snoop(c2c_right);  	return per_left - per_right;  } @@ -899,6 +917,8 @@ static double percent_ ## __f(struct c2c_hist_entry *c2c_he)			\  PERCENT_FN(rmt_hitm)  PERCENT_FN(lcl_hitm) +PERCENT_FN(rmt_peer) +PERCENT_FN(lcl_peer)  PERCENT_FN(st_l1hit)  PERCENT_FN(st_l1miss)  PERCENT_FN(st_na) @@ -966,6 +986,68 @@ percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,  }  static int +percent_lcl_peer_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, +		       struct hist_entry *he) +{ +	int width = c2c_width(fmt, hpp, he->hists); +	double per = PERCENT(he, lcl_peer); +	char buf[10]; + +	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per)); +} + +static int +percent_lcl_peer_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, +		       struct hist_entry *he) +{ +	return percent_color(fmt, hpp, he, percent_lcl_peer); +} + +static int64_t +percent_lcl_peer_cmp(struct perf_hpp_fmt *fmt __maybe_unused, +		     struct hist_entry *left, struct hist_entry *right) +{ +	double per_left; +	double per_right; + +	per_left  = PERCENT(left, lcl_peer); +	per_right = PERCENT(right, lcl_peer); + +	return per_left - per_right; +} + +static int +percent_rmt_peer_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, +		       struct hist_entry *he) +{ +	int width = c2c_width(fmt, hpp, he->hists); +	double per = PERCENT(he, rmt_peer); +	char buf[10]; + +	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per)); +} + +static int +percent_rmt_peer_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, +		       struct hist_entry *he) +{ +	return percent_color(fmt, hpp, he, percent_rmt_peer); +} + +static int64_t +percent_rmt_peer_cmp(struct perf_hpp_fmt *fmt __maybe_unused, +		     struct hist_entry *left, struct hist_entry *right) +{ +	double per_left; +	double per_right; + +	per_left  = PERCENT(left, rmt_peer); +	per_right = PERCENT(right, rmt_peer); + +	return per_left - per_right; +} + +static int  percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,  			   struct hist_entry *he)  { @@ -1142,18 +1224,22 @@ node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,  			advance_hpp(hpp, ret);  			switch (c2c.display) { -			case DISPLAY_RMT: +			case DISPLAY_RMT_HITM:  				ret = display_metrics(hpp, stats->rmt_hitm,  						      c2c_he->stats.rmt_hitm);  				break; -			case DISPLAY_LCL: +			case DISPLAY_LCL_HITM:  				ret = display_metrics(hpp, stats->lcl_hitm,  						      c2c_he->stats.lcl_hitm);  				break; -			case DISPLAY_TOT: +			case DISPLAY_TOT_HITM:  				ret = display_metrics(hpp, stats->tot_hitm,  						      c2c_he->stats.tot_hitm);  				break; +			case DISPLAY_SNP_PEER: +				ret = display_metrics(hpp, stats->tot_peer, +						      c2c_he->stats.tot_peer); +				break;  			default:  				break;  			} @@ -1213,6 +1299,8 @@ __func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he)	\  MEAN_ENTRY(mean_rmt_entry,  rmt_hitm);  MEAN_ENTRY(mean_lcl_entry,  lcl_hitm);  MEAN_ENTRY(mean_load_entry, load); +MEAN_ENTRY(mean_rmt_peer_entry, rmt_peer); +MEAN_ENTRY(mean_lcl_peer_entry, lcl_peer);  static int  cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, @@ -1360,6 +1448,30 @@ static struct c2c_dimension dim_rmt_hitm = {  	.width		= 7,  }; +static struct c2c_dimension dim_tot_peer = { +	.header		= HEADER_SPAN("------- Load Peer -------", "Total", 2), +	.name		= "tot_peer", +	.cmp		= tot_peer_cmp, +	.entry		= tot_peer_entry, +	.width		= 7, +}; + +static struct c2c_dimension dim_lcl_peer = { +	.header		= HEADER_SPAN_LOW("Local"), +	.name		= "lcl_peer", +	.cmp		= lcl_peer_cmp, +	.entry		= lcl_peer_entry, +	.width		= 7, +}; + +static struct c2c_dimension dim_rmt_peer = { +	.header		= HEADER_SPAN_LOW("Remote"), +	.name		= "rmt_peer", +	.cmp		= rmt_peer_cmp, +	.entry		= rmt_peer_entry, +	.width		= 7, +}; +  static struct c2c_dimension dim_cl_rmt_hitm = {  	.header		= HEADER_SPAN("----- HITM -----", "Rmt", 1),  	.name		= "cl_rmt_hitm", @@ -1376,6 +1488,22 @@ static struct c2c_dimension dim_cl_lcl_hitm = {  	.width		= 7,  }; +static struct c2c_dimension dim_cl_rmt_peer = { +	.header		= HEADER_SPAN("----- Peer -----", "Rmt", 1), +	.name		= "cl_rmt_peer", +	.cmp		= rmt_peer_cmp, +	.entry		= rmt_peer_entry, +	.width		= 7, +}; + +static struct c2c_dimension dim_cl_lcl_peer = { +	.header		= HEADER_SPAN_LOW("Lcl"), +	.name		= "cl_lcl_peer", +	.cmp		= lcl_peer_cmp, +	.entry		= lcl_peer_entry, +	.width		= 7, +}; +  static struct c2c_dimension dim_tot_stores = {  	.header		= HEADER_BOTH("Total", "Stores"),  	.name		= "tot_stores", @@ -1488,17 +1616,18 @@ static struct c2c_dimension dim_tot_loads = {  	.width		= 7,  }; -static struct c2c_header percent_hitm_header[] = { -	[DISPLAY_LCL] = HEADER_BOTH("Lcl", "Hitm"), -	[DISPLAY_RMT] = HEADER_BOTH("Rmt", "Hitm"), -	[DISPLAY_TOT] = HEADER_BOTH("Tot", "Hitm"), +static struct c2c_header percent_costly_snoop_header[] = { +	[DISPLAY_LCL_HITM] = HEADER_BOTH("Lcl", "Hitm"), +	[DISPLAY_RMT_HITM] = HEADER_BOTH("Rmt", "Hitm"), +	[DISPLAY_TOT_HITM] = HEADER_BOTH("Tot", "Hitm"), +	[DISPLAY_SNP_PEER] = HEADER_BOTH("Peer", "Snoop"),  }; -static struct c2c_dimension dim_percent_hitm = { -	.name		= "percent_hitm", -	.cmp		= percent_hitm_cmp, -	.entry		= percent_hitm_entry, -	.color		= percent_hitm_color, +static struct c2c_dimension dim_percent_costly_snoop = { +	.name		= "percent_costly_snoop", +	.cmp		= percent_costly_snoop_cmp, +	.entry		= percent_costly_snoop_entry, +	.color		= percent_costly_snoop_color,  	.width		= 7,  }; @@ -1520,6 +1649,24 @@ static struct c2c_dimension dim_percent_lcl_hitm = {  	.width		= 7,  }; +static struct c2c_dimension dim_percent_rmt_peer = { +	.header		= HEADER_SPAN("-- Peer Snoop --", "Rmt", 1), +	.name		= "percent_rmt_peer", +	.cmp		= percent_rmt_peer_cmp, +	.entry		= percent_rmt_peer_entry, +	.color		= percent_rmt_peer_color, +	.width		= 7, +}; + +static struct c2c_dimension dim_percent_lcl_peer = { +	.header		= HEADER_SPAN_LOW("Lcl"), +	.name		= "percent_lcl_peer", +	.cmp		= percent_lcl_peer_cmp, +	.entry		= percent_lcl_peer_entry, +	.color		= percent_lcl_peer_color, +	.width		= 7, +}; +  static struct c2c_dimension dim_percent_stores_l1hit = {  	.header		= HEADER_SPAN("------- Store Refs ------", "L1 Hit", 2),  	.name		= "percent_stores_l1hit", @@ -1588,12 +1735,6 @@ static struct c2c_dimension dim_dso = {  	.se		= &sort_dso,  }; -static struct c2c_header header_node[3] = { -	HEADER_LOW("Node"), -	HEADER_LOW("Node{cpus %hitms %stores}"), -	HEADER_LOW("Node{cpu list}"), -}; -  static struct c2c_dimension dim_node = {  	.name		= "node",  	.cmp		= empty_cmp, @@ -1625,6 +1766,22 @@ static struct c2c_dimension dim_mean_load = {  	.width		= 8,  }; +static struct c2c_dimension dim_mean_rmt_peer = { +	.header		= HEADER_SPAN("---------- cycles ----------", "rmt peer", 2), +	.name		= "mean_rmt_peer", +	.cmp		= empty_cmp, +	.entry		= mean_rmt_peer_entry, +	.width		= 8, +}; + +static struct c2c_dimension dim_mean_lcl_peer = { +	.header		= HEADER_SPAN_LOW("lcl peer"), +	.name		= "mean_lcl_peer", +	.cmp		= empty_cmp, +	.entry		= mean_lcl_peer_entry, +	.width		= 8, +}; +  static struct c2c_dimension dim_cpucnt = {  	.header		= HEADER_BOTH("cpu", "cnt"),  	.name		= "cpucnt", @@ -1672,8 +1829,13 @@ static struct c2c_dimension *dimensions[] = {  	&dim_tot_hitm,  	&dim_lcl_hitm,  	&dim_rmt_hitm, +	&dim_tot_peer, +	&dim_lcl_peer, +	&dim_rmt_peer,  	&dim_cl_lcl_hitm,  	&dim_cl_rmt_hitm, +	&dim_cl_lcl_peer, +	&dim_cl_rmt_peer,  	&dim_tot_stores,  	&dim_stores_l1hit,  	&dim_stores_l1miss, @@ -1688,9 +1850,11 @@ static struct c2c_dimension *dimensions[] = {  	&dim_ld_rmthit,  	&dim_tot_recs,  	&dim_tot_loads, -	&dim_percent_hitm, +	&dim_percent_costly_snoop,  	&dim_percent_rmt_hitm,  	&dim_percent_lcl_hitm, +	&dim_percent_rmt_peer, +	&dim_percent_lcl_peer,  	&dim_percent_stores_l1hit,  	&dim_percent_stores_l1miss,  	&dim_percent_stores_na, @@ -1703,6 +1867,8 @@ static struct c2c_dimension *dimensions[] = {  	&dim_node,  	&dim_mean_rmt,  	&dim_mean_lcl, +	&dim_mean_rmt_peer, +	&dim_mean_lcl_peer,  	&dim_mean_load,  	&dim_cpucnt,  	&dim_srcline, @@ -1941,18 +2107,22 @@ static bool he__display(struct hist_entry *he, struct c2c_stats *stats)  	c2c_he = container_of(he, struct c2c_hist_entry, he);  	switch (c2c.display) { -	case DISPLAY_LCL: +	case DISPLAY_LCL_HITM:  		he->filtered = filter_display(c2c_he->stats.lcl_hitm,  					      stats->lcl_hitm);  		break; -	case DISPLAY_RMT: +	case DISPLAY_RMT_HITM:  		he->filtered = filter_display(c2c_he->stats.rmt_hitm,  					      stats->rmt_hitm);  		break; -	case DISPLAY_TOT: +	case DISPLAY_TOT_HITM:  		he->filtered = filter_display(c2c_he->stats.tot_hitm,  					      stats->tot_hitm);  		break; +	case DISPLAY_SNP_PEER: +		he->filtered = filter_display(c2c_he->stats.tot_peer, +					      stats->tot_peer); +		break;  	default:  		break;  	} @@ -1972,15 +2142,17 @@ static inline bool is_valid_hist_entry(struct hist_entry *he)  		return true;  	switch (c2c.display) { -	case DISPLAY_LCL: +	case DISPLAY_LCL_HITM:  		has_record = !!c2c_he->stats.lcl_hitm;  		break; -	case DISPLAY_RMT: +	case DISPLAY_RMT_HITM:  		has_record = !!c2c_he->stats.rmt_hitm;  		break; -	case DISPLAY_TOT: +	case DISPLAY_TOT_HITM:  		has_record = !!c2c_he->stats.tot_hitm;  		break; +	case DISPLAY_SNP_PEER: +		has_record = !!c2c_he->stats.tot_peer;  	default:  		break;  	} @@ -2069,9 +2241,33 @@ static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused)  	return 0;  } +static struct c2c_header header_node_0 = HEADER_LOW("Node"); +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 void setup_nodes_header(void)  { -	dim_node.header = header_node[c2c.node_info]; +	switch (c2c.node_info) { +	case 0: +		dim_node.header = header_node_0; +		break; +	case 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; +	case 2: +		dim_node.header = header_node_2; +		break; +	default: +		break; +	} + +	return;  }  static int setup_nodes(struct perf_session *session) @@ -2136,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_PEER(__h) ((__h)->stats.lcl_peer || (__h)->stats.rmt_peer)  static int resort_shared_cl_cb(struct hist_entry *he, void *arg __maybe_unused)  {  	struct c2c_hist_entry *c2c_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_add_stats(&c2c.shared_clines_stats, &c2c_he->stats);  	} @@ -2202,6 +2399,8 @@ static void print_c2c__display_stats(FILE *out)  	fprintf(out, "  Load LLC Misses                   : %10d\n", llc_misses);  	fprintf(out, "  Load access blocked by data       : %10d\n", stats->blk_data);  	fprintf(out, "  Load access blocked by address    : %10d\n", stats->blk_addr); +	fprintf(out, "  Load HIT Local Peer               : %10d\n", stats->lcl_peer); +	fprintf(out, "  Load HIT Remote Peer              : %10d\n", stats->rmt_peer);  	fprintf(out, "  LLC Misses to Local DRAM          : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);  	fprintf(out, "  LLC Misses to Remote DRAM         : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);  	fprintf(out, "  LLC Misses to Remote cache (HIT)  : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.); @@ -2230,6 +2429,7 @@ static void print_shared_cacheline_info(FILE *out)  	fprintf(out, "  L1D hits on shared lines          : %10d\n", stats->ld_l1hit);  	fprintf(out, "  L2D hits on shared lines          : %10d\n", stats->ld_l2hit);  	fprintf(out, "  LLC hits on shared lines          : %10d\n", stats->ld_llchit + stats->lcl_hitm); +	fprintf(out, "  Load hits on peer cache or nodes  : %10d\n", stats->lcl_peer + stats->rmt_peer);  	fprintf(out, "  Locked Access on shared lines     : %10d\n", stats->locks);  	fprintf(out, "  Blocked Access on shared lines    : %10d\n", stats->blk_data + stats->blk_addr);  	fprintf(out, "  Store HITs on shared lines        : %10d\n", stats->store); @@ -2272,13 +2472,22 @@ static void print_pareto(FILE *out)  	int ret;  	const char *cl_output; -	cl_output = "cl_num," -		    "cl_rmt_hitm," -		    "cl_lcl_hitm," -		    "cl_stores_l1hit," -		    "cl_stores_l1miss," -		    "cl_stores_na," -		    "dcacheline"; +	if (c2c.display != DISPLAY_SNP_PEER) +		cl_output = "cl_num," +			    "cl_rmt_hitm," +			    "cl_lcl_hitm," +			    "cl_stores_l1hit," +			    "cl_stores_l1miss," +			    "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);  	ret = hpp_list__parse(&hpp_list, cl_output, NULL); @@ -2314,7 +2523,7 @@ static void print_c2c_info(FILE *out, struct perf_session *session)  		fprintf(out, "%-36s: %s\n", first ? "  Events" : "", evsel__name(evsel));  		first = false;  	} -	fprintf(out, "  Cachelines sort on                : %s HITMs\n", +	fprintf(out, "  Cachelines sort on                : %s\n",  		display_str[c2c.display]);  	fprintf(out, "  Cacheline data grouping           : %s\n", c2c.cl_sort);  } @@ -2471,7 +2680,7 @@ static int perf_c2c_browser__title(struct hist_browser *browser,  {  	scnprintf(bf, size,  		  "Shared Data Cache Line Table     " -		  "(%lu entries, sorted on %s HITMs)", +		  "(%lu entries, sorted on %s)",  		  browser->nr_non_filtered_entries,  		  display_str[c2c.display]);  	return 0; @@ -2585,7 +2794,7 @@ static int ui_quirks(void)  		nodestr = "CL";  	} -	dim_percent_hitm.header = percent_hitm_header[c2c.display]; +	dim_percent_costly_snoop.header = percent_costly_snoop_header[c2c.display];  	/* Fix the zero line for dcacheline column. */  	buf = fill_line("Cacheline", dim_dcacheline.width + @@ -2669,14 +2878,16 @@ static int setup_callchain(struct evlist *evlist)  static int setup_display(const char *str)  { -	const char *display = str ?: "tot"; +	const char *display = str;  	if (!strcmp(display, "tot")) -		c2c.display = DISPLAY_TOT; +		c2c.display = DISPLAY_TOT_HITM;  	else if (!strcmp(display, "rmt")) -		c2c.display = DISPLAY_RMT; +		c2c.display = DISPLAY_RMT_HITM;  	else if (!strcmp(display, "lcl")) -		c2c.display = DISPLAY_LCL; +		c2c.display = DISPLAY_LCL_HITM; +	else if (!strcmp(display, "peer")) +		c2c.display = DISPLAY_SNP_PEER;  	else {  		pr_err("failed: unknown display type: %s\n", str);  		return -1; @@ -2723,10 +2934,12 @@ static int build_cl_output(char *cl_sort, bool no_source)  	}  	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," : "", -		"percent_rmt_hitm," -		"percent_lcl_hitm," +		c2c.display == DISPLAY_SNP_PEER ? "percent_rmt_peer," +						  "percent_lcl_peer," : +						  "percent_rmt_hitm," +						  "percent_lcl_hitm,",  		"percent_stores_l1hit,"  		"percent_stores_l1miss,"  		"percent_stores_na," @@ -2734,8 +2947,10 @@ static int build_cl_output(char *cl_sort, bool no_source)  		add_pid   ? "pid," : "",  		add_tid   ? "tid," : "",  		add_iaddr ? "iaddr," : "", -		"mean_rmt," -		"mean_lcl," +		c2c.display == DISPLAY_SNP_PEER ? "mean_rmt_peer," +						  "mean_lcl_peer," : +						  "mean_rmt," +						  "mean_lcl,",  		"mean_load,"  		"tot_recs,"  		"cpucnt,", @@ -2756,6 +2971,7 @@ err:  static int setup_coalesce(const char *coalesce, bool no_source)  {  	const char *c = coalesce ?: coalesce_default; +	const char *sort_str = NULL;  	if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)  		return -ENOMEM; @@ -2763,12 +2979,16 @@ static int setup_coalesce(const char *coalesce, bool no_source)  	if (build_cl_output(c2c.cl_sort, no_source))  		return -1; -	if (asprintf(&c2c.cl_resort, "offset,%s", -		     c2c.display == DISPLAY_TOT ? -		     "tot_hitm" : -		     c2c.display == DISPLAY_RMT ? -		     "rmt_hitm,lcl_hitm" : -		     "lcl_hitm,rmt_hitm") < 0) +	if (c2c.display == DISPLAY_TOT_HITM) +		sort_str = "tot_hitm"; +	else if (c2c.display == DISPLAY_RMT_HITM) +		sort_str = "rmt_hitm,lcl_hitm"; +	else if (c2c.display == DISPLAY_LCL_HITM) +		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;  	pr_debug("coalesce sort   fields: %s\n", c2c.cl_sort); @@ -2814,7 +3034,7 @@ static int perf_c2c__report(int argc, const char **argv)  			     "print_type,threshold[,print_limit],order,sort_key[,branch],value",  			     callchain_help, &parse_callchain_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",  		   "coalesce fields: pid,tid,iaddr,dso"),  	OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), @@ -2848,27 +3068,39 @@ static int perf_c2c__report(int argc, const char **argv)  	data.path  = input_name;  	data.force = symbol_conf.force; +	session = perf_session__new(&data, &c2c.tool); +	if (IS_ERR(session)) { +		err = PTR_ERR(session); +		pr_debug("Error creating perf session\n"); +		goto out; +	} + +	/* +	 * Use the 'tot' as default display type if user doesn't specify it; +	 * since Arm64 platform doesn't support HITMs flag, use 'peer' as the +	 * default display type. +	 */ +	if (!display) { +		if (!strcmp(perf_env__arch(&session->header.env), "arm64")) +			display = "peer"; +		else +			display = "tot"; +	} +  	err = setup_display(display);  	if (err) -		goto out; +		goto out_session;  	err = setup_coalesce(coalesce, no_source);  	if (err) {  		pr_debug("Failed to initialize hists\n"); -		goto out; +		goto out_session;  	}  	err = c2c_hists__init(&c2c.hists, "dcacheline", 2);  	if (err) {  		pr_debug("Failed to initialize hists\n"); -		goto out; -	} - -	session = perf_session__new(&data, &c2c.tool); -	if (IS_ERR(session)) { -		err = PTR_ERR(session); -		pr_debug("Error creating perf session\n"); -		goto out; +		goto out_session;  	}  	session->itrace_synth_opts = &itrace_synth_opts; @@ -2876,7 +3108,7 @@ static int perf_c2c__report(int argc, const char **argv)  	err = setup_nodes(session);  	if (err) {  		pr_err("Failed setup nodes\n"); -		goto out; +		goto out_session;  	}  	err = mem2node__init(&c2c.mem2node, &session->header.env); @@ -2909,27 +3141,45 @@ static int perf_c2c__report(int argc, const char **argv)  		goto out_mem2node;  	} -	output_str = "cl_idx," -		     "dcacheline," -		     "dcacheline_node," -		     "dcacheline_count," -		     "percent_hitm," -		     "tot_hitm,lcl_hitm,rmt_hitm," -		     "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_SNP_PEER) +		output_str = "cl_idx," +			     "dcacheline," +			     "dcacheline_node," +			     "dcacheline_count," +			     "percent_costly_snoop," +			     "tot_hitm,lcl_hitm,rmt_hitm," +			     "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"; +	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) +	if (c2c.display == DISPLAY_TOT_HITM)  		sort_str = "tot_hitm"; -	else if (c2c.display == DISPLAY_RMT) +	else if (c2c.display == DISPLAY_RMT_HITM)  		sort_str = "rmt_hitm"; -	else if (c2c.display == DISPLAY_LCL) +	else if (c2c.display == DISPLAY_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);  | 
