xref: /linux/tools/perf/builtin-c2c.c (revision d5312a7ef79f5de574bce7b140ea1e48ce7e9262)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This is rewrite of original c2c tool introduced in here:
4  *   http://lwn.net/Articles/588866/
5  *
6  * The original tool was changed to fit in current perf state.
7  *
8  * Original authors:
9  *   Don Zickus <dzickus@redhat.com>
10  *   Dick Fowles <fowles@inreach.com>
11  *   Joe Mario <jmario@redhat.com>
12  */
13 #include <errno.h>
14 #include <inttypes.h>
15 
16 #include <asm/bug.h>
17 #include <linux/compiler.h>
18 #include <linux/err.h>
19 #include <linux/kernel.h>
20 #include <linux/stringify.h>
21 #include <linux/zalloc.h>
22 #include <sys/param.h>
23 
24 #include <dwarf-regs.h>
25 #include <perf/cpumap.h>
26 #include <subcmd/pager.h>
27 #include <subcmd/parse-options.h>
28 
29 #include "builtin.h"
30 #include "cacheline.h"
31 #include "data.h"
32 #include "debug.h"
33 #include "event.h"
34 #include "evlist.h"
35 #include "evsel.h"
36 #include "hist.h"
37 #include "map_symbol.h"
38 #include "mem-events.h"
39 #include "mem-info.h"
40 #include "mem2node.h"
41 #include "pmus.h"
42 #include "session.h"
43 #include "sort.h"
44 #include "string2.h"
45 #include "symbol.h"
46 #include "thread.h"
47 #include "tool.h"
48 #include "ui/browsers/hists.h"
49 #include "ui/progress.h"
50 #include "ui/ui.h"
51 #include "util/annotate.h"
52 #include "util/symbol.h"
53 #include "util/util.h"
54 
55 struct c2c_hists {
56 	struct hists		hists;
57 	struct perf_hpp_list	list;
58 	struct c2c_stats	stats;
59 };
60 
61 struct compute_stats {
62 	struct stats		 lcl_hitm;
63 	struct stats		 rmt_hitm;
64 	struct stats		 lcl_peer;
65 	struct stats		 rmt_peer;
66 	struct stats		 load;
67 };
68 
69 struct c2c_hist_entry {
70 	struct c2c_hists	*hists;
71 	struct evsel		*evsel;
72 	struct c2c_stats	 stats;
73 	unsigned long		*cpuset;
74 	unsigned long		*nodeset;
75 	struct c2c_stats	*node_stats;
76 	unsigned int		 cacheline_idx;
77 
78 	struct compute_stats	 cstats;
79 
80 	unsigned long		 paddr;
81 	unsigned long		 paddr_cnt;
82 	bool			 paddr_zero;
83 	char			*nodestr;
84 
85 	/*
86 	 * must be at the end,
87 	 * because of its callchain dynamic entry
88 	 */
89 	struct hist_entry	he;
90 };
91 
92 static char const *coalesce_default = "iaddr";
93 
94 struct perf_c2c {
95 	struct perf_tool	tool;
96 	struct c2c_hists	hists;
97 	struct mem2node		mem2node;
98 
99 	unsigned long		**nodes;
100 	int			 nodes_cnt;
101 	int			 cpus_cnt;
102 	int			*cpu2node;
103 	int			 node_info;
104 
105 	bool			 show_src;
106 	bool			 show_all;
107 	bool			 use_stdio;
108 	bool			 stats_only;
109 	bool			 symbol_full;
110 	bool			 stitch_lbr;
111 
112 	/* Shared cache line stats */
113 	struct c2c_stats	shared_clines_stats;
114 	int			shared_clines;
115 
116 	int			 display;
117 
118 	const char		*coalesce;
119 	char			*cl_sort;
120 	char			*cl_resort;
121 	char			*cl_output;
122 };
123 
124 enum {
125 	DISPLAY_LCL_HITM,
126 	DISPLAY_RMT_HITM,
127 	DISPLAY_TOT_HITM,
128 	DISPLAY_SNP_PEER,
129 	DISPLAY_MAX,
130 };
131 
132 static const char *display_str[DISPLAY_MAX] = {
133 	[DISPLAY_LCL_HITM] = "Local HITMs",
134 	[DISPLAY_RMT_HITM] = "Remote HITMs",
135 	[DISPLAY_TOT_HITM] = "Total HITMs",
136 	[DISPLAY_SNP_PEER] = "Peer Snoop",
137 };
138 
139 static const struct option c2c_options[] = {
140 	OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),
141 	OPT_END()
142 };
143 
144 static struct perf_c2c c2c;
145 
146 static void *c2c_he_zalloc(size_t size)
147 {
148 	struct c2c_hist_entry *c2c_he;
149 
150 	c2c_he = zalloc(size + sizeof(*c2c_he));
151 	if (!c2c_he)
152 		return NULL;
153 
154 	c2c_he->cpuset = bitmap_zalloc(c2c.cpus_cnt);
155 	if (!c2c_he->cpuset)
156 		goto out_free;
157 
158 	c2c_he->nodeset = bitmap_zalloc(c2c.nodes_cnt);
159 	if (!c2c_he->nodeset)
160 		goto out_free;
161 
162 	c2c_he->node_stats = calloc(c2c.nodes_cnt, sizeof(*c2c_he->node_stats));
163 	if (!c2c_he->node_stats)
164 		goto out_free;
165 
166 	init_stats(&c2c_he->cstats.lcl_hitm);
167 	init_stats(&c2c_he->cstats.rmt_hitm);
168 	init_stats(&c2c_he->cstats.lcl_peer);
169 	init_stats(&c2c_he->cstats.rmt_peer);
170 	init_stats(&c2c_he->cstats.load);
171 
172 	return &c2c_he->he;
173 
174 out_free:
175 	zfree(&c2c_he->nodeset);
176 	zfree(&c2c_he->cpuset);
177 	free(c2c_he);
178 	return NULL;
179 }
180 
181 static void c2c_he_free(void *he)
182 {
183 	struct c2c_hist_entry *c2c_he;
184 
185 	c2c_he = container_of(he, struct c2c_hist_entry, he);
186 	if (c2c_he->hists) {
187 		hists__delete_entries(&c2c_he->hists->hists);
188 		zfree(&c2c_he->hists);
189 	}
190 
191 	zfree(&c2c_he->cpuset);
192 	zfree(&c2c_he->nodeset);
193 	zfree(&c2c_he->nodestr);
194 	zfree(&c2c_he->node_stats);
195 	free(c2c_he);
196 }
197 
198 static struct hist_entry_ops c2c_entry_ops = {
199 	.new	= c2c_he_zalloc,
200 	.free	= c2c_he_free,
201 };
202 
203 static int c2c_hists__init(struct c2c_hists *hists,
204 			   const char *sort,
205 			   int nr_header_lines,
206 			   struct perf_env *env);
207 
208 static struct c2c_hists*
209 he__get_c2c_hists(struct hist_entry *he,
210 		  const char *sort,
211 		  int nr_header_lines,
212 		  struct perf_env *env)
213 {
214 	struct c2c_hist_entry *c2c_he;
215 	struct c2c_hists *hists;
216 	int ret;
217 
218 	c2c_he = container_of(he, struct c2c_hist_entry, he);
219 	if (c2c_he->hists)
220 		return c2c_he->hists;
221 
222 	hists = c2c_he->hists = zalloc(sizeof(*hists));
223 	if (!hists)
224 		return NULL;
225 
226 	ret = c2c_hists__init(hists, sort, nr_header_lines, env);
227 	if (ret) {
228 		c2c_he->hists = NULL;
229 		free(hists);
230 		return NULL;
231 	}
232 
233 	return hists;
234 }
235 
236 static void c2c_he__set_evsel(struct c2c_hist_entry *c2c_he,
237 				struct evsel *evsel)
238 {
239 	c2c_he->evsel = evsel;
240 }
241 
242 static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
243 			    struct perf_sample *sample)
244 {
245 	if (WARN_ONCE(sample->cpu == (unsigned int) -1,
246 		      "WARNING: no sample cpu value"))
247 		return;
248 
249 	/* cpuset bitmap has c2c.cpus_cnt bits from env->nr_cpus_avail */
250 	if (sample->cpu >= (unsigned int)c2c.cpus_cnt)
251 		return;
252 
253 	__set_bit(sample->cpu, c2c_he->cpuset);
254 }
255 
256 static void c2c_he__set_node(struct c2c_hist_entry *c2c_he,
257 			     struct perf_sample *sample)
258 {
259 	int node;
260 
261 	if (!sample->phys_addr) {
262 		c2c_he->paddr_zero = true;
263 		return;
264 	}
265 
266 	node = mem2node__node(&c2c.mem2node, sample->phys_addr);
267 	if (WARN_ONCE(node < 0, "WARNING: failed to find node\n"))
268 		return;
269 
270 	/* nodeset bitmap has c2c.nodes_cnt bits from env->nr_numa_nodes */
271 	if (node >= c2c.nodes_cnt)
272 		return;
273 
274 	__set_bit(node, c2c_he->nodeset);
275 
276 	if (c2c_he->paddr != sample->phys_addr) {
277 		c2c_he->paddr_cnt++;
278 		c2c_he->paddr = sample->phys_addr;
279 	}
280 }
281 
282 static void compute_stats(struct c2c_hist_entry *c2c_he,
283 			  struct c2c_stats *stats,
284 			  u64 weight)
285 {
286 	struct compute_stats *cstats = &c2c_he->cstats;
287 
288 	if (stats->rmt_hitm)
289 		update_stats(&cstats->rmt_hitm, weight);
290 	else if (stats->lcl_hitm)
291 		update_stats(&cstats->lcl_hitm, weight);
292 	else if (stats->rmt_peer)
293 		update_stats(&cstats->rmt_peer, weight);
294 	else if (stats->lcl_peer)
295 		update_stats(&cstats->lcl_peer, weight);
296 	else if (stats->load)
297 		update_stats(&cstats->load, weight);
298 }
299 
300 /*
301  * Return true if annotation is possible. When list is NULL,
302  * it means that we are called at the c2c_browser level,
303  * in that case we allow annotation to be initialized. When list
304  * is non-NULL, it means that we are called at the cacheline_browser
305  * level, in that case we allow annotation only if use_browser
306  * is set and symbol information is available.
307  */
308 static bool perf_c2c__has_annotation(struct perf_hpp_list *list)
309 {
310 	if (use_browser != 1)
311 		return false;
312 	return !list || list->sym;
313 }
314 
315 static void perf_c2c__evsel_hists_inc_stats(struct evsel *evsel,
316 					    struct hist_entry *he,
317 					    struct perf_sample *sample)
318 {
319 	struct hists *evsel_hists = evsel__hists(evsel);
320 
321 	hists__inc_nr_samples(evsel_hists, he->filtered);
322 	evsel_hists->stats.total_period += sample->period;
323 	if (!he->filtered)
324 		evsel_hists->stats.total_non_filtered_period += sample->period;
325 }
326 
327 static int process_sample_event(const struct perf_tool *tool __maybe_unused,
328 				union perf_event *event,
329 				struct perf_sample *sample,
330 				struct machine *machine)
331 {
332 	struct evsel *evsel = sample->evsel;
333 	struct c2c_hists *c2c_hists = &c2c.hists;
334 	struct c2c_hist_entry *c2c_he;
335 	struct c2c_stats stats = { .nr_entries = 0, };
336 	struct hist_entry *he;
337 	struct addr_location al;
338 	struct mem_info *mi = NULL;
339 	struct callchain_cursor *cursor;
340 	int ret;
341 
342 	addr_location__init(&al);
343 	if (machine__resolve(machine, &al, sample) < 0) {
344 		pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
345 			 perf_event__name(event->header.type), event->header.type,
346 			 sample->file_offset);
347 		ret = -1;
348 		goto out;
349 	}
350 
351 	if (c2c.stitch_lbr)
352 		thread__set_lbr_stitch_enable(al.thread, true);
353 
354 	cursor = get_tls_callchain_cursor();
355 	ret = sample__resolve_callchain(sample, cursor, NULL,
356 					&al, sysctl_perf_event_max_stack);
357 	if (ret)
358 		goto out;
359 
360 	mi = sample__resolve_mem(sample, &al);
361 	if (mi == NULL) {
362 		ret = -ENOMEM;
363 		goto out;
364 	}
365 
366 	c2c_decode_stats(&stats, mi);
367 
368 	he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
369 				  &al, NULL, NULL, mi, NULL,
370 				  sample, true);
371 	if (he == NULL) {
372 		ret = -ENOMEM;
373 		goto out;
374 	}
375 
376 	c2c_he = container_of(he, struct c2c_hist_entry, he);
377 	c2c_add_stats(&c2c_he->stats, &stats);
378 	c2c_add_stats(&c2c_hists->stats, &stats);
379 
380 	c2c_he__set_cpu(c2c_he, sample);
381 	c2c_he__set_node(c2c_he, sample);
382 	c2c_he__set_evsel(c2c_he, evsel);
383 
384 	hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
385 
386 	if (perf_c2c__has_annotation(NULL)) {
387 		perf_c2c__evsel_hists_inc_stats(evsel, he, sample);
388 		addr_map_symbol__inc_samples(mem_info__iaddr(mi), sample);
389 	}
390 
391 	ret = hist_entry__append_callchain(he, sample);
392 
393 	if (!ret) {
394 		/*
395 		 * There's already been warning about missing
396 		 * sample's cpu value. Let's account all to
397 		 * node 0 in this case, without any further
398 		 * warning.
399 		 *
400 		 * Doing node stats only for single callchain data.
401 		 */
402 		int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
403 		int node;
404 
405 		/* cpu2node[] has c2c.cpus_cnt entries; large u32 wraps signed negative */
406 		if (cpu < 0 || cpu >= c2c.cpus_cnt)
407 			cpu = 0;
408 		node = c2c.cpu2node[cpu];
409 
410 		c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2, machine->env);
411 		if (!c2c_hists) {
412 			ret = -ENOMEM;
413 			goto out;
414 		}
415 
416 		he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
417 					  &al, NULL, NULL, mi, NULL,
418 					  sample, true);
419 		if (he == NULL) {
420 			ret = -ENOMEM;
421 			goto out;
422 		}
423 
424 		c2c_he = container_of(he, struct c2c_hist_entry, he);
425 		c2c_add_stats(&c2c_he->stats, &stats);
426 		c2c_add_stats(&c2c_hists->stats, &stats);
427 		/* node_stats[] has c2c.nodes_cnt entries */
428 		if (node >= 0 && node < c2c.nodes_cnt)
429 			c2c_add_stats(&c2c_he->node_stats[node], &stats);
430 
431 		compute_stats(c2c_he, &stats, sample->weight);
432 
433 		c2c_he__set_cpu(c2c_he, sample);
434 		c2c_he__set_node(c2c_he, sample);
435 		c2c_he__set_evsel(c2c_he, evsel);
436 
437 		hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
438 		ret = hist_entry__append_callchain(he, sample);
439 	}
440 
441 out:
442 	mem_info__put(mi);
443 	addr_location__exit(&al);
444 	return ret;
445 }
446 
447 static const char * const c2c_usage[] = {
448 	"perf c2c {record|report}",
449 	NULL
450 };
451 
452 static const char * const __usage_report[] = {
453 	"perf c2c report",
454 	NULL
455 };
456 
457 static const char * const *report_c2c_usage = __usage_report;
458 
459 #define C2C_HEADER_MAX 2
460 
461 struct c2c_header {
462 	struct {
463 		const char *text;
464 		int	    span;
465 	} line[C2C_HEADER_MAX];
466 };
467 
468 struct c2c_dimension {
469 	struct c2c_header	 header;
470 	const char		*name;
471 	int			 width;
472 	struct sort_entry	*se;
473 
474 	int64_t (*cmp)(struct perf_hpp_fmt *fmt,
475 		       struct hist_entry *, struct hist_entry *);
476 	int   (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
477 		       struct hist_entry *he);
478 	int   (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
479 		       struct hist_entry *he);
480 };
481 
482 struct c2c_fmt {
483 	struct perf_hpp_fmt	 fmt;
484 	struct c2c_dimension	*dim;
485 };
486 
487 #define SYMBOL_WIDTH 30
488 
489 static struct c2c_dimension dim_symbol;
490 static struct c2c_dimension dim_srcline;
491 
492 static int symbol_width(struct hists *hists, struct sort_entry *se)
493 {
494 	int width = hists__col_len(hists, se->se_width_idx);
495 
496 	if (!c2c.symbol_full)
497 		width = MIN(width, SYMBOL_WIDTH);
498 
499 	return width;
500 }
501 
502 static int c2c_width(struct perf_hpp_fmt *fmt,
503 		     struct perf_hpp *hpp __maybe_unused,
504 		     struct hists *hists)
505 {
506 	struct c2c_fmt *c2c_fmt;
507 	struct c2c_dimension *dim;
508 
509 	c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
510 	dim = c2c_fmt->dim;
511 
512 	if (dim == &dim_symbol || dim == &dim_srcline)
513 		return symbol_width(hists, dim->se);
514 
515 	return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
516 			 c2c_fmt->dim->width;
517 }
518 
519 static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
520 		      struct hists *hists, int line, int *span)
521 {
522 	struct perf_hpp_list *hpp_list = hists->hpp_list;
523 	struct c2c_fmt *c2c_fmt;
524 	struct c2c_dimension *dim;
525 	const char *text = NULL;
526 	int width = c2c_width(fmt, hpp, hists);
527 
528 	c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
529 	dim = c2c_fmt->dim;
530 
531 	if (dim->se) {
532 		text = dim->header.line[line].text;
533 		/* Use the last line from sort_entry if not defined. */
534 		if (!text && (line == hpp_list->nr_header_lines - 1))
535 			text = dim->se->se_header;
536 	} else {
537 		text = dim->header.line[line].text;
538 
539 		if (*span) {
540 			(*span)--;
541 			return 0;
542 		} else {
543 			*span = dim->header.line[line].span;
544 		}
545 	}
546 
547 	if (text == NULL)
548 		text = "";
549 
550 	return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
551 }
552 
553 #define HEX_STR(__s, __v)				\
554 ({							\
555 	scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v);	\
556 	__s;						\
557 })
558 
559 static int64_t
560 dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
561 	       struct hist_entry *left, struct hist_entry *right)
562 {
563 	return sort__dcacheline_cmp(left, right);
564 }
565 
566 static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
567 			    struct hist_entry *he)
568 {
569 	uint64_t addr = 0;
570 	int width = c2c_width(fmt, hpp, he->hists);
571 	char buf[20];
572 
573 	if (he->mem_info)
574 		addr = cl_address(mem_info__daddr(he->mem_info)->addr, chk_double_cl);
575 
576 	return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
577 }
578 
579 static int
580 dcacheline_node_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
581 		      struct hist_entry *he)
582 {
583 	struct c2c_hist_entry *c2c_he;
584 	int width = c2c_width(fmt, hpp, he->hists);
585 
586 	c2c_he = container_of(he, struct c2c_hist_entry, he);
587 	if (WARN_ON_ONCE(!c2c_he->nodestr))
588 		return 0;
589 
590 	return scnprintf(hpp->buf, hpp->size, "%*s", width, c2c_he->nodestr);
591 }
592 
593 static int
594 dcacheline_node_count(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
595 		      struct hist_entry *he)
596 {
597 	struct c2c_hist_entry *c2c_he;
598 	int width = c2c_width(fmt, hpp, he->hists);
599 
600 	c2c_he = container_of(he, struct c2c_hist_entry, he);
601 	return scnprintf(hpp->buf, hpp->size, "%*lu", width, c2c_he->paddr_cnt);
602 }
603 
604 static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
605 			struct hist_entry *he)
606 {
607 	uint64_t addr = 0;
608 	int width = c2c_width(fmt, hpp, he->hists);
609 	char buf[20];
610 
611 	if (he->mem_info)
612 		addr = cl_offset(mem_info__daddr(he->mem_info)->al_addr, chk_double_cl);
613 
614 	return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
615 }
616 
617 static int64_t
618 offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
619 	   struct hist_entry *left, struct hist_entry *right)
620 {
621 	uint64_t l = 0, r = 0;
622 
623 	if (left->mem_info)
624 		l = cl_offset(mem_info__daddr(left->mem_info)->addr, chk_double_cl);
625 
626 	if (right->mem_info)
627 		r = cl_offset(mem_info__daddr(right->mem_info)->addr, chk_double_cl);
628 
629 	return (int64_t)(r - l);
630 }
631 
632 static int
633 iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
634 	    struct hist_entry *he)
635 {
636 	uint64_t addr = 0;
637 	int width = c2c_width(fmt, hpp, he->hists);
638 	char buf[20];
639 
640 	if (he->mem_info)
641 		addr = mem_info__iaddr(he->mem_info)->addr;
642 
643 	return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
644 }
645 
646 static int64_t
647 iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
648 	  struct hist_entry *left, struct hist_entry *right)
649 {
650 	return sort__iaddr_cmp(left, right);
651 }
652 
653 static int
654 tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
655 	       struct hist_entry *he)
656 {
657 	struct c2c_hist_entry *c2c_he;
658 	int width = c2c_width(fmt, hpp, he->hists);
659 	unsigned int tot_hitm;
660 
661 	c2c_he = container_of(he, struct c2c_hist_entry, he);
662 	tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
663 
664 	return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
665 }
666 
667 static int64_t
668 tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
669 	     struct hist_entry *left, struct hist_entry *right)
670 {
671 	struct c2c_hist_entry *c2c_left;
672 	struct c2c_hist_entry *c2c_right;
673 	uint64_t tot_hitm_left;
674 	uint64_t tot_hitm_right;
675 
676 	c2c_left  = container_of(left, struct c2c_hist_entry, he);
677 	c2c_right = container_of(right, struct c2c_hist_entry, he);
678 
679 	tot_hitm_left  = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
680 	tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
681 
682 	return tot_hitm_left - tot_hitm_right;
683 }
684 
685 #define STAT_FN_ENTRY(__f)					\
686 static int							\
687 __f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,	\
688 	      struct hist_entry *he)				\
689 {								\
690 	struct c2c_hist_entry *c2c_he;				\
691 	int width = c2c_width(fmt, hpp, he->hists);		\
692 								\
693 	c2c_he = container_of(he, struct c2c_hist_entry, he);	\
694 	return scnprintf(hpp->buf, hpp->size, "%*u", width,	\
695 			 c2c_he->stats.__f);			\
696 }
697 
698 #define STAT_FN_CMP(__f)						\
699 static int64_t								\
700 __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused,			\
701 	    struct hist_entry *left, struct hist_entry *right)		\
702 {									\
703 	struct c2c_hist_entry *c2c_left, *c2c_right;			\
704 									\
705 	c2c_left  = container_of(left, struct c2c_hist_entry, he);	\
706 	c2c_right = container_of(right, struct c2c_hist_entry, he);	\
707 	return (uint64_t) c2c_left->stats.__f -				\
708 	       (uint64_t) c2c_right->stats.__f;				\
709 }
710 
711 #define STAT_FN(__f)		\
712 	STAT_FN_ENTRY(__f)	\
713 	STAT_FN_CMP(__f)
714 
715 STAT_FN(rmt_hitm)
716 STAT_FN(lcl_hitm)
717 STAT_FN(rmt_peer)
718 STAT_FN(lcl_peer)
719 STAT_FN(tot_peer)
720 STAT_FN(store)
721 STAT_FN(st_l1hit)
722 STAT_FN(st_l1miss)
723 STAT_FN(st_na)
724 STAT_FN(ld_fbhit)
725 STAT_FN(ld_l1hit)
726 STAT_FN(ld_l2hit)
727 STAT_FN(ld_llchit)
728 STAT_FN(rmt_hit)
729 
730 static uint64_t get_load_llc_misses(struct c2c_stats *stats)
731 {
732 	return stats->lcl_dram +
733 	       stats->rmt_dram +
734 	       stats->rmt_hitm +
735 	       stats->rmt_hit;
736 }
737 
738 static uint64_t get_load_cache_hits(struct c2c_stats *stats)
739 {
740 	return stats->ld_fbhit +
741 	       stats->ld_l1hit +
742 	       stats->ld_l2hit +
743 	       stats->ld_llchit +
744 	       stats->lcl_hitm;
745 }
746 
747 static uint64_t get_stores(struct c2c_stats *stats)
748 {
749 	return stats->st_l1hit +
750 	       stats->st_l1miss +
751 	       stats->st_na;
752 }
753 
754 static uint64_t total_records(struct c2c_stats *stats)
755 {
756 	return get_load_llc_misses(stats) +
757 	       get_load_cache_hits(stats) +
758 	       get_stores(stats);
759 }
760 
761 static int
762 tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
763 		struct hist_entry *he)
764 {
765 	struct c2c_hist_entry *c2c_he;
766 	int width = c2c_width(fmt, hpp, he->hists);
767 	uint64_t tot_recs;
768 
769 	c2c_he = container_of(he, struct c2c_hist_entry, he);
770 	tot_recs = total_records(&c2c_he->stats);
771 
772 	return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
773 }
774 
775 static int64_t
776 tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
777 	     struct hist_entry *left, struct hist_entry *right)
778 {
779 	struct c2c_hist_entry *c2c_left;
780 	struct c2c_hist_entry *c2c_right;
781 	uint64_t tot_recs_left;
782 	uint64_t tot_recs_right;
783 
784 	c2c_left  = container_of(left, struct c2c_hist_entry, he);
785 	c2c_right = container_of(right, struct c2c_hist_entry, he);
786 
787 	tot_recs_left  = total_records(&c2c_left->stats);
788 	tot_recs_right = total_records(&c2c_right->stats);
789 
790 	return tot_recs_left - tot_recs_right;
791 }
792 
793 static uint64_t total_loads(struct c2c_stats *stats)
794 {
795 	return get_load_llc_misses(stats) +
796 	       get_load_cache_hits(stats);
797 }
798 
799 static int
800 tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
801 		struct hist_entry *he)
802 {
803 	struct c2c_hist_entry *c2c_he;
804 	int width = c2c_width(fmt, hpp, he->hists);
805 	uint64_t tot_recs;
806 
807 	c2c_he = container_of(he, struct c2c_hist_entry, he);
808 	tot_recs = total_loads(&c2c_he->stats);
809 
810 	return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
811 }
812 
813 static int64_t
814 tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
815 	      struct hist_entry *left, struct hist_entry *right)
816 {
817 	struct c2c_hist_entry *c2c_left;
818 	struct c2c_hist_entry *c2c_right;
819 	uint64_t tot_recs_left;
820 	uint64_t tot_recs_right;
821 
822 	c2c_left  = container_of(left, struct c2c_hist_entry, he);
823 	c2c_right = container_of(right, struct c2c_hist_entry, he);
824 
825 	tot_recs_left  = total_loads(&c2c_left->stats);
826 	tot_recs_right = total_loads(&c2c_right->stats);
827 
828 	return tot_recs_left - tot_recs_right;
829 }
830 
831 typedef double (get_percent_cb)(struct c2c_hist_entry *);
832 
833 static int
834 percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
835 	      struct hist_entry *he, get_percent_cb get_percent)
836 {
837 	struct c2c_hist_entry *c2c_he;
838 	int width = c2c_width(fmt, hpp, he->hists);
839 	double per;
840 
841 	c2c_he = container_of(he, struct c2c_hist_entry, he);
842 	per = get_percent(c2c_he);
843 
844 #ifdef HAVE_SLANG_SUPPORT
845 	if (use_browser)
846 		return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
847 #endif
848 	return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
849 }
850 
851 static double percent_costly_snoop(struct c2c_hist_entry *c2c_he)
852 {
853 	struct c2c_hists *hists;
854 	struct c2c_stats *stats;
855 	struct c2c_stats *total;
856 	int tot = 0, st = 0;
857 	double p;
858 
859 	hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
860 	stats = &c2c_he->stats;
861 	total = &hists->stats;
862 
863 	switch (c2c.display) {
864 	case DISPLAY_RMT_HITM:
865 		st  = stats->rmt_hitm;
866 		tot = total->rmt_hitm;
867 		break;
868 	case DISPLAY_LCL_HITM:
869 		st  = stats->lcl_hitm;
870 		tot = total->lcl_hitm;
871 		break;
872 	case DISPLAY_TOT_HITM:
873 		st  = stats->tot_hitm;
874 		tot = total->tot_hitm;
875 		break;
876 	case DISPLAY_SNP_PEER:
877 		st  = stats->tot_peer;
878 		tot = total->tot_peer;
879 		break;
880 	default:
881 		break;
882 	}
883 
884 	p = tot ? (double) st / tot : 0;
885 
886 	return 100 * p;
887 }
888 
889 #define PERC_STR(__s, __v)				\
890 ({							\
891 	scnprintf(__s, sizeof(__s), "%.2F%%", __v);	\
892 	__s;						\
893 })
894 
895 static int
896 percent_costly_snoop_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
897 			   struct hist_entry *he)
898 {
899 	struct c2c_hist_entry *c2c_he;
900 	int width = c2c_width(fmt, hpp, he->hists);
901 	char buf[10];
902 	double per;
903 
904 	c2c_he = container_of(he, struct c2c_hist_entry, he);
905 	per = percent_costly_snoop(c2c_he);
906 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
907 }
908 
909 static int
910 percent_costly_snoop_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
911 			   struct hist_entry *he)
912 {
913 	return percent_color(fmt, hpp, he, percent_costly_snoop);
914 }
915 
916 static int64_t
917 percent_costly_snoop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
918 			 struct hist_entry *left, struct hist_entry *right)
919 {
920 	struct c2c_hist_entry *c2c_left;
921 	struct c2c_hist_entry *c2c_right;
922 	double per_left;
923 	double per_right;
924 
925 	c2c_left  = container_of(left, struct c2c_hist_entry, he);
926 	c2c_right = container_of(right, struct c2c_hist_entry, he);
927 
928 	per_left  = percent_costly_snoop(c2c_left);
929 	per_right = percent_costly_snoop(c2c_right);
930 
931 	return per_left - per_right;
932 }
933 
934 static struct c2c_stats *he_stats(struct hist_entry *he)
935 {
936 	struct c2c_hist_entry *c2c_he;
937 
938 	c2c_he = container_of(he, struct c2c_hist_entry, he);
939 	return &c2c_he->stats;
940 }
941 
942 static struct c2c_stats *total_stats(struct hist_entry *he)
943 {
944 	struct c2c_hists *hists;
945 
946 	hists = container_of(he->hists, struct c2c_hists, hists);
947 	return &hists->stats;
948 }
949 
950 static double percent(u32 st, u32 tot)
951 {
952 	return tot ? 100. * (double) st / (double) tot : 0;
953 }
954 
955 #define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
956 
957 #define PERCENT_FN(__f)								\
958 static double percent_ ## __f(struct c2c_hist_entry *c2c_he)			\
959 {										\
960 	struct c2c_hists *hists;						\
961 										\
962 	hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);	\
963 	return percent(c2c_he->stats.__f, hists->stats.__f);			\
964 }
965 
966 PERCENT_FN(rmt_hitm)
967 PERCENT_FN(lcl_hitm)
968 PERCENT_FN(rmt_peer)
969 PERCENT_FN(lcl_peer)
970 PERCENT_FN(st_l1hit)
971 PERCENT_FN(st_l1miss)
972 PERCENT_FN(st_na)
973 
974 static int
975 percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
976 		       struct hist_entry *he)
977 {
978 	int width = c2c_width(fmt, hpp, he->hists);
979 	double per = PERCENT(he, rmt_hitm);
980 	char buf[10];
981 
982 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
983 }
984 
985 static int
986 percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
987 		       struct hist_entry *he)
988 {
989 	return percent_color(fmt, hpp, he, percent_rmt_hitm);
990 }
991 
992 static int64_t
993 percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
994 		     struct hist_entry *left, struct hist_entry *right)
995 {
996 	double per_left;
997 	double per_right;
998 
999 	per_left  = PERCENT(left, rmt_hitm);
1000 	per_right = PERCENT(right, rmt_hitm);
1001 
1002 	return per_left - per_right;
1003 }
1004 
1005 static int
1006 percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1007 		       struct hist_entry *he)
1008 {
1009 	int width = c2c_width(fmt, hpp, he->hists);
1010 	double per = PERCENT(he, lcl_hitm);
1011 	char buf[10];
1012 
1013 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1014 }
1015 
1016 static int
1017 percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1018 		       struct hist_entry *he)
1019 {
1020 	return percent_color(fmt, hpp, he, percent_lcl_hitm);
1021 }
1022 
1023 static int64_t
1024 percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1025 		     struct hist_entry *left, struct hist_entry *right)
1026 {
1027 	double per_left;
1028 	double per_right;
1029 
1030 	per_left  = PERCENT(left, lcl_hitm);
1031 	per_right = PERCENT(right, lcl_hitm);
1032 
1033 	return per_left - per_right;
1034 }
1035 
1036 static int
1037 percent_lcl_peer_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1038 		       struct hist_entry *he)
1039 {
1040 	int width = c2c_width(fmt, hpp, he->hists);
1041 	double per = PERCENT(he, lcl_peer);
1042 	char buf[10];
1043 
1044 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1045 }
1046 
1047 static int
1048 percent_lcl_peer_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1049 		       struct hist_entry *he)
1050 {
1051 	return percent_color(fmt, hpp, he, percent_lcl_peer);
1052 }
1053 
1054 static int64_t
1055 percent_lcl_peer_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1056 		     struct hist_entry *left, struct hist_entry *right)
1057 {
1058 	double per_left;
1059 	double per_right;
1060 
1061 	per_left  = PERCENT(left, lcl_peer);
1062 	per_right = PERCENT(right, lcl_peer);
1063 
1064 	return per_left - per_right;
1065 }
1066 
1067 static int
1068 percent_rmt_peer_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1069 		       struct hist_entry *he)
1070 {
1071 	int width = c2c_width(fmt, hpp, he->hists);
1072 	double per = PERCENT(he, rmt_peer);
1073 	char buf[10];
1074 
1075 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1076 }
1077 
1078 static int
1079 percent_rmt_peer_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1080 		       struct hist_entry *he)
1081 {
1082 	return percent_color(fmt, hpp, he, percent_rmt_peer);
1083 }
1084 
1085 static int64_t
1086 percent_rmt_peer_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1087 		     struct hist_entry *left, struct hist_entry *right)
1088 {
1089 	double per_left;
1090 	double per_right;
1091 
1092 	per_left  = PERCENT(left, rmt_peer);
1093 	per_right = PERCENT(right, rmt_peer);
1094 
1095 	return per_left - per_right;
1096 }
1097 
1098 static int
1099 percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1100 			   struct hist_entry *he)
1101 {
1102 	int width = c2c_width(fmt, hpp, he->hists);
1103 	double per = PERCENT(he, st_l1hit);
1104 	char buf[10];
1105 
1106 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1107 }
1108 
1109 static int
1110 percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1111 			   struct hist_entry *he)
1112 {
1113 	return percent_color(fmt, hpp, he, percent_st_l1hit);
1114 }
1115 
1116 static int64_t
1117 percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1118 			struct hist_entry *left, struct hist_entry *right)
1119 {
1120 	double per_left;
1121 	double per_right;
1122 
1123 	per_left  = PERCENT(left, st_l1hit);
1124 	per_right = PERCENT(right, st_l1hit);
1125 
1126 	return per_left - per_right;
1127 }
1128 
1129 static int
1130 percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1131 			   struct hist_entry *he)
1132 {
1133 	int width = c2c_width(fmt, hpp, he->hists);
1134 	double per = PERCENT(he, st_l1miss);
1135 	char buf[10];
1136 
1137 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1138 }
1139 
1140 static int
1141 percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1142 			    struct hist_entry *he)
1143 {
1144 	return percent_color(fmt, hpp, he, percent_st_l1miss);
1145 }
1146 
1147 static int64_t
1148 percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1149 			  struct hist_entry *left, struct hist_entry *right)
1150 {
1151 	double per_left;
1152 	double per_right;
1153 
1154 	per_left  = PERCENT(left, st_l1miss);
1155 	per_right = PERCENT(right, st_l1miss);
1156 
1157 	return per_left - per_right;
1158 }
1159 
1160 static int
1161 percent_stores_na_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1162 			struct hist_entry *he)
1163 {
1164 	int width = c2c_width(fmt, hpp, he->hists);
1165 	double per = PERCENT(he, st_na);
1166 	char buf[10];
1167 
1168 	return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1169 }
1170 
1171 static int
1172 percent_stores_na_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1173 			struct hist_entry *he)
1174 {
1175 	return percent_color(fmt, hpp, he, percent_st_na);
1176 }
1177 
1178 static int64_t
1179 percent_stores_na_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1180 		      struct hist_entry *left, struct hist_entry *right)
1181 {
1182 	double per_left;
1183 	double per_right;
1184 
1185 	per_left  = PERCENT(left, st_na);
1186 	per_right = PERCENT(right, st_na);
1187 
1188 	return per_left - per_right;
1189 }
1190 
1191 STAT_FN(lcl_dram)
1192 STAT_FN(rmt_dram)
1193 
1194 static int
1195 pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1196 	  struct hist_entry *he)
1197 {
1198 	int width = c2c_width(fmt, hpp, he->hists);
1199 
1200 	return scnprintf(hpp->buf, hpp->size, "%*d", width, thread__pid(he->thread));
1201 }
1202 
1203 static int64_t
1204 pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1205 	struct hist_entry *left, struct hist_entry *right)
1206 {
1207 	return thread__pid(left->thread) - thread__pid(right->thread);
1208 }
1209 
1210 static int64_t
1211 empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1212 	  struct hist_entry *left __maybe_unused,
1213 	  struct hist_entry *right __maybe_unused)
1214 {
1215 	return 0;
1216 }
1217 
1218 static int display_metrics(struct perf_hpp *hpp, u32 val, u32 sum)
1219 {
1220 	int ret;
1221 
1222 	if (sum != 0)
1223 		ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ",
1224 				percent(val, sum));
1225 	else
1226 		ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a");
1227 
1228 	return ret;
1229 }
1230 
1231 static int
1232 node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1233 	   struct hist_entry *he)
1234 {
1235 	struct c2c_hist_entry *c2c_he;
1236 	bool first = true;
1237 	int node;
1238 	int ret = 0;
1239 
1240 	c2c_he = container_of(he, struct c2c_hist_entry, he);
1241 
1242 	for (node = 0; node < c2c.nodes_cnt; node++) {
1243 		DECLARE_BITMAP(set, c2c.cpus_cnt);
1244 
1245 		bitmap_zero(set, c2c.cpus_cnt);
1246 		bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
1247 
1248 		if (bitmap_empty(set, c2c.cpus_cnt)) {
1249 			if (c2c.node_info == 1) {
1250 				ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
1251 				advance_hpp(hpp, ret);
1252 			}
1253 			continue;
1254 		}
1255 
1256 		if (!first) {
1257 			ret = scnprintf(hpp->buf, hpp->size, " ");
1258 			advance_hpp(hpp, ret);
1259 		}
1260 
1261 		switch (c2c.node_info) {
1262 		case 0:
1263 			ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
1264 			advance_hpp(hpp, ret);
1265 			break;
1266 		case 1:
1267 		{
1268 			int num = bitmap_weight(set, c2c.cpus_cnt);
1269 			struct c2c_stats *stats = &c2c_he->node_stats[node];
1270 
1271 			ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
1272 			advance_hpp(hpp, ret);
1273 
1274 			switch (c2c.display) {
1275 			case DISPLAY_RMT_HITM:
1276 				ret = display_metrics(hpp, stats->rmt_hitm,
1277 						      c2c_he->stats.rmt_hitm);
1278 				break;
1279 			case DISPLAY_LCL_HITM:
1280 				ret = display_metrics(hpp, stats->lcl_hitm,
1281 						      c2c_he->stats.lcl_hitm);
1282 				break;
1283 			case DISPLAY_TOT_HITM:
1284 				ret = display_metrics(hpp, stats->tot_hitm,
1285 						      c2c_he->stats.tot_hitm);
1286 				break;
1287 			case DISPLAY_SNP_PEER:
1288 				ret = display_metrics(hpp, stats->tot_peer,
1289 						      c2c_he->stats.tot_peer);
1290 				break;
1291 			default:
1292 				break;
1293 			}
1294 
1295 			advance_hpp(hpp, ret);
1296 
1297 			if (c2c_he->stats.store > 0) {
1298 				ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
1299 						percent(stats->store, c2c_he->stats.store));
1300 			} else {
1301 				ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
1302 			}
1303 
1304 			advance_hpp(hpp, ret);
1305 			break;
1306 		}
1307 		case 2:
1308 			ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
1309 			advance_hpp(hpp, ret);
1310 
1311 			ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
1312 			advance_hpp(hpp, ret);
1313 
1314 			ret = scnprintf(hpp->buf, hpp->size, "}");
1315 			advance_hpp(hpp, ret);
1316 			break;
1317 		default:
1318 			break;
1319 		}
1320 
1321 		first = false;
1322 	}
1323 
1324 	return 0;
1325 }
1326 
1327 static int
1328 mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1329 	   struct hist_entry *he, double mean)
1330 {
1331 	int width = c2c_width(fmt, hpp, he->hists);
1332 	char buf[10];
1333 
1334 	scnprintf(buf, 10, "%6.0f", mean);
1335 	return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1336 }
1337 
1338 #define MEAN_ENTRY(__func, __val)						\
1339 static int									\
1340 __func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he)	\
1341 {										\
1342 	struct c2c_hist_entry *c2c_he;						\
1343 	c2c_he = container_of(he, struct c2c_hist_entry, he);			\
1344 	return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val));	\
1345 }
1346 
1347 MEAN_ENTRY(mean_rmt_entry,  rmt_hitm);
1348 MEAN_ENTRY(mean_lcl_entry,  lcl_hitm);
1349 MEAN_ENTRY(mean_load_entry, load);
1350 MEAN_ENTRY(mean_rmt_peer_entry, rmt_peer);
1351 MEAN_ENTRY(mean_lcl_peer_entry, lcl_peer);
1352 
1353 static int
1354 cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1355 	     struct hist_entry *he)
1356 {
1357 	struct c2c_hist_entry *c2c_he;
1358 	int width = c2c_width(fmt, hpp, he->hists);
1359 	char buf[10];
1360 
1361 	c2c_he = container_of(he, struct c2c_hist_entry, he);
1362 
1363 	scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1364 	return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1365 }
1366 
1367 static int
1368 cl_idx_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1369 	     struct hist_entry *he)
1370 {
1371 	struct c2c_hist_entry *c2c_he;
1372 	int width = c2c_width(fmt, hpp, he->hists);
1373 	char buf[10];
1374 
1375 	c2c_he = container_of(he, struct c2c_hist_entry, he);
1376 
1377 	scnprintf(buf, 10, "%u", c2c_he->cacheline_idx);
1378 	return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1379 }
1380 
1381 static int
1382 cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1383 		   struct hist_entry *he)
1384 {
1385 	int width = c2c_width(fmt, hpp, he->hists);
1386 
1387 	return scnprintf(hpp->buf, hpp->size, "%*s", width, "");
1388 }
1389 
1390 #define HEADER_LOW(__h)			\
1391 	{				\
1392 		.line[1] = {		\
1393 			.text = __h,	\
1394 		},			\
1395 	}
1396 
1397 #define HEADER_BOTH(__h0, __h1)		\
1398 	{				\
1399 		.line[0] = {		\
1400 			.text = __h0,	\
1401 		},			\
1402 		.line[1] = {		\
1403 			.text = __h1,	\
1404 		},			\
1405 	}
1406 
1407 #define HEADER_SPAN(__h0, __h1, __s)	\
1408 	{				\
1409 		.line[0] = {		\
1410 			.text = __h0,	\
1411 			.span = __s,	\
1412 		},			\
1413 		.line[1] = {		\
1414 			.text = __h1,	\
1415 		},			\
1416 	}
1417 
1418 #define HEADER_SPAN_LOW(__h)		\
1419 	{				\
1420 		.line[1] = {		\
1421 			.text = __h,	\
1422 		},			\
1423 	}
1424 
1425 static struct c2c_dimension dim_dcacheline = {
1426 	.header		= HEADER_SPAN("--- Cacheline ----", "Address", 2),
1427 	.name		= "dcacheline",
1428 	.cmp		= dcacheline_cmp,
1429 	.entry		= dcacheline_entry,
1430 	.width		= 18,
1431 };
1432 
1433 static struct c2c_dimension dim_dcacheline_node = {
1434 	.header		= HEADER_LOW("Node"),
1435 	.name		= "dcacheline_node",
1436 	.cmp		= empty_cmp,
1437 	.entry		= dcacheline_node_entry,
1438 	.width		= 4,
1439 };
1440 
1441 static struct c2c_dimension dim_dcacheline_count = {
1442 	.header		= HEADER_LOW("PA cnt"),
1443 	.name		= "dcacheline_count",
1444 	.cmp		= empty_cmp,
1445 	.entry		= dcacheline_node_count,
1446 	.width		= 6,
1447 };
1448 
1449 static struct c2c_header header_offset_tui = HEADER_SPAN("-----", "Off", 2);
1450 
1451 static struct c2c_dimension dim_offset = {
1452 	.header		= HEADER_SPAN("--- Data address -", "Offset", 2),
1453 	.name		= "offset",
1454 	.cmp		= offset_cmp,
1455 	.entry		= offset_entry,
1456 	.width		= 18,
1457 };
1458 
1459 static struct c2c_dimension dim_offset_node = {
1460 	.header		= HEADER_LOW("Node"),
1461 	.name		= "offset_node",
1462 	.cmp		= empty_cmp,
1463 	.entry		= dcacheline_node_entry,
1464 	.width		= 4,
1465 };
1466 
1467 static struct c2c_dimension dim_iaddr = {
1468 	.header		= HEADER_LOW("Code address"),
1469 	.name		= "iaddr",
1470 	.cmp		= iaddr_cmp,
1471 	.entry		= iaddr_entry,
1472 	.width		= 18,
1473 };
1474 
1475 static struct c2c_dimension dim_tot_hitm = {
1476 	.header		= HEADER_SPAN("------- Load Hitm -------", "Total", 2),
1477 	.name		= "tot_hitm",
1478 	.cmp		= tot_hitm_cmp,
1479 	.entry		= tot_hitm_entry,
1480 	.width		= 7,
1481 };
1482 
1483 static struct c2c_dimension dim_lcl_hitm = {
1484 	.header		= HEADER_SPAN_LOW("LclHitm"),
1485 	.name		= "lcl_hitm",
1486 	.cmp		= lcl_hitm_cmp,
1487 	.entry		= lcl_hitm_entry,
1488 	.width		= 7,
1489 };
1490 
1491 static struct c2c_dimension dim_rmt_hitm = {
1492 	.header		= HEADER_SPAN_LOW("RmtHitm"),
1493 	.name		= "rmt_hitm",
1494 	.cmp		= rmt_hitm_cmp,
1495 	.entry		= rmt_hitm_entry,
1496 	.width		= 7,
1497 };
1498 
1499 static struct c2c_dimension dim_tot_peer = {
1500 	.header		= HEADER_SPAN("------- Load Peer -------", "Total", 2),
1501 	.name		= "tot_peer",
1502 	.cmp		= tot_peer_cmp,
1503 	.entry		= tot_peer_entry,
1504 	.width		= 7,
1505 };
1506 
1507 static struct c2c_dimension dim_lcl_peer = {
1508 	.header		= HEADER_SPAN_LOW("Local"),
1509 	.name		= "lcl_peer",
1510 	.cmp		= lcl_peer_cmp,
1511 	.entry		= lcl_peer_entry,
1512 	.width		= 7,
1513 };
1514 
1515 static struct c2c_dimension dim_rmt_peer = {
1516 	.header		= HEADER_SPAN_LOW("Remote"),
1517 	.name		= "rmt_peer",
1518 	.cmp		= rmt_peer_cmp,
1519 	.entry		= rmt_peer_entry,
1520 	.width		= 7,
1521 };
1522 
1523 static struct c2c_dimension dim_cl_rmt_hitm = {
1524 	.header		= HEADER_SPAN("----- HITM -----", "Rmt", 1),
1525 	.name		= "cl_rmt_hitm",
1526 	.cmp		= rmt_hitm_cmp,
1527 	.entry		= rmt_hitm_entry,
1528 	.width		= 7,
1529 };
1530 
1531 static struct c2c_dimension dim_cl_lcl_hitm = {
1532 	.header		= HEADER_SPAN_LOW("Lcl"),
1533 	.name		= "cl_lcl_hitm",
1534 	.cmp		= lcl_hitm_cmp,
1535 	.entry		= lcl_hitm_entry,
1536 	.width		= 7,
1537 };
1538 
1539 static struct c2c_dimension dim_cl_rmt_peer = {
1540 	.header		= HEADER_SPAN("----- Peer -----", "Rmt", 1),
1541 	.name		= "cl_rmt_peer",
1542 	.cmp		= rmt_peer_cmp,
1543 	.entry		= rmt_peer_entry,
1544 	.width		= 7,
1545 };
1546 
1547 static struct c2c_dimension dim_cl_lcl_peer = {
1548 	.header		= HEADER_SPAN_LOW("Lcl"),
1549 	.name		= "cl_lcl_peer",
1550 	.cmp		= lcl_peer_cmp,
1551 	.entry		= lcl_peer_entry,
1552 	.width		= 7,
1553 };
1554 
1555 static struct c2c_dimension dim_tot_stores = {
1556 	.header		= HEADER_BOTH("Total", "Stores"),
1557 	.name		= "tot_stores",
1558 	.cmp		= store_cmp,
1559 	.entry		= store_entry,
1560 	.width		= 7,
1561 };
1562 
1563 static struct c2c_dimension dim_stores_l1hit = {
1564 	.header		= HEADER_SPAN("--------- Stores --------", "L1Hit", 2),
1565 	.name		= "stores_l1hit",
1566 	.cmp		= st_l1hit_cmp,
1567 	.entry		= st_l1hit_entry,
1568 	.width		= 7,
1569 };
1570 
1571 static struct c2c_dimension dim_stores_l1miss = {
1572 	.header		= HEADER_SPAN_LOW("L1Miss"),
1573 	.name		= "stores_l1miss",
1574 	.cmp		= st_l1miss_cmp,
1575 	.entry		= st_l1miss_entry,
1576 	.width		= 7,
1577 };
1578 
1579 static struct c2c_dimension dim_stores_na = {
1580 	.header		= HEADER_SPAN_LOW("N/A"),
1581 	.name		= "stores_na",
1582 	.cmp		= st_na_cmp,
1583 	.entry		= st_na_entry,
1584 	.width		= 7,
1585 };
1586 
1587 static struct c2c_dimension dim_cl_stores_l1hit = {
1588 	.header		= HEADER_SPAN("------- Store Refs ------", "L1 Hit", 2),
1589 	.name		= "cl_stores_l1hit",
1590 	.cmp		= st_l1hit_cmp,
1591 	.entry		= st_l1hit_entry,
1592 	.width		= 7,
1593 };
1594 
1595 static struct c2c_dimension dim_cl_stores_l1miss = {
1596 	.header		= HEADER_SPAN_LOW("L1 Miss"),
1597 	.name		= "cl_stores_l1miss",
1598 	.cmp		= st_l1miss_cmp,
1599 	.entry		= st_l1miss_entry,
1600 	.width		= 7,
1601 };
1602 
1603 static struct c2c_dimension dim_cl_stores_na = {
1604 	.header		= HEADER_SPAN_LOW("N/A"),
1605 	.name		= "cl_stores_na",
1606 	.cmp		= st_na_cmp,
1607 	.entry		= st_na_entry,
1608 	.width		= 7,
1609 };
1610 
1611 static struct c2c_dimension dim_ld_fbhit = {
1612 	.header		= HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1613 	.name		= "ld_fbhit",
1614 	.cmp		= ld_fbhit_cmp,
1615 	.entry		= ld_fbhit_entry,
1616 	.width		= 7,
1617 };
1618 
1619 static struct c2c_dimension dim_ld_l1hit = {
1620 	.header		= HEADER_SPAN_LOW("L1"),
1621 	.name		= "ld_l1hit",
1622 	.cmp		= ld_l1hit_cmp,
1623 	.entry		= ld_l1hit_entry,
1624 	.width		= 7,
1625 };
1626 
1627 static struct c2c_dimension dim_ld_l2hit = {
1628 	.header		= HEADER_SPAN_LOW("L2"),
1629 	.name		= "ld_l2hit",
1630 	.cmp		= ld_l2hit_cmp,
1631 	.entry		= ld_l2hit_entry,
1632 	.width		= 7,
1633 };
1634 
1635 static struct c2c_dimension dim_ld_llchit = {
1636 	.header		= HEADER_SPAN("- LLC Load Hit --", "LclHit", 1),
1637 	.name		= "ld_lclhit",
1638 	.cmp		= ld_llchit_cmp,
1639 	.entry		= ld_llchit_entry,
1640 	.width		= 8,
1641 };
1642 
1643 static struct c2c_dimension dim_ld_rmthit = {
1644 	.header		= HEADER_SPAN("- RMT Load Hit --", "RmtHit", 1),
1645 	.name		= "ld_rmthit",
1646 	.cmp		= rmt_hit_cmp,
1647 	.entry		= rmt_hit_entry,
1648 	.width		= 8,
1649 };
1650 
1651 static struct c2c_dimension dim_tot_recs = {
1652 	.header		= HEADER_BOTH("Total", "records"),
1653 	.name		= "tot_recs",
1654 	.cmp		= tot_recs_cmp,
1655 	.entry		= tot_recs_entry,
1656 	.width		= 7,
1657 };
1658 
1659 static struct c2c_dimension dim_tot_loads = {
1660 	.header		= HEADER_BOTH("Total", "Loads"),
1661 	.name		= "tot_loads",
1662 	.cmp		= tot_loads_cmp,
1663 	.entry		= tot_loads_entry,
1664 	.width		= 7,
1665 };
1666 
1667 static struct c2c_header percent_costly_snoop_header[] = {
1668 	[DISPLAY_LCL_HITM] = HEADER_BOTH("Lcl", "Hitm"),
1669 	[DISPLAY_RMT_HITM] = HEADER_BOTH("Rmt", "Hitm"),
1670 	[DISPLAY_TOT_HITM] = HEADER_BOTH("Tot", "Hitm"),
1671 	[DISPLAY_SNP_PEER] = HEADER_BOTH("Peer", "Snoop"),
1672 };
1673 
1674 static struct c2c_dimension dim_percent_costly_snoop = {
1675 	.name		= "percent_costly_snoop",
1676 	.cmp		= percent_costly_snoop_cmp,
1677 	.entry		= percent_costly_snoop_entry,
1678 	.color		= percent_costly_snoop_color,
1679 	.width		= 7,
1680 };
1681 
1682 static struct c2c_dimension dim_percent_rmt_hitm = {
1683 	.header		= HEADER_SPAN("----- HITM -----", "RmtHitm", 1),
1684 	.name		= "percent_rmt_hitm",
1685 	.cmp		= percent_rmt_hitm_cmp,
1686 	.entry		= percent_rmt_hitm_entry,
1687 	.color		= percent_rmt_hitm_color,
1688 	.width		= 7,
1689 };
1690 
1691 static struct c2c_dimension dim_percent_lcl_hitm = {
1692 	.header		= HEADER_SPAN_LOW("LclHitm"),
1693 	.name		= "percent_lcl_hitm",
1694 	.cmp		= percent_lcl_hitm_cmp,
1695 	.entry		= percent_lcl_hitm_entry,
1696 	.color		= percent_lcl_hitm_color,
1697 	.width		= 7,
1698 };
1699 
1700 static struct c2c_dimension dim_percent_rmt_peer = {
1701 	.header		= HEADER_SPAN("-- Peer Snoop --", "Rmt", 1),
1702 	.name		= "percent_rmt_peer",
1703 	.cmp		= percent_rmt_peer_cmp,
1704 	.entry		= percent_rmt_peer_entry,
1705 	.color		= percent_rmt_peer_color,
1706 	.width		= 7,
1707 };
1708 
1709 static struct c2c_dimension dim_percent_lcl_peer = {
1710 	.header		= HEADER_SPAN_LOW("Lcl"),
1711 	.name		= "percent_lcl_peer",
1712 	.cmp		= percent_lcl_peer_cmp,
1713 	.entry		= percent_lcl_peer_entry,
1714 	.color		= percent_lcl_peer_color,
1715 	.width		= 7,
1716 };
1717 
1718 static struct c2c_dimension dim_percent_stores_l1hit = {
1719 	.header		= HEADER_SPAN("------- Store Refs ------", "L1 Hit", 2),
1720 	.name		= "percent_stores_l1hit",
1721 	.cmp		= percent_stores_l1hit_cmp,
1722 	.entry		= percent_stores_l1hit_entry,
1723 	.color		= percent_stores_l1hit_color,
1724 	.width		= 7,
1725 };
1726 
1727 static struct c2c_dimension dim_percent_stores_l1miss = {
1728 	.header		= HEADER_SPAN_LOW("L1 Miss"),
1729 	.name		= "percent_stores_l1miss",
1730 	.cmp		= percent_stores_l1miss_cmp,
1731 	.entry		= percent_stores_l1miss_entry,
1732 	.color		= percent_stores_l1miss_color,
1733 	.width		= 7,
1734 };
1735 
1736 static struct c2c_dimension dim_percent_stores_na = {
1737 	.header		= HEADER_SPAN_LOW("N/A"),
1738 	.name		= "percent_stores_na",
1739 	.cmp		= percent_stores_na_cmp,
1740 	.entry		= percent_stores_na_entry,
1741 	.color		= percent_stores_na_color,
1742 	.width		= 7,
1743 };
1744 
1745 static struct c2c_dimension dim_dram_lcl = {
1746 	.header		= HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1747 	.name		= "dram_lcl",
1748 	.cmp		= lcl_dram_cmp,
1749 	.entry		= lcl_dram_entry,
1750 	.width		= 8,
1751 };
1752 
1753 static struct c2c_dimension dim_dram_rmt = {
1754 	.header		= HEADER_SPAN_LOW("Rmt"),
1755 	.name		= "dram_rmt",
1756 	.cmp		= rmt_dram_cmp,
1757 	.entry		= rmt_dram_entry,
1758 	.width		= 8,
1759 };
1760 
1761 static struct c2c_dimension dim_pid = {
1762 	.header		= HEADER_LOW("Pid"),
1763 	.name		= "pid",
1764 	.cmp		= pid_cmp,
1765 	.entry		= pid_entry,
1766 	.width		= 7,
1767 };
1768 
1769 static struct c2c_dimension dim_tid = {
1770 	.header		= HEADER_LOW("Tid"),
1771 	.name		= "tid",
1772 	.se		= &sort_thread,
1773 };
1774 
1775 static struct c2c_dimension dim_symbol = {
1776 	.name		= "symbol",
1777 	.se		= &sort_sym,
1778 };
1779 
1780 static struct c2c_dimension dim_dso = {
1781 	.header		= HEADER_BOTH("Shared", "Object"),
1782 	.name		= "dso",
1783 	.se		= &sort_dso,
1784 };
1785 
1786 static struct c2c_dimension dim_node = {
1787 	.name		= "node",
1788 	.cmp		= empty_cmp,
1789 	.entry		= node_entry,
1790 	.width		= 4,
1791 };
1792 
1793 static struct c2c_dimension dim_mean_rmt = {
1794 	.header		= HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1795 	.name		= "mean_rmt",
1796 	.cmp		= empty_cmp,
1797 	.entry		= mean_rmt_entry,
1798 	.width		= 8,
1799 };
1800 
1801 static struct c2c_dimension dim_mean_lcl = {
1802 	.header		= HEADER_SPAN_LOW("lcl hitm"),
1803 	.name		= "mean_lcl",
1804 	.cmp		= empty_cmp,
1805 	.entry		= mean_lcl_entry,
1806 	.width		= 8,
1807 };
1808 
1809 static struct c2c_dimension dim_mean_load = {
1810 	.header		= HEADER_SPAN_LOW("load"),
1811 	.name		= "mean_load",
1812 	.cmp		= empty_cmp,
1813 	.entry		= mean_load_entry,
1814 	.width		= 8,
1815 };
1816 
1817 static struct c2c_dimension dim_mean_rmt_peer = {
1818 	.header		= HEADER_SPAN("---------- cycles ----------", "rmt peer", 2),
1819 	.name		= "mean_rmt_peer",
1820 	.cmp		= empty_cmp,
1821 	.entry		= mean_rmt_peer_entry,
1822 	.width		= 8,
1823 };
1824 
1825 static struct c2c_dimension dim_mean_lcl_peer = {
1826 	.header		= HEADER_SPAN_LOW("lcl peer"),
1827 	.name		= "mean_lcl_peer",
1828 	.cmp		= empty_cmp,
1829 	.entry		= mean_lcl_peer_entry,
1830 	.width		= 8,
1831 };
1832 
1833 static struct c2c_dimension dim_cpucnt = {
1834 	.header		= HEADER_BOTH("cpu", "cnt"),
1835 	.name		= "cpucnt",
1836 	.cmp		= empty_cmp,
1837 	.entry		= cpucnt_entry,
1838 	.width		= 8,
1839 };
1840 
1841 static struct c2c_dimension dim_srcline = {
1842 	.name		= "cl_srcline",
1843 	.se		= &sort_srcline,
1844 };
1845 
1846 static struct c2c_dimension dim_dcacheline_idx = {
1847 	.header		= HEADER_LOW("Index"),
1848 	.name		= "cl_idx",
1849 	.cmp		= empty_cmp,
1850 	.entry		= cl_idx_entry,
1851 	.width		= 5,
1852 };
1853 
1854 static struct c2c_dimension dim_dcacheline_num = {
1855 	.header		= HEADER_LOW("Num"),
1856 	.name		= "cl_num",
1857 	.cmp		= empty_cmp,
1858 	.entry		= cl_idx_entry,
1859 	.width		= 5,
1860 };
1861 
1862 static struct c2c_dimension dim_dcacheline_num_empty = {
1863 	.header		= HEADER_LOW("Num"),
1864 	.name		= "cl_num_empty",
1865 	.cmp		= empty_cmp,
1866 	.entry		= cl_idx_empty_entry,
1867 	.width		= 5,
1868 };
1869 
1870 static struct c2c_dimension *dimensions[] = {
1871 	&dim_dcacheline,
1872 	&dim_dcacheline_node,
1873 	&dim_dcacheline_count,
1874 	&dim_offset,
1875 	&dim_offset_node,
1876 	&dim_iaddr,
1877 	&dim_tot_hitm,
1878 	&dim_lcl_hitm,
1879 	&dim_rmt_hitm,
1880 	&dim_tot_peer,
1881 	&dim_lcl_peer,
1882 	&dim_rmt_peer,
1883 	&dim_cl_lcl_hitm,
1884 	&dim_cl_rmt_hitm,
1885 	&dim_cl_lcl_peer,
1886 	&dim_cl_rmt_peer,
1887 	&dim_tot_stores,
1888 	&dim_stores_l1hit,
1889 	&dim_stores_l1miss,
1890 	&dim_stores_na,
1891 	&dim_cl_stores_l1hit,
1892 	&dim_cl_stores_l1miss,
1893 	&dim_cl_stores_na,
1894 	&dim_ld_fbhit,
1895 	&dim_ld_l1hit,
1896 	&dim_ld_l2hit,
1897 	&dim_ld_llchit,
1898 	&dim_ld_rmthit,
1899 	&dim_tot_recs,
1900 	&dim_tot_loads,
1901 	&dim_percent_costly_snoop,
1902 	&dim_percent_rmt_hitm,
1903 	&dim_percent_lcl_hitm,
1904 	&dim_percent_rmt_peer,
1905 	&dim_percent_lcl_peer,
1906 	&dim_percent_stores_l1hit,
1907 	&dim_percent_stores_l1miss,
1908 	&dim_percent_stores_na,
1909 	&dim_dram_lcl,
1910 	&dim_dram_rmt,
1911 	&dim_pid,
1912 	&dim_tid,
1913 	&dim_symbol,
1914 	&dim_dso,
1915 	&dim_node,
1916 	&dim_mean_rmt,
1917 	&dim_mean_lcl,
1918 	&dim_mean_rmt_peer,
1919 	&dim_mean_lcl_peer,
1920 	&dim_mean_load,
1921 	&dim_cpucnt,
1922 	&dim_srcline,
1923 	&dim_dcacheline_idx,
1924 	&dim_dcacheline_num,
1925 	&dim_dcacheline_num_empty,
1926 	NULL,
1927 };
1928 
1929 static void fmt_free(struct perf_hpp_fmt *fmt)
1930 {
1931 	struct c2c_fmt *c2c_fmt;
1932 
1933 	c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1934 	free(c2c_fmt);
1935 }
1936 
1937 static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1938 {
1939 	struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1940 	struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1941 
1942 	return c2c_a->dim == c2c_b->dim;
1943 }
1944 
1945 static struct c2c_dimension *get_dimension(const char *name)
1946 {
1947 	unsigned int i;
1948 
1949 	for (i = 0; dimensions[i]; i++) {
1950 		struct c2c_dimension *dim = dimensions[i];
1951 
1952 		if (!strcmp(dim->name, name))
1953 			return dim;
1954 	}
1955 
1956 	return NULL;
1957 }
1958 
1959 static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1960 			struct hist_entry *he)
1961 {
1962 	struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1963 	struct c2c_dimension *dim = c2c_fmt->dim;
1964 	size_t len = fmt->user_len;
1965 
1966 	if (!len) {
1967 		len = hists__col_len(he->hists, dim->se->se_width_idx);
1968 
1969 		if (dim == &dim_symbol || dim == &dim_srcline)
1970 			len = symbol_width(he->hists, dim->se);
1971 	}
1972 
1973 	return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1974 }
1975 
1976 static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1977 			  struct hist_entry *a, struct hist_entry *b)
1978 {
1979 	struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1980 	struct c2c_dimension *dim = c2c_fmt->dim;
1981 
1982 	return dim->se->se_cmp(a, b);
1983 }
1984 
1985 static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1986 			       struct hist_entry *a, struct hist_entry *b)
1987 {
1988 	struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1989 	struct c2c_dimension *dim = c2c_fmt->dim;
1990 	int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1991 
1992 	collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1993 	return collapse_fn(a, b);
1994 }
1995 
1996 static struct c2c_fmt *get_format(const char *name)
1997 {
1998 	struct c2c_dimension *dim = get_dimension(name);
1999 	struct c2c_fmt *c2c_fmt;
2000 	struct perf_hpp_fmt *fmt;
2001 
2002 	if (!dim)
2003 		return NULL;
2004 
2005 	c2c_fmt = zalloc(sizeof(*c2c_fmt));
2006 	if (!c2c_fmt)
2007 		return NULL;
2008 
2009 	c2c_fmt->dim = dim;
2010 
2011 	fmt = &c2c_fmt->fmt;
2012 	INIT_LIST_HEAD(&fmt->list);
2013 	INIT_LIST_HEAD(&fmt->sort_list);
2014 
2015 	fmt->cmp	= dim->se ? c2c_se_cmp   : dim->cmp;
2016 	fmt->sort	= dim->se ? c2c_se_cmp   : dim->cmp;
2017 	fmt->color	= dim->se ? NULL	 : dim->color;
2018 	fmt->entry	= dim->se ? c2c_se_entry : dim->entry;
2019 	fmt->header	= c2c_header;
2020 	fmt->width	= c2c_width;
2021 	fmt->collapse	= dim->se ? c2c_se_collapse : dim->cmp;
2022 	fmt->equal	= fmt_equal;
2023 	fmt->free	= fmt_free;
2024 
2025 	return c2c_fmt;
2026 }
2027 
2028 static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name,
2029 				  struct perf_env *env __maybe_unused)
2030 {
2031 	struct c2c_fmt *c2c_fmt = get_format(name);
2032 	int level = 0;
2033 
2034 	if (!c2c_fmt) {
2035 		reset_dimensions();
2036 		return output_field_add(hpp_list, name, &level);
2037 	}
2038 
2039 	perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
2040 	return 0;
2041 }
2042 
2043 static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name, struct perf_env *env)
2044 {
2045 	struct c2c_fmt *c2c_fmt = get_format(name);
2046 	struct c2c_dimension *dim;
2047 
2048 	if (!c2c_fmt) {
2049 		reset_dimensions();
2050 		return sort_dimension__add(hpp_list, name, /*evlist=*/NULL, env, /*level=*/0);
2051 	}
2052 
2053 	dim = c2c_fmt->dim;
2054 	if (dim == &dim_dso)
2055 		hpp_list->dso = 1;
2056 
2057 	if (dim == &dim_symbol || dim == &dim_iaddr)
2058 		hpp_list->sym = 1;
2059 
2060 	perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
2061 	return 0;
2062 }
2063 
2064 #define PARSE_LIST(_list, _fn)							\
2065 	do {									\
2066 		char *tmp, *tok;						\
2067 		ret = 0;							\
2068 										\
2069 		if (!_list)							\
2070 			break;							\
2071 										\
2072 		for (tok = strtok_r((char *)_list, ", ", &tmp);			\
2073 				tok; tok = strtok_r(NULL, ", ", &tmp)) {	\
2074 			ret = _fn(hpp_list, tok, env);				\
2075 			if (ret == -EINVAL) {					\
2076 				pr_err("Invalid --fields key: `%s'", tok);	\
2077 				break;						\
2078 			} else if (ret == -ESRCH) {				\
2079 				pr_err("Unknown --fields key: `%s'", tok);	\
2080 				break;						\
2081 			}							\
2082 		}								\
2083 	} while (0)
2084 
2085 static int hpp_list__parse(struct perf_hpp_list *hpp_list,
2086 			   const char *output_,
2087 			   const char *sort_,
2088 			   struct perf_env *env)
2089 {
2090 	char *output = output_ ? strdup(output_) : NULL;
2091 	char *sort   = sort_   ? strdup(sort_) : NULL;
2092 	int ret;
2093 
2094 	PARSE_LIST(output, c2c_hists__init_output);
2095 	PARSE_LIST(sort,   c2c_hists__init_sort);
2096 
2097 	/* copy sort keys to output fields */
2098 	perf_hpp__setup_output_field(hpp_list);
2099 
2100 	/*
2101 	 * We don't need other sorting keys other than those
2102 	 * we already specified. It also really slows down
2103 	 * the processing a lot with big number of output
2104 	 * fields, so switching this off for c2c.
2105 	 */
2106 
2107 #if 0
2108 	/* and then copy output fields to sort keys */
2109 	perf_hpp__append_sort_keys(&hists->list);
2110 #endif
2111 
2112 	free(output);
2113 	free(sort);
2114 	return ret;
2115 }
2116 
2117 static int c2c_hists__init(struct c2c_hists *hists,
2118 			   const char *sort,
2119 			   int nr_header_lines,
2120 			   struct perf_env *env)
2121 {
2122 	__hists__init(&hists->hists, &hists->list);
2123 
2124 	/*
2125 	 * Initialize only with sort fields, we need to resort
2126 	 * later anyway, and that's where we add output fields
2127 	 * as well.
2128 	 */
2129 	perf_hpp_list__init(&hists->list);
2130 
2131 	/* Overload number of header lines.*/
2132 	hists->list.nr_header_lines = nr_header_lines;
2133 
2134 	return hpp_list__parse(&hists->list, /*output=*/NULL, sort, env);
2135 }
2136 
2137 static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
2138 			     const char *output,
2139 			     const char *sort,
2140 			     struct perf_env *env)
2141 {
2142 	perf_hpp__reset_output_field(&c2c_hists->list);
2143 	return hpp_list__parse(&c2c_hists->list, output, sort, env);
2144 }
2145 
2146 #define DISPLAY_LINE_LIMIT  0.001
2147 
2148 static u8 filter_display(u32 val, u32 sum)
2149 {
2150 	if (sum == 0 || ((double)val / sum) < DISPLAY_LINE_LIMIT)
2151 		return HIST_FILTER__C2C;
2152 
2153 	return 0;
2154 }
2155 
2156 static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
2157 {
2158 	struct c2c_hist_entry *c2c_he;
2159 
2160 	if (c2c.show_all)
2161 		return true;
2162 
2163 	c2c_he = container_of(he, struct c2c_hist_entry, he);
2164 
2165 	switch (c2c.display) {
2166 	case DISPLAY_LCL_HITM:
2167 		he->filtered = filter_display(c2c_he->stats.lcl_hitm,
2168 					      stats->lcl_hitm);
2169 		break;
2170 	case DISPLAY_RMT_HITM:
2171 		he->filtered = filter_display(c2c_he->stats.rmt_hitm,
2172 					      stats->rmt_hitm);
2173 		break;
2174 	case DISPLAY_TOT_HITM:
2175 		he->filtered = filter_display(c2c_he->stats.tot_hitm,
2176 					      stats->tot_hitm);
2177 		break;
2178 	case DISPLAY_SNP_PEER:
2179 		he->filtered = filter_display(c2c_he->stats.tot_peer,
2180 					      stats->tot_peer);
2181 		break;
2182 	default:
2183 		break;
2184 	}
2185 
2186 	return he->filtered == 0;
2187 }
2188 
2189 static inline bool is_valid_hist_entry(struct hist_entry *he)
2190 {
2191 	struct c2c_hist_entry *c2c_he;
2192 	bool has_record = false;
2193 
2194 	c2c_he = container_of(he, struct c2c_hist_entry, he);
2195 
2196 	/* It's a valid entry if contains stores */
2197 	if (c2c_he->stats.store)
2198 		return true;
2199 
2200 	switch (c2c.display) {
2201 	case DISPLAY_LCL_HITM:
2202 		has_record = !!c2c_he->stats.lcl_hitm;
2203 		break;
2204 	case DISPLAY_RMT_HITM:
2205 		has_record = !!c2c_he->stats.rmt_hitm;
2206 		break;
2207 	case DISPLAY_TOT_HITM:
2208 		has_record = !!c2c_he->stats.tot_hitm;
2209 		break;
2210 	case DISPLAY_SNP_PEER:
2211 		has_record = !!c2c_he->stats.tot_peer;
2212 	default:
2213 		break;
2214 	}
2215 
2216 	return has_record;
2217 }
2218 
2219 static void set_node_width(struct c2c_hist_entry *c2c_he, int len)
2220 {
2221 	struct c2c_dimension *dim;
2222 
2223 	dim = &c2c.hists == c2c_he->hists ?
2224 	      &dim_dcacheline_node : &dim_offset_node;
2225 
2226 	if (len > dim->width)
2227 		dim->width = len;
2228 }
2229 
2230 static int set_nodestr(struct c2c_hist_entry *c2c_he)
2231 {
2232 	char buf[30];
2233 	int len;
2234 
2235 	if (c2c_he->nodestr)
2236 		return 0;
2237 
2238 	if (!bitmap_empty(c2c_he->nodeset, c2c.nodes_cnt)) {
2239 		len = bitmap_scnprintf(c2c_he->nodeset, c2c.nodes_cnt,
2240 				      buf, sizeof(buf));
2241 	} else {
2242 		len = scnprintf(buf, sizeof(buf), "N/A");
2243 	}
2244 
2245 	set_node_width(c2c_he, len);
2246 	c2c_he->nodestr = strdup(buf);
2247 	return c2c_he->nodestr ? 0 : -ENOMEM;
2248 }
2249 
2250 static void calc_width(struct c2c_hist_entry *c2c_he)
2251 {
2252 	struct c2c_hists *c2c_hists;
2253 
2254 	c2c_hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
2255 	hists__calc_col_len(&c2c_hists->hists, &c2c_he->he);
2256 	set_nodestr(c2c_he);
2257 }
2258 
2259 static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
2260 {
2261 	struct c2c_hist_entry *c2c_he;
2262 
2263 	c2c_he = container_of(he, struct c2c_hist_entry, he);
2264 
2265 	if (c2c.show_src && !he->srcline)
2266 		he->srcline = hist_entry__srcline(he);
2267 
2268 	calc_width(c2c_he);
2269 
2270 	if (!is_valid_hist_entry(he))
2271 		he->filtered = HIST_FILTER__C2C;
2272 
2273 	return 0;
2274 }
2275 
2276 static int resort_cl_cb(struct hist_entry *he, void *arg)
2277 {
2278 	struct perf_env *env = arg;
2279 	struct c2c_hist_entry *c2c_he;
2280 	struct c2c_hists *c2c_hists;
2281 	bool display = he__display(he, &c2c.shared_clines_stats);
2282 
2283 	c2c_he = container_of(he, struct c2c_hist_entry, he);
2284 	c2c_hists = c2c_he->hists;
2285 
2286 	if (display && c2c_hists) {
2287 		static unsigned int idx;
2288 
2289 		c2c_he->cacheline_idx = idx++;
2290 		calc_width(c2c_he);
2291 
2292 		c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort, env);
2293 
2294 		hists__collapse_resort(&c2c_hists->hists, NULL);
2295 		hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
2296 	}
2297 
2298 	return 0;
2299 }
2300 
2301 static struct c2c_header header_node_0 = HEADER_LOW("Node");
2302 static struct c2c_header header_node_1_hitms_stores =
2303 		HEADER_LOW("Node{cpus %hitms %stores}");
2304 static struct c2c_header header_node_1_peers_stores =
2305 		HEADER_LOW("Node{cpus %peers %stores}");
2306 static struct c2c_header header_node_2 = HEADER_LOW("Node{cpu list}");
2307 
2308 static void setup_nodes_header(void)
2309 {
2310 	switch (c2c.node_info) {
2311 	case 0:
2312 		dim_node.header = header_node_0;
2313 		break;
2314 	case 1:
2315 		if (c2c.display == DISPLAY_SNP_PEER)
2316 			dim_node.header = header_node_1_peers_stores;
2317 		else
2318 			dim_node.header = header_node_1_hitms_stores;
2319 		break;
2320 	case 2:
2321 		dim_node.header = header_node_2;
2322 		break;
2323 	default:
2324 		break;
2325 	}
2326 
2327 	return;
2328 }
2329 
2330 static int setup_nodes(struct perf_session *session)
2331 {
2332 	struct numa_node *n;
2333 	unsigned long **nodes;
2334 	struct perf_cpu cpu;
2335 	int *cpu2node;
2336 	struct perf_env *env = perf_session__env(session);
2337 
2338 	if (c2c.node_info > 2)
2339 		c2c.node_info = 2;
2340 
2341 	c2c.nodes_cnt = env->nr_numa_nodes;
2342 	c2c.cpus_cnt  = env->nr_cpus_avail;
2343 
2344 	n = env->numa_nodes;
2345 	if (!n)
2346 		return -EINVAL;
2347 
2348 	nodes = calloc(c2c.nodes_cnt, sizeof(unsigned long *));
2349 	if (!nodes)
2350 		return -ENOMEM;
2351 
2352 	c2c.nodes = nodes;
2353 
2354 	cpu2node = calloc(c2c.cpus_cnt, sizeof(int));
2355 	if (!cpu2node)
2356 		return -ENOMEM;
2357 
2358 	for (int idx = 0; idx < c2c.cpus_cnt; idx++)
2359 		cpu2node[idx] = -1;
2360 
2361 	c2c.cpu2node = cpu2node;
2362 
2363 	for (int node = 0; node < c2c.nodes_cnt; node++) {
2364 		struct perf_cpu_map *map = n[node].map;
2365 		unsigned long *set;
2366 		unsigned int idx;
2367 
2368 		set = bitmap_zalloc(c2c.cpus_cnt);
2369 		if (!set)
2370 			return -ENOMEM;
2371 
2372 		nodes[node] = set;
2373 
2374 		perf_cpu_map__for_each_cpu_skip_any(cpu, idx, map) {
2375 			/* topology CPU IDs from perf.data may exceed nr_cpus_avail */
2376 			if (cpu.cpu < 0 || cpu.cpu >= c2c.cpus_cnt)
2377 				continue;
2378 
2379 			__set_bit(cpu.cpu, set);
2380 
2381 			if (WARN_ONCE(cpu2node[cpu.cpu] != -1, "node/cpu topology bug"))
2382 				return -EINVAL;
2383 
2384 			cpu2node[cpu.cpu] = node;
2385 		}
2386 	}
2387 
2388 	setup_nodes_header();
2389 	return 0;
2390 }
2391 
2392 #define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
2393 #define HAS_PEER(__h) ((__h)->stats.lcl_peer || (__h)->stats.rmt_peer)
2394 
2395 static int resort_shared_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
2396 {
2397 	struct c2c_hist_entry *c2c_he;
2398 	c2c_he = container_of(he, struct c2c_hist_entry, he);
2399 
2400 	if (HAS_HITMS(c2c_he) || HAS_PEER(c2c_he)) {
2401 		c2c.shared_clines++;
2402 		c2c_add_stats(&c2c.shared_clines_stats, &c2c_he->stats);
2403 	}
2404 
2405 	return 0;
2406 }
2407 
2408 static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb, void *arg)
2409 {
2410 	struct rb_node *next = rb_first_cached(&hists->entries);
2411 	int ret = 0;
2412 
2413 	while (next) {
2414 		struct hist_entry *he;
2415 
2416 		he = rb_entry(next, struct hist_entry, rb_node);
2417 		ret = cb(he, arg);
2418 		if (ret)
2419 			break;
2420 		next = rb_next(&he->rb_node);
2421 	}
2422 
2423 	return ret;
2424 }
2425 
2426 static void print_c2c__display_stats(FILE *out)
2427 {
2428 	int llc_misses;
2429 	struct c2c_stats *stats = &c2c.hists.stats;
2430 
2431 	llc_misses = get_load_llc_misses(stats);
2432 
2433 	fprintf(out, "=================================================\n");
2434 	fprintf(out, "            Trace Event Information              \n");
2435 	fprintf(out, "=================================================\n");
2436 	fprintf(out, "  Total records                     : %10d\n", stats->nr_entries);
2437 	fprintf(out, "  Locked Load/Store Operations      : %10d\n", stats->locks);
2438 	fprintf(out, "  Load Operations                   : %10d\n", stats->load);
2439 	fprintf(out, "  Loads - uncacheable               : %10d\n", stats->ld_uncache);
2440 	fprintf(out, "  Loads - IO                        : %10d\n", stats->ld_io);
2441 	fprintf(out, "  Loads - Miss                      : %10d\n", stats->ld_miss);
2442 	fprintf(out, "  Loads - no mapping                : %10d\n", stats->ld_noadrs);
2443 	fprintf(out, "  Load Fill Buffer Hit              : %10d\n", stats->ld_fbhit);
2444 	fprintf(out, "  Load L1D hit                      : %10d\n", stats->ld_l1hit);
2445 	fprintf(out, "  Load L2D hit                      : %10d\n", stats->ld_l2hit);
2446 	fprintf(out, "  Load LLC hit                      : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2447 	fprintf(out, "  Load Local HITM                   : %10d\n", stats->lcl_hitm);
2448 	fprintf(out, "  Load Remote HITM                  : %10d\n", stats->rmt_hitm);
2449 	fprintf(out, "  Load Remote HIT                   : %10d\n", stats->rmt_hit);
2450 	fprintf(out, "  Load Local DRAM                   : %10d\n", stats->lcl_dram);
2451 	fprintf(out, "  Load Remote DRAM                  : %10d\n", stats->rmt_dram);
2452 	fprintf(out, "  Load MESI State Exclusive         : %10d\n", stats->ld_excl);
2453 	fprintf(out, "  Load MESI State Shared            : %10d\n", stats->ld_shared);
2454 	fprintf(out, "  Load LLC Misses                   : %10d\n", llc_misses);
2455 	fprintf(out, "  Load access blocked by data       : %10d\n", stats->blk_data);
2456 	fprintf(out, "  Load access blocked by address    : %10d\n", stats->blk_addr);
2457 	fprintf(out, "  Load HIT Local Peer               : %10d\n", stats->lcl_peer);
2458 	fprintf(out, "  Load HIT Remote Peer              : %10d\n", stats->rmt_peer);
2459 	fprintf(out, "  LLC Misses to Local DRAM          : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);
2460 	fprintf(out, "  LLC Misses to Remote DRAM         : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);
2461 	fprintf(out, "  LLC Misses to Remote cache (HIT)  : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.);
2462 	fprintf(out, "  LLC Misses to Remote cache (HITM) : %10.1f%%\n", ((double)stats->rmt_hitm/(double)llc_misses) * 100.);
2463 	fprintf(out, "  Store Operations                  : %10d\n", stats->store);
2464 	fprintf(out, "  Store - uncacheable               : %10d\n", stats->st_uncache);
2465 	fprintf(out, "  Store - no mapping                : %10d\n", stats->st_noadrs);
2466 	fprintf(out, "  Store L1D Hit                     : %10d\n", stats->st_l1hit);
2467 	fprintf(out, "  Store L1D Miss                    : %10d\n", stats->st_l1miss);
2468 	fprintf(out, "  Store No available memory level   : %10d\n", stats->st_na);
2469 	fprintf(out, "  No Page Map Rejects               : %10d\n", stats->nomap);
2470 	fprintf(out, "  Unable to parse data source       : %10d\n", stats->noparse);
2471 }
2472 
2473 static void print_shared_cacheline_info(FILE *out)
2474 {
2475 	struct c2c_stats *stats = &c2c.shared_clines_stats;
2476 	int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
2477 
2478 	fprintf(out, "=================================================\n");
2479 	fprintf(out, "    Global Shared Cache Line Event Information   \n");
2480 	fprintf(out, "=================================================\n");
2481 	fprintf(out, "  Total Shared Cache Lines          : %10d\n", c2c.shared_clines);
2482 	fprintf(out, "  Load HITs on shared lines         : %10d\n", stats->load);
2483 	fprintf(out, "  Fill Buffer Hits on shared lines  : %10d\n", stats->ld_fbhit);
2484 	fprintf(out, "  L1D hits on shared lines          : %10d\n", stats->ld_l1hit);
2485 	fprintf(out, "  L2D hits on shared lines          : %10d\n", stats->ld_l2hit);
2486 	fprintf(out, "  LLC hits on shared lines          : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2487 	fprintf(out, "  Load hits on peer cache or nodes  : %10d\n", stats->lcl_peer + stats->rmt_peer);
2488 	fprintf(out, "  Locked Access on shared lines     : %10d\n", stats->locks);
2489 	fprintf(out, "  Blocked Access on shared lines    : %10d\n", stats->blk_data + stats->blk_addr);
2490 	fprintf(out, "  Store HITs on shared lines        : %10d\n", stats->store);
2491 	fprintf(out, "  Store L1D hits on shared lines    : %10d\n", stats->st_l1hit);
2492 	fprintf(out, "  Store No available memory level   : %10d\n", stats->st_na);
2493 	fprintf(out, "  Total Merged records              : %10d\n", hitm_cnt + stats->store);
2494 }
2495 
2496 static void print_cacheline(struct c2c_hists *c2c_hists,
2497 			    struct hist_entry *he_cl,
2498 			    struct perf_hpp_list *hpp_list,
2499 			    FILE *out)
2500 {
2501 	char bf[1000];
2502 	struct perf_hpp hpp = {
2503 		.buf            = bf,
2504 		.size           = 1000,
2505 	};
2506 	static bool once;
2507 
2508 	if (!once) {
2509 		hists__fprintf_headers(&c2c_hists->hists, out);
2510 		once = true;
2511 	} else {
2512 		fprintf(out, "\n");
2513 	}
2514 
2515 	fprintf(out, "  ----------------------------------------------------------------------\n");
2516 	__hist_entry__snprintf(he_cl, &hpp, hpp_list);
2517 	fprintf(out, "%s\n", bf);
2518 	fprintf(out, "  ----------------------------------------------------------------------\n");
2519 
2520 	hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, false);
2521 }
2522 
2523 static void print_pareto(FILE *out, struct perf_env *env)
2524 {
2525 	struct perf_hpp_list hpp_list;
2526 	struct rb_node *nd;
2527 	int ret;
2528 	const char *cl_output;
2529 
2530 	if (c2c.display != DISPLAY_SNP_PEER)
2531 		cl_output = "cl_num,"
2532 			    "cl_rmt_hitm,"
2533 			    "cl_lcl_hitm,"
2534 			    "cl_stores_l1hit,"
2535 			    "cl_stores_l1miss,"
2536 			    "cl_stores_na,"
2537 			    "dcacheline";
2538 	else
2539 		cl_output = "cl_num,"
2540 			    "cl_rmt_peer,"
2541 			    "cl_lcl_peer,"
2542 			    "cl_stores_l1hit,"
2543 			    "cl_stores_l1miss,"
2544 			    "cl_stores_na,"
2545 			    "dcacheline";
2546 
2547 	perf_hpp_list__init(&hpp_list);
2548 	ret = hpp_list__parse(&hpp_list, cl_output, /*evlist=*/NULL, env);
2549 
2550 	if (WARN_ONCE(ret, "failed to setup sort entries\n"))
2551 		return;
2552 
2553 	nd = rb_first_cached(&c2c.hists.hists.entries);
2554 
2555 	for (; nd; nd = rb_next(nd)) {
2556 		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2557 		struct c2c_hist_entry *c2c_he;
2558 
2559 		if (he->filtered)
2560 			continue;
2561 
2562 		c2c_he = container_of(he, struct c2c_hist_entry, he);
2563 		print_cacheline(c2c_he->hists, he, &hpp_list, out);
2564 	}
2565 }
2566 
2567 static void print_c2c_info(FILE *out, struct perf_session *session)
2568 {
2569 	struct evlist *evlist = session->evlist;
2570 	struct evsel *evsel;
2571 	bool first = true;
2572 
2573 	fprintf(out, "=================================================\n");
2574 	fprintf(out, "                 c2c details                     \n");
2575 	fprintf(out, "=================================================\n");
2576 
2577 	evlist__for_each_entry(evlist, evsel) {
2578 		fprintf(out, "%-36s: %s\n", first ? "  Events" : "", evsel__name(evsel));
2579 		first = false;
2580 	}
2581 	fprintf(out, "  Cachelines sort on                : %s\n",
2582 		display_str[c2c.display]);
2583 	fprintf(out, "  Cacheline data grouping           : %s\n", c2c.cl_sort);
2584 }
2585 
2586 static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
2587 {
2588 	setup_pager();
2589 
2590 	print_c2c__display_stats(out);
2591 	fprintf(out, "\n");
2592 	print_shared_cacheline_info(out);
2593 	fprintf(out, "\n");
2594 	print_c2c_info(out, session);
2595 
2596 	if (c2c.stats_only)
2597 		return;
2598 
2599 	fprintf(out, "\n");
2600 	fprintf(out, "=================================================\n");
2601 	fprintf(out, "           Shared Data Cache Line Table          \n");
2602 	fprintf(out, "=================================================\n");
2603 	fprintf(out, "#\n");
2604 
2605 	hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, true);
2606 
2607 	fprintf(out, "\n");
2608 	fprintf(out, "=================================================\n");
2609 	fprintf(out, "      Shared Cache Line Distribution Pareto      \n");
2610 	fprintf(out, "=================================================\n");
2611 	fprintf(out, "#\n");
2612 
2613 	print_pareto(out, perf_session__env(session));
2614 }
2615 
2616 #ifdef HAVE_SLANG_SUPPORT
2617 
2618 static int perf_c2c__toggle_annotation(struct hist_browser *browser)
2619 {
2620 	struct hist_entry *he = browser->he_selection;
2621 	struct symbol *sym = NULL;
2622 	struct annotated_source *src = NULL;
2623 	struct c2c_hist_entry *c2c_he = NULL;
2624 	u64 al_addr = NO_ADDR;
2625 
2626 	if (!perf_c2c__has_annotation(he->hists->hpp_list)) {
2627 		ui_browser__help_window(&browser->b, "No annotation support");
2628 		return 0;
2629 	}
2630 
2631 	if (he == NULL) {
2632 		ui_browser__help_window(&browser->b, "No entry selected for annotation");
2633 		return 0;
2634 	}
2635 
2636 	sym = he->ms.sym;
2637 	if (sym == NULL) {
2638 		ui_browser__help_window(&browser->b, "Can not annotate, no symbol found");
2639 		return 0;
2640 	}
2641 
2642 	src = symbol__hists(sym, 0);
2643 	if (src == NULL) {
2644 		ui_browser__help_window(&browser->b, "Failed to initialize annotation source");
2645 		return 0;
2646 	}
2647 
2648 	if (he->mem_info)
2649 		al_addr = mem_info__iaddr(he->mem_info)->al_addr;
2650 
2651 	c2c_he = container_of(he, struct c2c_hist_entry, he);
2652 	return hist_entry__tui_annotate(he, c2c_he->evsel, NULL, al_addr);
2653 }
2654 
2655 static void c2c_browser__update_nr_entries(struct hist_browser *hb)
2656 {
2657 	u64 nr_entries = 0;
2658 	struct rb_node *nd = rb_first_cached(&hb->hists->entries);
2659 
2660 	while (nd) {
2661 		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2662 
2663 		if (!he->filtered)
2664 			nr_entries++;
2665 
2666 		nd = rb_next(nd);
2667 	}
2668 
2669 	hb->nr_non_filtered_entries = nr_entries;
2670 }
2671 
2672 struct c2c_cacheline_browser {
2673 	struct hist_browser	 hb;
2674 	struct hist_entry	*he;
2675 };
2676 
2677 static int
2678 perf_c2c_cacheline_browser__title(struct hist_browser *browser,
2679 				  char *bf, size_t size)
2680 {
2681 	struct c2c_cacheline_browser *cl_browser;
2682 	struct hist_entry *he;
2683 	uint64_t addr = 0;
2684 
2685 	cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
2686 	he = cl_browser->he;
2687 
2688 	if (he->mem_info)
2689 		addr = cl_address(mem_info__daddr(he->mem_info)->addr, chk_double_cl);
2690 
2691 	scnprintf(bf, size, "Cacheline 0x%lx", addr);
2692 	return 0;
2693 }
2694 
2695 static struct c2c_cacheline_browser*
2696 c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
2697 {
2698 	struct c2c_cacheline_browser *browser;
2699 
2700 	browser = zalloc(sizeof(*browser));
2701 	if (browser) {
2702 		hist_browser__init(&browser->hb, hists);
2703 		browser->hb.c2c_filter	= true;
2704 		browser->hb.title	= perf_c2c_cacheline_browser__title;
2705 		browser->he		= he;
2706 	}
2707 
2708 	return browser;
2709 }
2710 
2711 static int perf_c2c__browse_cacheline(struct hist_entry *he)
2712 {
2713 	struct c2c_hist_entry *c2c_he;
2714 	struct c2c_hists *c2c_hists;
2715 	struct c2c_cacheline_browser *cl_browser;
2716 	struct hist_browser *browser;
2717 	int key = -1;
2718 	static const char help[] =
2719 	" ENTER         Toggle callchains (if present) \n"
2720 	" n             Toggle Node details info \n"
2721 	" s             Toggle full length of symbol and source line columns \n"
2722 	" a             Toggle annotation view \n"
2723 	" q             Return back to cacheline list \n";
2724 
2725 	if (!he)
2726 		return 0;
2727 
2728 	/* Display compact version first. */
2729 	c2c.symbol_full = false;
2730 
2731 	c2c_he = container_of(he, struct c2c_hist_entry, he);
2732 	c2c_hists = c2c_he->hists;
2733 
2734 	cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
2735 	if (cl_browser == NULL)
2736 		return -1;
2737 
2738 	browser = &cl_browser->hb;
2739 
2740 	/* reset abort key so that it can get Ctrl-C as a key */
2741 	SLang_reset_tty();
2742 	SLang_init_tty(0, 0, 0);
2743 
2744 	c2c_browser__update_nr_entries(browser);
2745 
2746 	while (1) {
2747 		key = hist_browser__run(browser, "? - help", true, 0);
2748 
2749 		switch (key) {
2750 		case 's':
2751 			c2c.symbol_full = !c2c.symbol_full;
2752 			break;
2753 		case 'n':
2754 			c2c.node_info = (c2c.node_info + 1) % 3;
2755 			setup_nodes_header();
2756 			break;
2757 		case 'a':
2758 			perf_c2c__toggle_annotation(browser);
2759 			break;
2760 		case 'q':
2761 			goto out;
2762 		case '?':
2763 			ui_browser__help_window(&browser->b, help);
2764 			break;
2765 		default:
2766 			break;
2767 		}
2768 	}
2769 
2770 out:
2771 	free(cl_browser);
2772 	return 0;
2773 }
2774 
2775 static int perf_c2c_browser__title(struct hist_browser *browser,
2776 				   char *bf, size_t size)
2777 {
2778 	scnprintf(bf, size,
2779 		  "Shared Data Cache Line Table     "
2780 		  "(%lu entries, sorted on %s)",
2781 		  browser->nr_non_filtered_entries,
2782 		  display_str[c2c.display]);
2783 	return 0;
2784 }
2785 
2786 static struct hist_browser*
2787 perf_c2c_browser__new(struct hists *hists)
2788 {
2789 	struct hist_browser *browser = hist_browser__new(hists);
2790 
2791 	if (browser) {
2792 		browser->title = perf_c2c_browser__title;
2793 		browser->c2c_filter = true;
2794 	}
2795 
2796 	return browser;
2797 }
2798 
2799 static int perf_c2c__hists_browse(struct hists *hists)
2800 {
2801 	struct hist_browser *browser;
2802 	int key = -1;
2803 	static const char help[] =
2804 	" d             Display cacheline details \n"
2805 	" ENTER         Toggle callchains (if present) \n"
2806 	" q             Quit \n";
2807 
2808 	browser = perf_c2c_browser__new(hists);
2809 	if (browser == NULL)
2810 		return -1;
2811 
2812 	/* reset abort key so that it can get Ctrl-C as a key */
2813 	SLang_reset_tty();
2814 	SLang_init_tty(0, 0, 0);
2815 
2816 	c2c_browser__update_nr_entries(browser);
2817 
2818 	while (1) {
2819 		key = hist_browser__run(browser, "? - help", true, 0);
2820 
2821 		switch (key) {
2822 		case 'q':
2823 			goto out;
2824 		case 'd':
2825 			perf_c2c__browse_cacheline(browser->he_selection);
2826 			break;
2827 		case '?':
2828 			ui_browser__help_window(&browser->b, help);
2829 			break;
2830 		default:
2831 			break;
2832 		}
2833 	}
2834 
2835 out:
2836 	hist_browser__delete(browser);
2837 	return 0;
2838 }
2839 
2840 static void perf_c2c_display(struct perf_session *session)
2841 {
2842 	if (use_browser == 0)
2843 		perf_c2c__hists_fprintf(stdout, session);
2844 	else
2845 		perf_c2c__hists_browse(&c2c.hists.hists);
2846 }
2847 #else
2848 static void perf_c2c_display(struct perf_session *session)
2849 {
2850 	use_browser = 0;
2851 	perf_c2c__hists_fprintf(stdout, session);
2852 }
2853 #endif /* HAVE_SLANG_SUPPORT */
2854 
2855 static char *fill_line(const char *orig, int len)
2856 {
2857 	int i, j, olen = strlen(orig);
2858 	char *buf;
2859 
2860 	buf = zalloc(len + 1);
2861 	if (!buf)
2862 		return NULL;
2863 
2864 	j = len / 2 - olen / 2;
2865 
2866 	for (i = 0; i < j - 1; i++)
2867 		buf[i] = '-';
2868 
2869 	buf[i++] = ' ';
2870 
2871 	strcpy(buf + i, orig);
2872 
2873 	i += olen;
2874 
2875 	buf[i++] = ' ';
2876 
2877 	for (; i < len; i++)
2878 		buf[i] = '-';
2879 
2880 	return buf;
2881 }
2882 
2883 static int ui_quirks(void)
2884 {
2885 	const char *nodestr = "Data address";
2886 	char *buf;
2887 
2888 	if (!c2c.use_stdio) {
2889 		dim_offset.width  = 5;
2890 		dim_offset.header = header_offset_tui;
2891 		nodestr = chk_double_cl ? "Double-CL" : "CL";
2892 	}
2893 
2894 	dim_percent_costly_snoop.header = percent_costly_snoop_header[c2c.display];
2895 
2896 	/* Fix the zero line for dcacheline column. */
2897 	buf = fill_line(chk_double_cl ? "Double-Cacheline" : "Cacheline",
2898 				dim_dcacheline.width +
2899 				dim_dcacheline_node.width +
2900 				dim_dcacheline_count.width + 4);
2901 	if (!buf)
2902 		return -ENOMEM;
2903 
2904 	dim_dcacheline.header.line[0].text = buf;
2905 
2906 	/* Fix the zero line for offset column. */
2907 	buf = fill_line(nodestr, dim_offset.width +
2908 			         dim_offset_node.width +
2909 				 dim_dcacheline_count.width + 4);
2910 	if (!buf)
2911 		return -ENOMEM;
2912 
2913 	dim_offset.header.line[0].text = buf;
2914 
2915 	return 0;
2916 }
2917 
2918 #define CALLCHAIN_DEFAULT_OPT  "graph,0.5,caller,function,percent"
2919 
2920 static const char callchain_help[] =
2921 	"Display call graph (stack chain/backtrace):\n\n"
2922 	CALLCHAIN_REPORT_HELP
2923 	"\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
2924 
2925 static int
2926 parse_callchain_opt(const struct option *opt, const char *arg, int unset)
2927 {
2928 	struct callchain_param *callchain = opt->value;
2929 
2930 	callchain->enabled = !unset;
2931 	/*
2932 	 * --no-call-graph
2933 	 */
2934 	if (unset) {
2935 		symbol_conf.use_callchain = false;
2936 		callchain->mode = CHAIN_NONE;
2937 		return 0;
2938 	}
2939 
2940 	return parse_callchain_report_opt(arg);
2941 }
2942 
2943 static int setup_callchain(struct evlist *evlist)
2944 {
2945 	u64 sample_type = evlist__combined_sample_type(evlist);
2946 	enum perf_call_graph_mode mode = CALLCHAIN_NONE;
2947 
2948 	if ((sample_type & PERF_SAMPLE_REGS_USER) &&
2949 	    (sample_type & PERF_SAMPLE_STACK_USER)) {
2950 		mode = CALLCHAIN_DWARF;
2951 		dwarf_callchain_users = true;
2952 	} else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
2953 		mode = CALLCHAIN_LBR;
2954 	else if (sample_type & PERF_SAMPLE_CALLCHAIN)
2955 		mode = CALLCHAIN_FP;
2956 
2957 	if (!callchain_param.enabled &&
2958 	    callchain_param.mode != CHAIN_NONE &&
2959 	    mode != CALLCHAIN_NONE) {
2960 		symbol_conf.use_callchain = true;
2961 		if (callchain_register_param(&callchain_param) < 0) {
2962 			ui__error("Can't register callchain params.\n");
2963 			return -EINVAL;
2964 		}
2965 	}
2966 
2967 	if (c2c.stitch_lbr && (mode != CALLCHAIN_LBR)) {
2968 		ui__warning("Can't find LBR callchain. Switch off --stitch-lbr.\n"
2969 			    "Please apply --call-graph lbr when recording.\n");
2970 		c2c.stitch_lbr = false;
2971 	}
2972 
2973 	callchain_param.record_mode = mode;
2974 	callchain_param.min_percent = 0;
2975 	return 0;
2976 }
2977 
2978 static int setup_display(const char *str)
2979 {
2980 	const char *display = str;
2981 
2982 	if (!strcmp(display, "tot"))
2983 		c2c.display = DISPLAY_TOT_HITM;
2984 	else if (!strcmp(display, "rmt"))
2985 		c2c.display = DISPLAY_RMT_HITM;
2986 	else if (!strcmp(display, "lcl"))
2987 		c2c.display = DISPLAY_LCL_HITM;
2988 	else if (!strcmp(display, "peer"))
2989 		c2c.display = DISPLAY_SNP_PEER;
2990 	else {
2991 		pr_err("failed: unknown display type: %s\n", str);
2992 		return -1;
2993 	}
2994 
2995 	return 0;
2996 }
2997 
2998 #define for_each_token(__tok, __buf, __sep, __tmp)		\
2999 	for (__tok = strtok_r(__buf, __sep, &__tmp); __tok;	\
3000 	     __tok = strtok_r(NULL,  __sep, &__tmp))
3001 
3002 static int build_cl_output(char *cl_sort, bool no_source)
3003 {
3004 	char *tok, *tmp, *buf = strdup(cl_sort);
3005 	bool add_pid   = false;
3006 	bool add_tid   = false;
3007 	bool add_iaddr = false;
3008 	bool add_sym   = false;
3009 	bool add_dso   = false;
3010 	bool add_src   = false;
3011 	int ret = 0;
3012 
3013 	if (!buf)
3014 		return -ENOMEM;
3015 
3016 	for_each_token(tok, buf, ",", tmp) {
3017 		if (!strcmp(tok, "tid")) {
3018 			add_tid = true;
3019 		} else if (!strcmp(tok, "pid")) {
3020 			add_pid = true;
3021 		} else if (!strcmp(tok, "iaddr")) {
3022 			add_iaddr = true;
3023 			add_sym   = true;
3024 			add_dso   = true;
3025 			add_src   = no_source ? false : true;
3026 		} else if (!strcmp(tok, "dso")) {
3027 			add_dso = true;
3028 		} else if (strcmp(tok, "offset")) {
3029 			pr_err("unrecognized sort token: %s\n", tok);
3030 			ret = -EINVAL;
3031 			goto err;
3032 		}
3033 	}
3034 
3035 	if (asprintf(&c2c.cl_output,
3036 		"%s%s%s%s%s%s%s%s%s%s%s%s",
3037 		c2c.use_stdio ? "cl_num_empty," : "",
3038 		c2c.display == DISPLAY_SNP_PEER ? "percent_rmt_peer,"
3039 						  "percent_lcl_peer," :
3040 						  "percent_rmt_hitm,"
3041 						  "percent_lcl_hitm,",
3042 		"percent_stores_l1hit,"
3043 		"percent_stores_l1miss,"
3044 		"percent_stores_na,"
3045 		"offset,offset_node,dcacheline_count,",
3046 		add_pid   ? "pid," : "",
3047 		add_tid   ? "tid," : "",
3048 		add_iaddr ? "iaddr," : "",
3049 		c2c.display == DISPLAY_SNP_PEER ? "mean_rmt_peer,"
3050 						  "mean_lcl_peer," :
3051 						  "mean_rmt,"
3052 						  "mean_lcl,",
3053 		"mean_load,"
3054 		"tot_recs,"
3055 		"cpucnt,",
3056 		add_sym ? "symbol," : "",
3057 		add_dso ? "dso," : "",
3058 		add_src ? "cl_srcline," : "",
3059 		"node") < 0) {
3060 		ret = -ENOMEM;
3061 		goto err;
3062 	}
3063 
3064 	c2c.show_src = add_src;
3065 err:
3066 	free(buf);
3067 	return ret;
3068 }
3069 
3070 static int setup_coalesce(const char *coalesce, bool no_source)
3071 {
3072 	const char *c = coalesce ?: coalesce_default;
3073 	const char *sort_str = NULL;
3074 
3075 	if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)
3076 		return -ENOMEM;
3077 
3078 	if (build_cl_output(c2c.cl_sort, no_source))
3079 		return -1;
3080 
3081 	if (c2c.display == DISPLAY_TOT_HITM)
3082 		sort_str = "tot_hitm";
3083 	else if (c2c.display == DISPLAY_RMT_HITM)
3084 		sort_str = "rmt_hitm,lcl_hitm";
3085 	else if (c2c.display == DISPLAY_LCL_HITM)
3086 		sort_str = "lcl_hitm,rmt_hitm";
3087 	else if (c2c.display == DISPLAY_SNP_PEER)
3088 		sort_str = "tot_peer";
3089 
3090 	if (asprintf(&c2c.cl_resort, "offset,%s", sort_str) < 0)
3091 		return -ENOMEM;
3092 
3093 	pr_debug("coalesce sort   fields: %s\n", c2c.cl_sort);
3094 	pr_debug("coalesce resort fields: %s\n", c2c.cl_resort);
3095 	pr_debug("coalesce output fields: %s\n", c2c.cl_output);
3096 	return 0;
3097 }
3098 
3099 static int perf_c2c__report(int argc, const char **argv)
3100 {
3101 	struct itrace_synth_opts itrace_synth_opts = {
3102 		.set = true,
3103 		.mem = true,	/* Only enable memory event */
3104 		.default_no_sample = true,
3105 	};
3106 
3107 	struct perf_session *session;
3108 	struct ui_progress prog;
3109 	struct perf_data data = {
3110 		.mode = PERF_DATA_MODE_READ,
3111 	};
3112 	char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
3113 	const char *display = NULL;
3114 	const char *coalesce = NULL;
3115 	bool no_source = false;
3116 	const char *disassembler_style = NULL, *objdump_path = NULL;
3117 	const struct option options[] = {
3118 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
3119 		   "file", "vmlinux pathname"),
3120 	OPT_STRING('i', "input", &input_name, "file",
3121 		   "the input file to process"),
3122 	OPT_INCR('N', "node-info", &c2c.node_info,
3123 		 "show extra node info in report (repeat for more info)"),
3124 	OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
3125 	OPT_BOOLEAN(0, "stats", &c2c.stats_only,
3126 		    "Display only statistic tables (implies --stdio)"),
3127 	OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
3128 		    "Display full length of symbols"),
3129 	OPT_BOOLEAN(0, "no-source", &no_source,
3130 		    "Do not display Source Line column"),
3131 	OPT_BOOLEAN(0, "show-all", &c2c.show_all,
3132 		    "Show all captured HITM lines."),
3133 	OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
3134 			     "print_type,threshold[,print_limit],order,sort_key[,branch],value",
3135 			     callchain_help, &parse_callchain_opt,
3136 			     callchain_default_opt),
3137 	OPT_STRING('d', "display", &display, "Switch HITM output type", "tot,lcl,rmt,peer"),
3138 	OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
3139 		   "coalesce fields: pid,tid,iaddr,dso"),
3140 	OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
3141 	OPT_BOOLEAN(0, "stitch-lbr", &c2c.stitch_lbr,
3142 		    "Enable LBR callgraph stitching approach"),
3143 	OPT_BOOLEAN(0, "double-cl", &chk_double_cl, "Detect adjacent cacheline false sharing"),
3144 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
3145 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
3146 	OPT_STRING(0, "objdump", &objdump_path, "path",
3147 		   "objdump binary to use for disassembly and annotations"),
3148 	OPT_PARENT(c2c_options),
3149 	OPT_END()
3150 	};
3151 	int err = 0;
3152 	const char *output_str, *sort_str = NULL;
3153 	struct perf_env *env;
3154 
3155 	annotation_options__init();
3156 
3157 	err = hists__init();
3158 	if (err < 0)
3159 		goto out;
3160 
3161 	argc = parse_options(argc, argv, options, report_c2c_usage,
3162 			     PARSE_OPT_STOP_AT_NON_OPTION);
3163 	if (argc)
3164 		usage_with_options(report_c2c_usage, options);
3165 
3166 #ifndef HAVE_SLANG_SUPPORT
3167 	c2c.use_stdio = true;
3168 #endif
3169 
3170 	if (c2c.stats_only)
3171 		c2c.use_stdio = true;
3172 
3173 	/**
3174 	 * Annotation related options disassembler_style, objdump_path are set
3175 	 * in the c2c_options, so we can use them here.
3176 	 */
3177 	if (disassembler_style) {
3178 		annotate_opts.disassembler_style = strdup(disassembler_style);
3179 		if (!annotate_opts.disassembler_style) {
3180 			err = -ENOMEM;
3181 			pr_err("Failed to allocate memory for annotation options\n");
3182 			goto out;
3183 		}
3184 	}
3185 	if (objdump_path) {
3186 		annotate_opts.objdump_path = strdup(objdump_path);
3187 		if (!annotate_opts.objdump_path) {
3188 			err = -ENOMEM;
3189 			pr_err("Failed to allocate memory for annotation options\n");
3190 			goto out;
3191 		}
3192 	}
3193 
3194 	err = symbol__validate_sym_arguments();
3195 	if (err)
3196 		goto out;
3197 
3198 	if (!input_name || !strlen(input_name))
3199 		input_name = "perf.data";
3200 
3201 	data.path  = input_name;
3202 	data.force = symbol_conf.force;
3203 
3204 	perf_tool__init(&c2c.tool, /*ordered_events=*/true);
3205 	c2c.tool.sample		= process_sample_event;
3206 	c2c.tool.mmap		= perf_event__process_mmap;
3207 	c2c.tool.mmap2		= perf_event__process_mmap2;
3208 	c2c.tool.comm		= perf_event__process_comm;
3209 	c2c.tool.exit		= perf_event__process_exit;
3210 	c2c.tool.fork		= perf_event__process_fork;
3211 	c2c.tool.lost		= perf_event__process_lost;
3212 	c2c.tool.attr		= perf_event__process_attr;
3213 	c2c.tool.auxtrace_info  = perf_event__process_auxtrace_info;
3214 	c2c.tool.auxtrace       = perf_event__process_auxtrace;
3215 	c2c.tool.auxtrace_error = perf_event__process_auxtrace_error;
3216 	c2c.tool.ordering_requires_timestamps = true;
3217 	session = perf_session__new(&data, &c2c.tool);
3218 	if (IS_ERR(session)) {
3219 		err = PTR_ERR(session);
3220 		pr_debug("Error creating perf session\n");
3221 		goto out;
3222 	}
3223 	env = perf_session__env(session);
3224 	/*
3225 	 * Use the 'tot' as default display type if user doesn't specify it;
3226 	 * since Arm64 platform doesn't support HITMs flag, use 'peer' as the
3227 	 * default display type.
3228 	 */
3229 	if (!display) {
3230 		if (perf_env__e_machine(env, /*e_flags=*/NULL) == EM_AARCH64)
3231 			display = "peer";
3232 		else
3233 			display = "tot";
3234 	}
3235 
3236 	err = setup_display(display);
3237 	if (err)
3238 		goto out_session;
3239 
3240 	err = setup_coalesce(coalesce, no_source);
3241 	if (err) {
3242 		pr_debug("Failed to initialize hists\n");
3243 		goto out_session;
3244 	}
3245 
3246 	err = c2c_hists__init(&c2c.hists, "dcacheline", 2, perf_session__env(session));
3247 	if (err) {
3248 		pr_debug("Failed to initialize hists\n");
3249 		goto out_session;
3250 	}
3251 
3252 	session->itrace_synth_opts = &itrace_synth_opts;
3253 
3254 	err = setup_nodes(session);
3255 	if (err) {
3256 		pr_err("Failed setup nodes\n");
3257 		goto out_session;
3258 	}
3259 
3260 	err = mem2node__init(&c2c.mem2node, env);
3261 	if (err)
3262 		goto out_session;
3263 
3264 	err = setup_callchain(session->evlist);
3265 	if (err)
3266 		goto out_mem2node;
3267 
3268 	if (c2c.use_stdio)
3269 		use_browser = 0;
3270 	else
3271 		use_browser = 1;
3272 
3273 	/*
3274 	 * Only in the TUI browser we are doing integrated annotation,
3275 	 * so don't allocate extra space that won't be used in the stdio
3276 	 * implementation.
3277 	 */
3278 	if (perf_c2c__has_annotation(NULL)) {
3279 		int ret = symbol__annotation_init();
3280 
3281 		if (ret < 0)
3282 			goto out_mem2node;
3283 		/*
3284 		 * For searching by name on the "Browse map details".
3285 		 * providing it only in verbose mode not to bloat too
3286 		 * much struct symbol.
3287 		 */
3288 		if (verbose > 0) {
3289 			/*
3290 			 * XXX: Need to provide a less kludgy way to ask for
3291 			 * more space per symbol, the u32 is for the index on
3292 			 * the ui browser.
3293 			 * See symbol__browser_index.
3294 			 */
3295 			symbol_conf.priv_size += sizeof(u32);
3296 		}
3297 		annotation_config__init();
3298 	}
3299 
3300 	if (symbol__init(env) < 0)
3301 		goto out_mem2node;
3302 
3303 	/* No pipe support at the moment. */
3304 	if (perf_data__is_pipe(session->data)) {
3305 		pr_debug("No pipe support at the moment.\n");
3306 		goto out_mem2node;
3307 	}
3308 
3309 	setup_browser(false);
3310 
3311 	err = perf_session__process_events(session);
3312 	if (err) {
3313 		pr_err("failed to process sample\n");
3314 		goto out_mem2node;
3315 	}
3316 
3317 	if (c2c.display != DISPLAY_SNP_PEER)
3318 		output_str = "cl_idx,"
3319 			     "dcacheline,"
3320 			     "dcacheline_node,"
3321 			     "dcacheline_count,"
3322 			     "percent_costly_snoop,"
3323 			     "tot_hitm,lcl_hitm,rmt_hitm,"
3324 			     "tot_recs,"
3325 			     "tot_loads,"
3326 			     "tot_stores,"
3327 			     "stores_l1hit,stores_l1miss,stores_na,"
3328 			     "ld_fbhit,ld_l1hit,ld_l2hit,"
3329 			     "ld_lclhit,lcl_hitm,"
3330 			     "ld_rmthit,rmt_hitm,"
3331 			     "dram_lcl,dram_rmt";
3332 	else
3333 		output_str = "cl_idx,"
3334 			     "dcacheline,"
3335 			     "dcacheline_node,"
3336 			     "dcacheline_count,"
3337 			     "percent_costly_snoop,"
3338 			     "tot_peer,lcl_peer,rmt_peer,"
3339 			     "tot_recs,"
3340 			     "tot_loads,"
3341 			     "tot_stores,"
3342 			     "stores_l1hit,stores_l1miss,stores_na,"
3343 			     "ld_fbhit,ld_l1hit,ld_l2hit,"
3344 			     "ld_lclhit,lcl_hitm,"
3345 			     "ld_rmthit,rmt_hitm,"
3346 			     "dram_lcl,dram_rmt";
3347 
3348 	if (c2c.display == DISPLAY_TOT_HITM)
3349 		sort_str = "tot_hitm";
3350 	else if (c2c.display == DISPLAY_RMT_HITM)
3351 		sort_str = "rmt_hitm";
3352 	else if (c2c.display == DISPLAY_LCL_HITM)
3353 		sort_str = "lcl_hitm";
3354 	else if (c2c.display == DISPLAY_SNP_PEER)
3355 		sort_str = "tot_peer";
3356 
3357 	c2c_hists__reinit(&c2c.hists, output_str, sort_str, perf_session__env(session));
3358 
3359 	ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
3360 
3361 	hists__collapse_resort(&c2c.hists.hists, NULL);
3362 	hists__output_resort_cb(&c2c.hists.hists, &prog, resort_shared_cl_cb);
3363 	hists__iterate_cb(&c2c.hists.hists, resort_cl_cb, perf_session__env(session));
3364 
3365 	ui_progress__finish();
3366 
3367 	if (ui_quirks()) {
3368 		pr_err("failed to setup UI\n");
3369 		goto out_mem2node;
3370 	}
3371 
3372 	perf_c2c_display(session);
3373 
3374 out_mem2node:
3375 	mem2node__exit(&c2c.mem2node);
3376 out_session:
3377 	perf_session__delete(session);
3378 out:
3379 	annotation_options__exit();
3380 	return err;
3381 }
3382 
3383 static int parse_record_events(const struct option *opt,
3384 			       const char *str, int unset __maybe_unused)
3385 {
3386 	bool *event_set = (bool *) opt->value;
3387 	struct perf_pmu *pmu;
3388 
3389 	pmu = perf_mem_events_find_pmu();
3390 	if (!pmu) {
3391 		pr_err("failed: there is no PMU that supports perf c2c\n");
3392 		exit(-1);
3393 	}
3394 
3395 	if (!strcmp(str, "list")) {
3396 		perf_pmu__mem_events_list(pmu);
3397 		exit(0);
3398 	}
3399 	if (perf_pmu__mem_events_parse(pmu, str))
3400 		exit(-1);
3401 
3402 	*event_set = true;
3403 	return 0;
3404 }
3405 
3406 
3407 static const char * const __usage_record[] = {
3408 	"perf c2c record [<options>] [<command>]",
3409 	"perf c2c record [<options>] -- <command> [<options>]",
3410 	NULL
3411 };
3412 
3413 static const char * const *record_mem_usage = __usage_record;
3414 
3415 static int perf_c2c__record(int argc, const char **argv)
3416 {
3417 	int rec_argc, i = 0, j;
3418 	const char **rec_argv;
3419 	char *event_name_storage = NULL;
3420 	int ret;
3421 	bool all_user = false, all_kernel = false;
3422 	bool event_set = false;
3423 	struct perf_mem_event *e;
3424 	struct perf_pmu *pmu;
3425 	struct option options[] = {
3426 	OPT_CALLBACK('e', "event", &event_set, "event",
3427 		     "event selector. Use 'perf c2c record -e list' to list available events",
3428 		     parse_record_events),
3429 	OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
3430 	OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
3431 	OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
3432 	OPT_PARENT(c2c_options),
3433 	OPT_END()
3434 	};
3435 
3436 	pmu = perf_mem_events_find_pmu();
3437 	if (!pmu) {
3438 		pr_err("failed: no PMU supports the memory events\n");
3439 		return -1;
3440 	}
3441 
3442 	if (perf_pmu__mem_events_init()) {
3443 		pr_err("failed: memory events not supported\n");
3444 		return -1;
3445 	}
3446 
3447 	argc = parse_options(argc, argv, options, record_mem_usage,
3448 			     PARSE_OPT_KEEP_UNKNOWN);
3449 
3450 	/* Max number of arguments multiplied by number of PMUs that can support them. */
3451 	rec_argc = argc + 11 * (perf_pmu__mem_events_num_mem_pmus(pmu) + 1);
3452 
3453 	rec_argv = calloc(rec_argc + 1, sizeof(char *));
3454 	if (!rec_argv)
3455 		return -1;
3456 
3457 	rec_argv[i++] = "record";
3458 
3459 	if (!event_set) {
3460 		e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD_STORE);
3461 		/*
3462 		 * The load and store operations are required, use the event
3463 		 * PERF_MEM_EVENTS__LOAD_STORE if it is supported.
3464 		 */
3465 		if (e->tag) {
3466 			perf_mem_record[PERF_MEM_EVENTS__LOAD_STORE] = true;
3467 			rec_argv[i++] = "-W";
3468 		} else {
3469 			perf_mem_record[PERF_MEM_EVENTS__LOAD] = true;
3470 			perf_mem_record[PERF_MEM_EVENTS__STORE] = true;
3471 		}
3472 	}
3473 
3474 	if (perf_mem_record[PERF_MEM_EVENTS__LOAD])
3475 		rec_argv[i++] = "-W";
3476 
3477 	rec_argv[i++] = "-d";
3478 	rec_argv[i++] = "--phys-data";
3479 	rec_argv[i++] = "--sample-cpu";
3480 
3481 	ret = perf_mem_events__record_args(rec_argv, &i, &event_name_storage);
3482 	if (ret)
3483 		goto out;
3484 
3485 	if (all_user)
3486 		rec_argv[i++] = "--all-user";
3487 
3488 	if (all_kernel)
3489 		rec_argv[i++] = "--all-kernel";
3490 
3491 	for (j = 0; j < argc; j++, i++)
3492 		rec_argv[i] = argv[j];
3493 
3494 	if (verbose > 0) {
3495 		pr_debug("calling: ");
3496 
3497 		j = 0;
3498 
3499 		while (rec_argv[j]) {
3500 			pr_debug("%s ", rec_argv[j]);
3501 			j++;
3502 		}
3503 		pr_debug("\n");
3504 	}
3505 
3506 	ret = cmd_record(i, rec_argv);
3507 out:
3508 	free(event_name_storage);
3509 	free(rec_argv);
3510 	return ret;
3511 }
3512 
3513 int cmd_c2c(int argc, const char **argv)
3514 {
3515 	argc = parse_options(argc, argv, c2c_options, c2c_usage,
3516 			     PARSE_OPT_STOP_AT_NON_OPTION);
3517 
3518 	if (!argc)
3519 		usage_with_options(c2c_usage, c2c_options);
3520 
3521 	if (strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
3522 		return perf_c2c__record(argc, argv);
3523 	} else if (strlen(argv[0]) > 2 && strstarts("report", argv[0])) {
3524 		return perf_c2c__report(argc, argv);
3525 	} else {
3526 		usage_with_options(c2c_usage, c2c_options);
3527 	}
3528 
3529 	return 0;
3530 }
3531