]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - tools/perf/builtin-c2c.c
perf auxtrace: Uninline functions that touch perf_session
[mirror_ubuntu-jammy-kernel.git] / tools / perf / builtin-c2c.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
465f27a3
JO
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 */
a43783ae 13#include <errno.h>
fd20e811 14#include <inttypes.h>
7aef3bf3
JO
15#include <linux/compiler.h>
16#include <linux/kernel.h>
cbb88500 17#include <linux/stringify.h>
7f7c536f 18#include <linux/zalloc.h>
1e181b92 19#include <asm/bug.h>
391e4206 20#include <sys/param.h>
7aef3bf3
JO
21#include "debug.h"
22#include "builtin.h"
8520a98d 23#include <subcmd/pager.h>
7aef3bf3 24#include <subcmd/parse-options.h>
39bcd4a4 25#include "mem-events.h"
903a6f15
JO
26#include "session.h"
27#include "hist.h"
cbb88500 28#include "sort.h"
903a6f15 29#include "tool.h"
12500902 30#include "cacheline.h"
903a6f15 31#include "data.h"
5ab8c689 32#include "event.h"
2709b97d
JO
33#include "evlist.h"
34#include "evsel.h"
5a1a99cd 35#include "ui/browsers/hists.h"
e7ff8920 36#include "thread.h"
7f834c2e 37#include "mem2node.h"
daecf9e0 38#include "symbol.h"
8520a98d 39#include "ui/ui.h"
171f7474 40#include "ui/progress.h"
c1a604df 41#include "../perf.h"
903a6f15 42
c75540e3
JO
43struct c2c_hists {
44 struct hists hists;
45 struct perf_hpp_list list;
b2252ae6 46 struct c2c_stats stats;
c75540e3
JO
47};
48
92062d54
JO
49struct compute_stats {
50 struct stats lcl_hitm;
51 struct stats rmt_hitm;
52 struct stats load;
53};
54
78b27543
JO
55struct c2c_hist_entry {
56 struct c2c_hists *hists;
b2252ae6 57 struct c2c_stats stats;
1e181b92 58 unsigned long *cpuset;
7f834c2e 59 unsigned long *nodeset;
1e181b92 60 struct c2c_stats *node_stats;
bb342dae 61 unsigned int cacheline_idx;
92062d54
JO
62
63 struct compute_stats cstats;
64
4c820527
JO
65 unsigned long paddr;
66 unsigned long paddr_cnt;
67 bool paddr_zero;
68 char *nodestr;
69
78b27543
JO
70 /*
71 * must be at the end,
72 * because of its callchain dynamic entry
73 */
74 struct hist_entry he;
75};
76
423701a0 77static char const *coalesce_default = "iaddr";
fc9c630e 78
903a6f15 79struct perf_c2c {
c75540e3
JO
80 struct perf_tool tool;
81 struct c2c_hists hists;
7f834c2e 82 struct mem2node mem2node;
1e181b92
JO
83
84 unsigned long **nodes;
85 int nodes_cnt;
86 int cpus_cnt;
87 int *cpu2node;
88 int node_info;
89d9ba8f
JO
89
90 bool show_src;
af09b2d3 91 bool show_all;
5a1a99cd 92 bool use_stdio;
74c63a25 93 bool stats_only;
590b6a3a 94 bool symbol_full;
7ef2efaa
JO
95
96 /* HITM shared clines stats */
97 struct c2c_stats hitm_stats;
98 int shared_clines;
55b95776
JO
99
100 int display;
fc9c630e
JO
101
102 const char *coalesce;
103 char *cl_sort;
104 char *cl_resort;
105 char *cl_output;
55b95776
JO
106};
107
108enum {
109 DISPLAY_LCL,
110 DISPLAY_RMT,
d940bacc
JO
111 DISPLAY_TOT,
112 DISPLAY_MAX,
113};
114
115static const char *display_str[DISPLAY_MAX] = {
116 [DISPLAY_LCL] = "Local",
117 [DISPLAY_RMT] = "Remote",
118 [DISPLAY_TOT] = "Total",
903a6f15
JO
119};
120
3a5bfab6
JO
121static const struct option c2c_options[] = {
122 OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),
123 OPT_END()
124};
125
903a6f15 126static struct perf_c2c c2c;
7aef3bf3 127
78b27543
JO
128static void *c2c_he_zalloc(size_t size)
129{
130 struct c2c_hist_entry *c2c_he;
131
132 c2c_he = zalloc(size + sizeof(*c2c_he));
133 if (!c2c_he)
134 return NULL;
135
1e181b92
JO
136 c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
137 if (!c2c_he->cpuset)
138 return NULL;
139
7f834c2e
JO
140 c2c_he->nodeset = bitmap_alloc(c2c.nodes_cnt);
141 if (!c2c_he->nodeset)
142 return NULL;
143
1e181b92
JO
144 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
145 if (!c2c_he->node_stats)
146 return NULL;
147
92062d54
JO
148 init_stats(&c2c_he->cstats.lcl_hitm);
149 init_stats(&c2c_he->cstats.rmt_hitm);
150 init_stats(&c2c_he->cstats.load);
151
78b27543
JO
152 return &c2c_he->he;
153}
154
155static void c2c_he_free(void *he)
156{
157 struct c2c_hist_entry *c2c_he;
158
159 c2c_he = container_of(he, struct c2c_hist_entry, he);
160 if (c2c_he->hists) {
161 hists__delete_entries(&c2c_he->hists->hists);
162 free(c2c_he->hists);
163 }
164
1e181b92 165 free(c2c_he->cpuset);
7f834c2e
JO
166 free(c2c_he->nodeset);
167 free(c2c_he->nodestr);
1e181b92 168 free(c2c_he->node_stats);
78b27543
JO
169 free(c2c_he);
170}
171
172static struct hist_entry_ops c2c_entry_ops = {
173 .new = c2c_he_zalloc,
174 .free = c2c_he_free,
175};
176
ec06f9b9 177static int c2c_hists__init(struct c2c_hists *hists,
1d62fcd6
JO
178 const char *sort,
179 int nr_header_lines);
ec06f9b9 180
b2252ae6
JO
181static struct c2c_hists*
182he__get_c2c_hists(struct hist_entry *he,
1d62fcd6
JO
183 const char *sort,
184 int nr_header_lines)
ec06f9b9
JO
185{
186 struct c2c_hist_entry *c2c_he;
187 struct c2c_hists *hists;
188 int ret;
189
190 c2c_he = container_of(he, struct c2c_hist_entry, he);
191 if (c2c_he->hists)
b2252ae6 192 return c2c_he->hists;
ec06f9b9
JO
193
194 hists = c2c_he->hists = zalloc(sizeof(*hists));
195 if (!hists)
196 return NULL;
197
1d62fcd6 198 ret = c2c_hists__init(hists, sort, nr_header_lines);
ec06f9b9
JO
199 if (ret) {
200 free(hists);
201 return NULL;
202 }
203
b2252ae6 204 return hists;
ec06f9b9
JO
205}
206
1e181b92
JO
207static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
208 struct perf_sample *sample)
209{
210 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
211 "WARNING: no sample cpu value"))
212 return;
213
214 set_bit(sample->cpu, c2c_he->cpuset);
215}
216
7f834c2e
JO
217static void c2c_he__set_node(struct c2c_hist_entry *c2c_he,
218 struct perf_sample *sample)
219{
220 int node;
221
222 if (!sample->phys_addr) {
223 c2c_he->paddr_zero = true;
224 return;
225 }
226
227 node = mem2node__node(&c2c.mem2node, sample->phys_addr);
228 if (WARN_ONCE(node < 0, "WARNING: failed to find node\n"))
229 return;
230
231 set_bit(node, c2c_he->nodeset);
232
233 if (c2c_he->paddr != sample->phys_addr) {
234 c2c_he->paddr_cnt++;
235 c2c_he->paddr = sample->phys_addr;
236 }
237}
238
92062d54
JO
239static void compute_stats(struct c2c_hist_entry *c2c_he,
240 struct c2c_stats *stats,
241 u64 weight)
242{
243 struct compute_stats *cstats = &c2c_he->cstats;
244
245 if (stats->rmt_hitm)
246 update_stats(&cstats->rmt_hitm, weight);
247 else if (stats->lcl_hitm)
248 update_stats(&cstats->lcl_hitm, weight);
249 else if (stats->load)
250 update_stats(&cstats->load, weight);
251}
252
78b27543
JO
253static int process_sample_event(struct perf_tool *tool __maybe_unused,
254 union perf_event *event,
255 struct perf_sample *sample,
32dcd021 256 struct evsel *evsel,
78b27543
JO
257 struct machine *machine)
258{
b2252ae6
JO
259 struct c2c_hists *c2c_hists = &c2c.hists;
260 struct c2c_hist_entry *c2c_he;
261 struct c2c_stats stats = { .nr_entries = 0, };
78b27543
JO
262 struct hist_entry *he;
263 struct addr_location al;
ec06f9b9 264 struct mem_info *mi, *mi_dup;
78b27543
JO
265 int ret;
266
267 if (machine__resolve(machine, &al, sample) < 0) {
268 pr_debug("problem processing %d event, skipping it.\n",
269 event->header.type);
270 return -1;
271 }
272
dd805768
JO
273 ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
274 evsel, &al, sysctl_perf_event_max_stack);
275 if (ret)
276 goto out;
277
78b27543
JO
278 mi = sample__resolve_mem(sample, &al);
279 if (mi == NULL)
280 return -ENOMEM;
281
5cedb413
JO
282 /*
283 * The mi object is released in hists__add_entry_ops,
284 * if it gets sorted out into existing data, so we need
285 * to take the copy now.
286 */
287 mi_dup = mem_info__get(mi);
ec06f9b9 288
b2252ae6
JO
289 c2c_decode_stats(&stats, mi);
290
291 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
78b27543
JO
292 &al, NULL, NULL, mi,
293 sample, true);
ec06f9b9 294 if (he == NULL)
5cedb413 295 goto free_mi;
78b27543 296
b2252ae6
JO
297 c2c_he = container_of(he, struct c2c_hist_entry, he);
298 c2c_add_stats(&c2c_he->stats, &stats);
299 c2c_add_stats(&c2c_hists->stats, &stats);
300
1e181b92 301 c2c_he__set_cpu(c2c_he, sample);
7f834c2e 302 c2c_he__set_node(c2c_he, sample);
1e181b92 303
b2252ae6 304 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
78b27543
JO
305 ret = hist_entry__append_callchain(he, sample);
306
ec06f9b9 307 if (!ret) {
1e181b92
JO
308 /*
309 * There's already been warning about missing
310 * sample's cpu value. Let's account all to
311 * node 0 in this case, without any further
312 * warning.
313 *
314 * Doing node stats only for single callchain data.
315 */
316 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
317 int node = c2c.cpu2node[cpu];
318
ec06f9b9
JO
319 mi = mi_dup;
320
fc9c630e 321 c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2);
b2252ae6 322 if (!c2c_hists)
5cedb413 323 goto free_mi;
ec06f9b9 324
b2252ae6 325 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
ec06f9b9
JO
326 &al, NULL, NULL, mi,
327 sample, true);
328 if (he == NULL)
5cedb413 329 goto free_mi;
ec06f9b9 330
b2252ae6
JO
331 c2c_he = container_of(he, struct c2c_hist_entry, he);
332 c2c_add_stats(&c2c_he->stats, &stats);
333 c2c_add_stats(&c2c_hists->stats, &stats);
1e181b92
JO
334 c2c_add_stats(&c2c_he->node_stats[node], &stats);
335
92062d54
JO
336 compute_stats(c2c_he, &stats, sample->weight);
337
1e181b92 338 c2c_he__set_cpu(c2c_he, sample);
7f834c2e 339 c2c_he__set_node(c2c_he, sample);
b2252ae6
JO
340
341 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
ec06f9b9
JO
342 ret = hist_entry__append_callchain(he, sample);
343 }
344
345out:
78b27543
JO
346 addr_location__put(&al);
347 return ret;
ec06f9b9 348
ec06f9b9 349free_mi:
5cedb413
JO
350 mem_info__put(mi_dup);
351 mem_info__put(mi);
ec06f9b9
JO
352 ret = -ENOMEM;
353 goto out;
78b27543
JO
354}
355
356static struct perf_c2c c2c = {
357 .tool = {
358 .sample = process_sample_event,
359 .mmap = perf_event__process_mmap,
360 .mmap2 = perf_event__process_mmap2,
361 .comm = perf_event__process_comm,
362 .exit = perf_event__process_exit,
363 .fork = perf_event__process_fork,
364 .lost = perf_event__process_lost,
365 .ordered_events = true,
366 .ordering_requires_timestamps = true,
367 },
368};
369
7aef3bf3 370static const char * const c2c_usage[] = {
903a6f15 371 "perf c2c {record|report}",
7aef3bf3
JO
372 NULL
373};
374
903a6f15
JO
375static const char * const __usage_report[] = {
376 "perf c2c report",
377 NULL
378};
379
380static const char * const *report_c2c_usage = __usage_report;
381
c75540e3
JO
382#define C2C_HEADER_MAX 2
383
384struct c2c_header {
385 struct {
386 const char *text;
387 int span;
388 } line[C2C_HEADER_MAX];
389};
390
391struct c2c_dimension {
392 struct c2c_header header;
393 const char *name;
394 int width;
8d3f938d 395 struct sort_entry *se;
c75540e3
JO
396
397 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
398 struct hist_entry *, struct hist_entry *);
399 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
400 struct hist_entry *he);
401 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
402 struct hist_entry *he);
403};
404
405struct c2c_fmt {
406 struct perf_hpp_fmt fmt;
407 struct c2c_dimension *dim;
408};
409
590b6a3a
JO
410#define SYMBOL_WIDTH 30
411
412static struct c2c_dimension dim_symbol;
413static struct c2c_dimension dim_srcline;
414
415static int symbol_width(struct hists *hists, struct sort_entry *se)
416{
417 int width = hists__col_len(hists, se->se_width_idx);
418
419 if (!c2c.symbol_full)
420 width = MIN(width, SYMBOL_WIDTH);
421
422 return width;
423}
424
c75540e3
JO
425static int c2c_width(struct perf_hpp_fmt *fmt,
426 struct perf_hpp *hpp __maybe_unused,
7e6a7998 427 struct hists *hists)
c75540e3
JO
428{
429 struct c2c_fmt *c2c_fmt;
8d3f938d 430 struct c2c_dimension *dim;
c75540e3
JO
431
432 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
8d3f938d
JO
433 dim = c2c_fmt->dim;
434
590b6a3a
JO
435 if (dim == &dim_symbol || dim == &dim_srcline)
436 return symbol_width(hists, dim->se);
437
8d3f938d
JO
438 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
439 c2c_fmt->dim->width;
c75540e3
JO
440}
441
442static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
8d3f938d 443 struct hists *hists, int line, int *span)
c75540e3 444{
8d3f938d 445 struct perf_hpp_list *hpp_list = hists->hpp_list;
c75540e3
JO
446 struct c2c_fmt *c2c_fmt;
447 struct c2c_dimension *dim;
8d3f938d
JO
448 const char *text = NULL;
449 int width = c2c_width(fmt, hpp, hists);
c75540e3
JO
450
451 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
452 dim = c2c_fmt->dim;
453
8d3f938d
JO
454 if (dim->se) {
455 text = dim->header.line[line].text;
456 /* Use the last line from sort_entry if not defined. */
457 if (!text && (line == hpp_list->nr_header_lines - 1))
458 text = dim->se->se_header;
c75540e3 459 } else {
8d3f938d
JO
460 text = dim->header.line[line].text;
461
462 if (*span) {
463 (*span)--;
464 return 0;
465 } else {
466 *span = dim->header.line[line].span;
467 }
c75540e3
JO
468 }
469
8d3f938d
JO
470 if (text == NULL)
471 text = "";
472
473 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
c75540e3
JO
474}
475
cbb88500
JO
476#define HEX_STR(__s, __v) \
477({ \
478 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
479 __s; \
480})
481
482static int64_t
483dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
484 struct hist_entry *left, struct hist_entry *right)
485{
486 return sort__dcacheline_cmp(left, right);
487}
488
489static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
490 struct hist_entry *he)
491{
492 uint64_t addr = 0;
493 int width = c2c_width(fmt, hpp, he->hists);
494 char buf[20];
495
496 if (he->mem_info)
497 addr = cl_address(he->mem_info->daddr.addr);
498
499 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
500}
501
7f834c2e
JO
502static int
503dcacheline_node_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
504 struct hist_entry *he)
505{
506 struct c2c_hist_entry *c2c_he;
507 int width = c2c_width(fmt, hpp, he->hists);
508
509 c2c_he = container_of(he, struct c2c_hist_entry, he);
510 if (WARN_ON_ONCE(!c2c_he->nodestr))
511 return 0;
512
513 return scnprintf(hpp->buf, hpp->size, "%*s", width, c2c_he->nodestr);
514}
515
03d9fcb7
JO
516static int
517dcacheline_node_count(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
518 struct hist_entry *he)
519{
520 struct c2c_hist_entry *c2c_he;
521 int width = c2c_width(fmt, hpp, he->hists);
522
523 c2c_he = container_of(he, struct c2c_hist_entry, he);
524 return scnprintf(hpp->buf, hpp->size, "%*lu", width, c2c_he->paddr_cnt);
525}
526
48acdebd
JO
527static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
528 struct hist_entry *he)
529{
530 uint64_t addr = 0;
531 int width = c2c_width(fmt, hpp, he->hists);
532 char buf[20];
533
534 if (he->mem_info)
535 addr = cl_offset(he->mem_info->daddr.al_addr);
536
537 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
538}
539
540static int64_t
541offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
542 struct hist_entry *left, struct hist_entry *right)
543{
544 uint64_t l = 0, r = 0;
545
546 if (left->mem_info)
547 l = cl_offset(left->mem_info->daddr.addr);
548 if (right->mem_info)
549 r = cl_offset(right->mem_info->daddr.addr);
550
551 return (int64_t)(r - l);
552}
553
43575a95
JO
554static int
555iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
556 struct hist_entry *he)
557{
558 uint64_t addr = 0;
559 int width = c2c_width(fmt, hpp, he->hists);
560 char buf[20];
561
562 if (he->mem_info)
563 addr = he->mem_info->iaddr.addr;
564
565 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
566}
567
568static int64_t
569iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
570 struct hist_entry *left, struct hist_entry *right)
571{
572 return sort__iaddr_cmp(left, right);
573}
574
97cb486e
JO
575static int
576tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
577 struct hist_entry *he)
578{
579 struct c2c_hist_entry *c2c_he;
580 int width = c2c_width(fmt, hpp, he->hists);
581 unsigned int tot_hitm;
582
583 c2c_he = container_of(he, struct c2c_hist_entry, he);
584 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
585
586 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
587}
588
589static int64_t
590tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
591 struct hist_entry *left, struct hist_entry *right)
592{
593 struct c2c_hist_entry *c2c_left;
594 struct c2c_hist_entry *c2c_right;
595 unsigned int tot_hitm_left;
596 unsigned int tot_hitm_right;
597
598 c2c_left = container_of(left, struct c2c_hist_entry, he);
599 c2c_right = container_of(right, struct c2c_hist_entry, he);
600
601 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
602 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
603
604 return tot_hitm_left - tot_hitm_right;
605}
606
607#define STAT_FN_ENTRY(__f) \
608static int \
609__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
610 struct hist_entry *he) \
611{ \
612 struct c2c_hist_entry *c2c_he; \
613 int width = c2c_width(fmt, hpp, he->hists); \
614 \
615 c2c_he = container_of(he, struct c2c_hist_entry, he); \
616 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
617 c2c_he->stats.__f); \
618}
619
620#define STAT_FN_CMP(__f) \
621static int64_t \
622__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
623 struct hist_entry *left, struct hist_entry *right) \
624{ \
625 struct c2c_hist_entry *c2c_left, *c2c_right; \
626 \
627 c2c_left = container_of(left, struct c2c_hist_entry, he); \
628 c2c_right = container_of(right, struct c2c_hist_entry, he); \
629 return c2c_left->stats.__f - c2c_right->stats.__f; \
630}
631
632#define STAT_FN(__f) \
633 STAT_FN_ENTRY(__f) \
634 STAT_FN_CMP(__f)
635
636STAT_FN(rmt_hitm)
637STAT_FN(lcl_hitm)
0f18896d
JO
638STAT_FN(store)
639STAT_FN(st_l1hit)
640STAT_FN(st_l1miss)
1295f685
JO
641STAT_FN(ld_fbhit)
642STAT_FN(ld_l1hit)
643STAT_FN(ld_l2hit)
4d08910c
JO
644STAT_FN(ld_llchit)
645STAT_FN(rmt_hit)
97cb486e 646
04402d20
JO
647static uint64_t llc_miss(struct c2c_stats *stats)
648{
649 uint64_t llcmiss;
650
651 llcmiss = stats->lcl_dram +
652 stats->rmt_dram +
653 stats->rmt_hitm +
654 stats->rmt_hit;
655
656 return llcmiss;
657}
658
659static int
660ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
661 struct hist_entry *he)
662{
663 struct c2c_hist_entry *c2c_he;
664 int width = c2c_width(fmt, hpp, he->hists);
665
666 c2c_he = container_of(he, struct c2c_hist_entry, he);
667
668 return scnprintf(hpp->buf, hpp->size, "%*lu", width,
669 llc_miss(&c2c_he->stats));
670}
671
672static int64_t
673ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
674 struct hist_entry *left, struct hist_entry *right)
675{
676 struct c2c_hist_entry *c2c_left;
677 struct c2c_hist_entry *c2c_right;
678
679 c2c_left = container_of(left, struct c2c_hist_entry, he);
680 c2c_right = container_of(right, struct c2c_hist_entry, he);
681
682 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
683}
684
01b84d76
JO
685static uint64_t total_records(struct c2c_stats *stats)
686{
687 uint64_t lclmiss, ldcnt, total;
688
689 lclmiss = stats->lcl_dram +
690 stats->rmt_dram +
691 stats->rmt_hitm +
692 stats->rmt_hit;
693
694 ldcnt = lclmiss +
695 stats->ld_fbhit +
696 stats->ld_l1hit +
697 stats->ld_l2hit +
698 stats->ld_llchit +
699 stats->lcl_hitm;
700
701 total = ldcnt +
702 stats->st_l1hit +
703 stats->st_l1miss;
704
705 return total;
706}
707
708static int
709tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
710 struct hist_entry *he)
711{
712 struct c2c_hist_entry *c2c_he;
713 int width = c2c_width(fmt, hpp, he->hists);
714 uint64_t tot_recs;
715
716 c2c_he = container_of(he, struct c2c_hist_entry, he);
717 tot_recs = total_records(&c2c_he->stats);
718
719 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
720}
721
722static int64_t
723tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
724 struct hist_entry *left, struct hist_entry *right)
725{
726 struct c2c_hist_entry *c2c_left;
727 struct c2c_hist_entry *c2c_right;
728 uint64_t tot_recs_left;
729 uint64_t tot_recs_right;
730
731 c2c_left = container_of(left, struct c2c_hist_entry, he);
732 c2c_right = container_of(right, struct c2c_hist_entry, he);
733
734 tot_recs_left = total_records(&c2c_left->stats);
735 tot_recs_right = total_records(&c2c_right->stats);
736
737 return tot_recs_left - tot_recs_right;
738}
739
55177c4e
JO
740static uint64_t total_loads(struct c2c_stats *stats)
741{
742 uint64_t lclmiss, ldcnt;
743
744 lclmiss = stats->lcl_dram +
745 stats->rmt_dram +
746 stats->rmt_hitm +
747 stats->rmt_hit;
748
749 ldcnt = lclmiss +
750 stats->ld_fbhit +
751 stats->ld_l1hit +
752 stats->ld_l2hit +
753 stats->ld_llchit +
754 stats->lcl_hitm;
755
756 return ldcnt;
757}
758
759static int
760tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
761 struct hist_entry *he)
762{
763 struct c2c_hist_entry *c2c_he;
764 int width = c2c_width(fmt, hpp, he->hists);
765 uint64_t tot_recs;
766
767 c2c_he = container_of(he, struct c2c_hist_entry, he);
768 tot_recs = total_loads(&c2c_he->stats);
769
770 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
771}
772
773static int64_t
774tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
775 struct hist_entry *left, struct hist_entry *right)
776{
777 struct c2c_hist_entry *c2c_left;
778 struct c2c_hist_entry *c2c_right;
779 uint64_t tot_recs_left;
780 uint64_t tot_recs_right;
781
782 c2c_left = container_of(left, struct c2c_hist_entry, he);
783 c2c_right = container_of(right, struct c2c_hist_entry, he);
784
785 tot_recs_left = total_loads(&c2c_left->stats);
786 tot_recs_right = total_loads(&c2c_right->stats);
787
788 return tot_recs_left - tot_recs_right;
789}
790
f0c50c15
JO
791typedef double (get_percent_cb)(struct c2c_hist_entry *);
792
793static int
794percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
795 struct hist_entry *he, get_percent_cb get_percent)
796{
797 struct c2c_hist_entry *c2c_he;
798 int width = c2c_width(fmt, hpp, he->hists);
799 double per;
800
801 c2c_he = container_of(he, struct c2c_hist_entry, he);
802 per = get_percent(c2c_he);
803
5a1a99cd
JO
804#ifdef HAVE_SLANG_SUPPORT
805 if (use_browser)
806 return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
807#endif
f0c50c15
JO
808 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
809}
810
811static double percent_hitm(struct c2c_hist_entry *c2c_he)
812{
813 struct c2c_hists *hists;
814 struct c2c_stats *stats;
815 struct c2c_stats *total;
55b95776 816 int tot = 0, st = 0;
f0c50c15
JO
817 double p;
818
819 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
820 stats = &c2c_he->stats;
821 total = &hists->stats;
822
55b95776
JO
823 switch (c2c.display) {
824 case DISPLAY_RMT:
825 st = stats->rmt_hitm;
826 tot = total->rmt_hitm;
827 break;
828 case DISPLAY_LCL:
829 st = stats->lcl_hitm;
830 tot = total->lcl_hitm;
d940bacc
JO
831 break;
832 case DISPLAY_TOT:
833 st = stats->tot_hitm;
834 tot = total->tot_hitm;
55b95776
JO
835 default:
836 break;
837 }
f0c50c15
JO
838
839 p = tot ? (double) st / tot : 0;
840
841 return 100 * p;
842}
843
844#define PERC_STR(__s, __v) \
845({ \
846 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
847 __s; \
848})
849
850static int
851percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
852 struct hist_entry *he)
853{
854 struct c2c_hist_entry *c2c_he;
855 int width = c2c_width(fmt, hpp, he->hists);
856 char buf[10];
857 double per;
858
859 c2c_he = container_of(he, struct c2c_hist_entry, he);
860 per = percent_hitm(c2c_he);
861 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
862}
863
864static int
865percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
866 struct hist_entry *he)
867{
868 return percent_color(fmt, hpp, he, percent_hitm);
869}
870
871static int64_t
872percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
873 struct hist_entry *left, struct hist_entry *right)
874{
875 struct c2c_hist_entry *c2c_left;
876 struct c2c_hist_entry *c2c_right;
877 double per_left;
878 double per_right;
879
880 c2c_left = container_of(left, struct c2c_hist_entry, he);
881 c2c_right = container_of(right, struct c2c_hist_entry, he);
882
883 per_left = percent_hitm(c2c_left);
884 per_right = percent_hitm(c2c_right);
885
886 return per_left - per_right;
887}
888
9cb3500a
JO
889static struct c2c_stats *he_stats(struct hist_entry *he)
890{
891 struct c2c_hist_entry *c2c_he;
892
893 c2c_he = container_of(he, struct c2c_hist_entry, he);
894 return &c2c_he->stats;
895}
896
897static struct c2c_stats *total_stats(struct hist_entry *he)
898{
899 struct c2c_hists *hists;
900
901 hists = container_of(he->hists, struct c2c_hists, hists);
902 return &hists->stats;
903}
904
905static double percent(int st, int tot)
906{
907 return tot ? 100. * (double) st / (double) tot : 0;
908}
909
910#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
911
912#define PERCENT_FN(__f) \
913static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
914{ \
915 struct c2c_hists *hists; \
916 \
917 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
918 return percent(c2c_he->stats.__f, hists->stats.__f); \
919}
920
921PERCENT_FN(rmt_hitm)
922PERCENT_FN(lcl_hitm)
923PERCENT_FN(st_l1hit)
924PERCENT_FN(st_l1miss)
925
926static int
927percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
928 struct hist_entry *he)
929{
930 int width = c2c_width(fmt, hpp, he->hists);
931 double per = PERCENT(he, rmt_hitm);
932 char buf[10];
933
934 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
935}
936
937static int
938percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
939 struct hist_entry *he)
940{
941 return percent_color(fmt, hpp, he, percent_rmt_hitm);
942}
943
944static int64_t
945percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
946 struct hist_entry *left, struct hist_entry *right)
947{
948 double per_left;
949 double per_right;
950
951 per_left = PERCENT(left, lcl_hitm);
952 per_right = PERCENT(right, lcl_hitm);
953
954 return per_left - per_right;
955}
956
957static int
958percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
959 struct hist_entry *he)
960{
961 int width = c2c_width(fmt, hpp, he->hists);
962 double per = PERCENT(he, lcl_hitm);
963 char buf[10];
964
965 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
966}
967
968static int
969percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
970 struct hist_entry *he)
971{
972 return percent_color(fmt, hpp, he, percent_lcl_hitm);
973}
974
975static int64_t
976percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
977 struct hist_entry *left, struct hist_entry *right)
978{
979 double per_left;
980 double per_right;
981
982 per_left = PERCENT(left, lcl_hitm);
983 per_right = PERCENT(right, lcl_hitm);
984
985 return per_left - per_right;
986}
987
988static int
989percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
990 struct hist_entry *he)
991{
992 int width = c2c_width(fmt, hpp, he->hists);
993 double per = PERCENT(he, st_l1hit);
994 char buf[10];
995
996 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
997}
998
999static int
1000percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1001 struct hist_entry *he)
1002{
1003 return percent_color(fmt, hpp, he, percent_st_l1hit);
1004}
1005
1006static int64_t
1007percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1008 struct hist_entry *left, struct hist_entry *right)
1009{
1010 double per_left;
1011 double per_right;
1012
1013 per_left = PERCENT(left, st_l1hit);
1014 per_right = PERCENT(right, st_l1hit);
1015
1016 return per_left - per_right;
1017}
1018
1019static int
1020percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1021 struct hist_entry *he)
1022{
1023 int width = c2c_width(fmt, hpp, he->hists);
1024 double per = PERCENT(he, st_l1miss);
1025 char buf[10];
1026
1027 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1028}
1029
1030static int
1031percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1032 struct hist_entry *he)
1033{
1034 return percent_color(fmt, hpp, he, percent_st_l1miss);
1035}
1036
1037static int64_t
1038percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1039 struct hist_entry *left, struct hist_entry *right)
1040{
1041 double per_left;
1042 double per_right;
1043
1044 per_left = PERCENT(left, st_l1miss);
1045 per_right = PERCENT(right, st_l1miss);
1046
1047 return per_left - per_right;
1048}
1049
6c70f54c
JO
1050STAT_FN(lcl_dram)
1051STAT_FN(rmt_dram)
1052
36d3deb9
JO
1053static int
1054pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1055 struct hist_entry *he)
1056{
1057 int width = c2c_width(fmt, hpp, he->hists);
1058
1059 return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
1060}
1061
1062static int64_t
1063pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1064 struct hist_entry *left, struct hist_entry *right)
1065{
1066 return left->thread->pid_ - right->thread->pid_;
1067}
1068
1e181b92
JO
1069static int64_t
1070empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1071 struct hist_entry *left __maybe_unused,
1072 struct hist_entry *right __maybe_unused)
1073{
1074 return 0;
1075}
1076
1077static int
1078node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1079 struct hist_entry *he)
1080{
1081 struct c2c_hist_entry *c2c_he;
1082 bool first = true;
1083 int node;
1084 int ret = 0;
1085
1086 c2c_he = container_of(he, struct c2c_hist_entry, he);
1087
1088 for (node = 0; node < c2c.nodes_cnt; node++) {
1089 DECLARE_BITMAP(set, c2c.cpus_cnt);
1090
1091 bitmap_zero(set, c2c.cpus_cnt);
1092 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
1093
1094 if (!bitmap_weight(set, c2c.cpus_cnt)) {
1095 if (c2c.node_info == 1) {
1096 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
1097 advance_hpp(hpp, ret);
1098 }
1099 continue;
1100 }
1101
1102 if (!first) {
1103 ret = scnprintf(hpp->buf, hpp->size, " ");
1104 advance_hpp(hpp, ret);
1105 }
1106
1107 switch (c2c.node_info) {
1108 case 0:
1109 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
1110 advance_hpp(hpp, ret);
1111 break;
1112 case 1:
1113 {
67260e8c 1114 int num = bitmap_weight(set, c2c.cpus_cnt);
1e181b92
JO
1115 struct c2c_stats *stats = &c2c_he->node_stats[node];
1116
1117 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
1118 advance_hpp(hpp, ret);
1119
55b95776
JO
1120 #define DISPLAY_HITM(__h) \
1121 if (c2c_he->stats.__h> 0) { \
1122 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", \
1123 percent(stats->__h, c2c_he->stats.__h));\
1124 } else { \
1125 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); \
1126 }
1e181b92 1127
55b95776
JO
1128 switch (c2c.display) {
1129 case DISPLAY_RMT:
1130 DISPLAY_HITM(rmt_hitm);
1131 break;
1132 case DISPLAY_LCL:
1133 DISPLAY_HITM(lcl_hitm);
d940bacc
JO
1134 break;
1135 case DISPLAY_TOT:
1136 DISPLAY_HITM(tot_hitm);
55b95776
JO
1137 default:
1138 break;
1e181b92
JO
1139 }
1140
55b95776
JO
1141 #undef DISPLAY_HITM
1142
1e181b92
JO
1143 advance_hpp(hpp, ret);
1144
1145 if (c2c_he->stats.store > 0) {
1146 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
1147 percent(stats->store, c2c_he->stats.store));
1148 } else {
1149 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
1150 }
1151
1152 advance_hpp(hpp, ret);
1153 break;
1154 }
1155 case 2:
1156 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
1157 advance_hpp(hpp, ret);
1158
1159 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
1160 advance_hpp(hpp, ret);
1161
1162 ret = scnprintf(hpp->buf, hpp->size, "}");
1163 advance_hpp(hpp, ret);
1164 break;
1165 default:
1166 break;
1167 }
1168
1169 first = false;
1170 }
1171
1172 return 0;
1173}
1174
92062d54
JO
1175static int
1176mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1177 struct hist_entry *he, double mean)
1178{
1179 int width = c2c_width(fmt, hpp, he->hists);
1180 char buf[10];
1181
1182 scnprintf(buf, 10, "%6.0f", mean);
1183 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1184}
1185
1186#define MEAN_ENTRY(__func, __val) \
1187static int \
1188__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1189{ \
1190 struct c2c_hist_entry *c2c_he; \
1191 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1192 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1193}
1194
1195MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1196MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1197MEAN_ENTRY(mean_load_entry, load);
1198
b6fe2bbc 1199static int
7e6a7998 1200cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
b6fe2bbc
JO
1201 struct hist_entry *he)
1202{
1203 struct c2c_hist_entry *c2c_he;
1204 int width = c2c_width(fmt, hpp, he->hists);
1205 char buf[10];
1206
1207 c2c_he = container_of(he, struct c2c_hist_entry, he);
1208
1209 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1210 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1211}
1212
bb342dae 1213static int
7e6a7998 1214cl_idx_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
bb342dae
JO
1215 struct hist_entry *he)
1216{
1217 struct c2c_hist_entry *c2c_he;
1218 int width = c2c_width(fmt, hpp, he->hists);
1219 char buf[10];
1220
1221 c2c_he = container_of(he, struct c2c_hist_entry, he);
1222
1223 scnprintf(buf, 10, "%u", c2c_he->cacheline_idx);
1224 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1225}
1226
1227static int
7e6a7998 1228cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
bb342dae
JO
1229 struct hist_entry *he)
1230{
1231 int width = c2c_width(fmt, hpp, he->hists);
1232
1233 return scnprintf(hpp->buf, hpp->size, "%*s", width, "");
1234}
1235
600a8cf4
JO
1236#define HEADER_LOW(__h) \
1237 { \
1238 .line[1] = { \
1239 .text = __h, \
1240 }, \
1241 }
1242
1243#define HEADER_BOTH(__h0, __h1) \
1244 { \
1245 .line[0] = { \
1246 .text = __h0, \
1247 }, \
1248 .line[1] = { \
1249 .text = __h1, \
1250 }, \
1251 }
1252
1253#define HEADER_SPAN(__h0, __h1, __s) \
1254 { \
1255 .line[0] = { \
1256 .text = __h0, \
1257 .span = __s, \
1258 }, \
1259 .line[1] = { \
1260 .text = __h1, \
1261 }, \
1262 }
1263
1264#define HEADER_SPAN_LOW(__h) \
1265 { \
1266 .line[1] = { \
1267 .text = __h, \
1268 }, \
1269 }
1270
cbb88500 1271static struct c2c_dimension dim_dcacheline = {
03d9fcb7 1272 .header = HEADER_SPAN("--- Cacheline ----", "Address", 2),
cbb88500
JO
1273 .name = "dcacheline",
1274 .cmp = dcacheline_cmp,
1275 .entry = dcacheline_entry,
1276 .width = 18,
1277};
1278
7f834c2e
JO
1279static struct c2c_dimension dim_dcacheline_node = {
1280 .header = HEADER_LOW("Node"),
1281 .name = "dcacheline_node",
1282 .cmp = empty_cmp,
1283 .entry = dcacheline_node_entry,
1284 .width = 4,
1285};
1286
03d9fcb7
JO
1287static struct c2c_dimension dim_dcacheline_count = {
1288 .header = HEADER_LOW("PA cnt"),
1289 .name = "dcacheline_count",
1290 .cmp = empty_cmp,
1291 .entry = dcacheline_node_count,
1292 .width = 6,
1293};
1294
1295static struct c2c_header header_offset_tui = HEADER_SPAN("-----", "Off", 2);
5a1a99cd 1296
48acdebd 1297static struct c2c_dimension dim_offset = {
03d9fcb7 1298 .header = HEADER_SPAN("--- Data address -", "Offset", 2),
48acdebd
JO
1299 .name = "offset",
1300 .cmp = offset_cmp,
1301 .entry = offset_entry,
1302 .width = 18,
1303};
1304
7f834c2e
JO
1305static struct c2c_dimension dim_offset_node = {
1306 .header = HEADER_LOW("Node"),
1307 .name = "offset_node",
1308 .cmp = empty_cmp,
1309 .entry = dcacheline_node_entry,
1310 .width = 4,
1311};
1312
43575a95
JO
1313static struct c2c_dimension dim_iaddr = {
1314 .header = HEADER_LOW("Code address"),
1315 .name = "iaddr",
1316 .cmp = iaddr_cmp,
1317 .entry = iaddr_entry,
1318 .width = 18,
1319};
1320
97cb486e
JO
1321static struct c2c_dimension dim_tot_hitm = {
1322 .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1323 .name = "tot_hitm",
1324 .cmp = tot_hitm_cmp,
1325 .entry = tot_hitm_entry,
1326 .width = 7,
1327};
1328
1329static struct c2c_dimension dim_lcl_hitm = {
1330 .header = HEADER_SPAN_LOW("Lcl"),
1331 .name = "lcl_hitm",
1332 .cmp = lcl_hitm_cmp,
1333 .entry = lcl_hitm_entry,
1334 .width = 7,
1335};
1336
1337static struct c2c_dimension dim_rmt_hitm = {
1338 .header = HEADER_SPAN_LOW("Rmt"),
1339 .name = "rmt_hitm",
1340 .cmp = rmt_hitm_cmp,
1341 .entry = rmt_hitm_entry,
1342 .width = 7,
1343};
1344
1345static struct c2c_dimension dim_cl_rmt_hitm = {
1346 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1347 .name = "cl_rmt_hitm",
1348 .cmp = rmt_hitm_cmp,
1349 .entry = rmt_hitm_entry,
1350 .width = 7,
1351};
1352
1353static struct c2c_dimension dim_cl_lcl_hitm = {
1354 .header = HEADER_SPAN_LOW("Lcl"),
1355 .name = "cl_lcl_hitm",
1356 .cmp = lcl_hitm_cmp,
1357 .entry = lcl_hitm_entry,
1358 .width = 7,
1359};
1360
0f18896d
JO
1361static struct c2c_dimension dim_stores = {
1362 .header = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1363 .name = "stores",
1364 .cmp = store_cmp,
1365 .entry = store_entry,
1366 .width = 7,
1367};
1368
1369static struct c2c_dimension dim_stores_l1hit = {
1370 .header = HEADER_SPAN_LOW("L1Hit"),
1371 .name = "stores_l1hit",
1372 .cmp = st_l1hit_cmp,
1373 .entry = st_l1hit_entry,
1374 .width = 7,
1375};
1376
1377static struct c2c_dimension dim_stores_l1miss = {
1378 .header = HEADER_SPAN_LOW("L1Miss"),
1379 .name = "stores_l1miss",
1380 .cmp = st_l1miss_cmp,
1381 .entry = st_l1miss_entry,
1382 .width = 7,
1383};
1384
1385static struct c2c_dimension dim_cl_stores_l1hit = {
1386 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1387 .name = "cl_stores_l1hit",
1388 .cmp = st_l1hit_cmp,
1389 .entry = st_l1hit_entry,
1390 .width = 7,
1391};
1392
1393static struct c2c_dimension dim_cl_stores_l1miss = {
1394 .header = HEADER_SPAN_LOW("L1 Miss"),
1395 .name = "cl_stores_l1miss",
1396 .cmp = st_l1miss_cmp,
1397 .entry = st_l1miss_entry,
1398 .width = 7,
1399};
1400
1295f685
JO
1401static struct c2c_dimension dim_ld_fbhit = {
1402 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1403 .name = "ld_fbhit",
1404 .cmp = ld_fbhit_cmp,
1405 .entry = ld_fbhit_entry,
1406 .width = 7,
1407};
1408
1409static struct c2c_dimension dim_ld_l1hit = {
1410 .header = HEADER_SPAN_LOW("L1"),
1411 .name = "ld_l1hit",
1412 .cmp = ld_l1hit_cmp,
1413 .entry = ld_l1hit_entry,
1414 .width = 7,
1415};
1416
1417static struct c2c_dimension dim_ld_l2hit = {
1418 .header = HEADER_SPAN_LOW("L2"),
1419 .name = "ld_l2hit",
1420 .cmp = ld_l2hit_cmp,
1421 .entry = ld_l2hit_entry,
1422 .width = 7,
1423};
1424
4d08910c
JO
1425static struct c2c_dimension dim_ld_llchit = {
1426 .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1427 .name = "ld_lclhit",
1428 .cmp = ld_llchit_cmp,
1429 .entry = ld_llchit_entry,
1430 .width = 8,
1431};
1432
1433static struct c2c_dimension dim_ld_rmthit = {
1434 .header = HEADER_SPAN_LOW("Rmt"),
1435 .name = "ld_rmthit",
1436 .cmp = rmt_hit_cmp,
1437 .entry = rmt_hit_entry,
1438 .width = 8,
1439};
1440
04402d20
JO
1441static struct c2c_dimension dim_ld_llcmiss = {
1442 .header = HEADER_BOTH("LLC", "Ld Miss"),
1443 .name = "ld_llcmiss",
1444 .cmp = ld_llcmiss_cmp,
1445 .entry = ld_llcmiss_entry,
1446 .width = 7,
1447};
1448
01b84d76
JO
1449static struct c2c_dimension dim_tot_recs = {
1450 .header = HEADER_BOTH("Total", "records"),
1451 .name = "tot_recs",
1452 .cmp = tot_recs_cmp,
1453 .entry = tot_recs_entry,
1454 .width = 7,
1455};
1456
55177c4e
JO
1457static struct c2c_dimension dim_tot_loads = {
1458 .header = HEADER_BOTH("Total", "Loads"),
1459 .name = "tot_loads",
1460 .cmp = tot_loads_cmp,
1461 .entry = tot_loads_entry,
1462 .width = 7,
1463};
1464
55b95776
JO
1465static struct c2c_header percent_hitm_header[] = {
1466 [DISPLAY_LCL] = HEADER_BOTH("Lcl", "Hitm"),
1467 [DISPLAY_RMT] = HEADER_BOTH("Rmt", "Hitm"),
d940bacc 1468 [DISPLAY_TOT] = HEADER_BOTH("Tot", "Hitm"),
55b95776
JO
1469};
1470
f0c50c15 1471static struct c2c_dimension dim_percent_hitm = {
f0c50c15
JO
1472 .name = "percent_hitm",
1473 .cmp = percent_hitm_cmp,
1474 .entry = percent_hitm_entry,
1475 .color = percent_hitm_color,
1476 .width = 7,
1477};
1478
9cb3500a
JO
1479static struct c2c_dimension dim_percent_rmt_hitm = {
1480 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1481 .name = "percent_rmt_hitm",
1482 .cmp = percent_rmt_hitm_cmp,
1483 .entry = percent_rmt_hitm_entry,
1484 .color = percent_rmt_hitm_color,
1485 .width = 7,
1486};
1487
1488static struct c2c_dimension dim_percent_lcl_hitm = {
1489 .header = HEADER_SPAN_LOW("Lcl"),
1490 .name = "percent_lcl_hitm",
1491 .cmp = percent_lcl_hitm_cmp,
1492 .entry = percent_lcl_hitm_entry,
1493 .color = percent_lcl_hitm_color,
1494 .width = 7,
1495};
1496
1497static struct c2c_dimension dim_percent_stores_l1hit = {
1498 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1499 .name = "percent_stores_l1hit",
1500 .cmp = percent_stores_l1hit_cmp,
1501 .entry = percent_stores_l1hit_entry,
1502 .color = percent_stores_l1hit_color,
1503 .width = 7,
1504};
1505
1506static struct c2c_dimension dim_percent_stores_l1miss = {
1507 .header = HEADER_SPAN_LOW("L1 Miss"),
1508 .name = "percent_stores_l1miss",
1509 .cmp = percent_stores_l1miss_cmp,
1510 .entry = percent_stores_l1miss_entry,
1511 .color = percent_stores_l1miss_color,
1512 .width = 7,
1513};
1514
6c70f54c
JO
1515static struct c2c_dimension dim_dram_lcl = {
1516 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1517 .name = "dram_lcl",
1518 .cmp = lcl_dram_cmp,
1519 .entry = lcl_dram_entry,
1520 .width = 8,
1521};
1522
1523static struct c2c_dimension dim_dram_rmt = {
1524 .header = HEADER_SPAN_LOW("Rmt"),
1525 .name = "dram_rmt",
1526 .cmp = rmt_dram_cmp,
1527 .entry = rmt_dram_entry,
1528 .width = 8,
1529};
1530
36d3deb9
JO
1531static struct c2c_dimension dim_pid = {
1532 .header = HEADER_LOW("Pid"),
1533 .name = "pid",
1534 .cmp = pid_cmp,
1535 .entry = pid_entry,
1536 .width = 7,
1537};
1538
e87019c5
JO
1539static struct c2c_dimension dim_tid = {
1540 .header = HEADER_LOW("Tid"),
1541 .name = "tid",
1542 .se = &sort_thread,
1543};
1544
51dedaa4
JO
1545static struct c2c_dimension dim_symbol = {
1546 .name = "symbol",
1547 .se = &sort_sym,
1548};
1549
1550static struct c2c_dimension dim_dso = {
1551 .header = HEADER_BOTH("Shared", "Object"),
1552 .name = "dso",
1553 .se = &sort_dso,
1554};
1555
1e181b92
JO
1556static struct c2c_header header_node[3] = {
1557 HEADER_LOW("Node"),
1558 HEADER_LOW("Node{cpus %hitms %stores}"),
1559 HEADER_LOW("Node{cpu list}"),
1560};
1561
1562static struct c2c_dimension dim_node = {
1563 .name = "node",
1564 .cmp = empty_cmp,
1565 .entry = node_entry,
1566 .width = 4,
1567};
1568
92062d54
JO
1569static struct c2c_dimension dim_mean_rmt = {
1570 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1571 .name = "mean_rmt",
1572 .cmp = empty_cmp,
1573 .entry = mean_rmt_entry,
1574 .width = 8,
1575};
1576
1577static struct c2c_dimension dim_mean_lcl = {
1578 .header = HEADER_SPAN_LOW("lcl hitm"),
1579 .name = "mean_lcl",
1580 .cmp = empty_cmp,
1581 .entry = mean_lcl_entry,
1582 .width = 8,
1583};
1584
1585static struct c2c_dimension dim_mean_load = {
1586 .header = HEADER_SPAN_LOW("load"),
1587 .name = "mean_load",
1588 .cmp = empty_cmp,
1589 .entry = mean_load_entry,
1590 .width = 8,
1591};
1592
b6fe2bbc
JO
1593static struct c2c_dimension dim_cpucnt = {
1594 .header = HEADER_BOTH("cpu", "cnt"),
1595 .name = "cpucnt",
1596 .cmp = empty_cmp,
1597 .entry = cpucnt_entry,
1598 .width = 8,
1599};
1600
89d9ba8f
JO
1601static struct c2c_dimension dim_srcline = {
1602 .name = "cl_srcline",
1603 .se = &sort_srcline,
1604};
1605
bb342dae
JO
1606static struct c2c_dimension dim_dcacheline_idx = {
1607 .header = HEADER_LOW("Index"),
1608 .name = "cl_idx",
1609 .cmp = empty_cmp,
1610 .entry = cl_idx_entry,
1611 .width = 5,
1612};
1613
1614static struct c2c_dimension dim_dcacheline_num = {
1615 .header = HEADER_LOW("Num"),
1616 .name = "cl_num",
1617 .cmp = empty_cmp,
1618 .entry = cl_idx_entry,
1619 .width = 5,
1620};
1621
1622static struct c2c_dimension dim_dcacheline_num_empty = {
1623 .header = HEADER_LOW("Num"),
1624 .name = "cl_num_empty",
1625 .cmp = empty_cmp,
1626 .entry = cl_idx_empty_entry,
1627 .width = 5,
1628};
1629
c75540e3 1630static struct c2c_dimension *dimensions[] = {
cbb88500 1631 &dim_dcacheline,
7f834c2e 1632 &dim_dcacheline_node,
03d9fcb7 1633 &dim_dcacheline_count,
48acdebd 1634 &dim_offset,
7f834c2e 1635 &dim_offset_node,
43575a95 1636 &dim_iaddr,
97cb486e
JO
1637 &dim_tot_hitm,
1638 &dim_lcl_hitm,
1639 &dim_rmt_hitm,
1640 &dim_cl_lcl_hitm,
1641 &dim_cl_rmt_hitm,
0f18896d
JO
1642 &dim_stores,
1643 &dim_stores_l1hit,
1644 &dim_stores_l1miss,
1645 &dim_cl_stores_l1hit,
1646 &dim_cl_stores_l1miss,
1295f685
JO
1647 &dim_ld_fbhit,
1648 &dim_ld_l1hit,
1649 &dim_ld_l2hit,
4d08910c
JO
1650 &dim_ld_llchit,
1651 &dim_ld_rmthit,
04402d20 1652 &dim_ld_llcmiss,
01b84d76 1653 &dim_tot_recs,
55177c4e 1654 &dim_tot_loads,
f0c50c15 1655 &dim_percent_hitm,
9cb3500a
JO
1656 &dim_percent_rmt_hitm,
1657 &dim_percent_lcl_hitm,
1658 &dim_percent_stores_l1hit,
1659 &dim_percent_stores_l1miss,
6c70f54c
JO
1660 &dim_dram_lcl,
1661 &dim_dram_rmt,
36d3deb9 1662 &dim_pid,
e87019c5 1663 &dim_tid,
51dedaa4
JO
1664 &dim_symbol,
1665 &dim_dso,
1e181b92 1666 &dim_node,
92062d54
JO
1667 &dim_mean_rmt,
1668 &dim_mean_lcl,
1669 &dim_mean_load,
b6fe2bbc 1670 &dim_cpucnt,
89d9ba8f 1671 &dim_srcline,
bb342dae
JO
1672 &dim_dcacheline_idx,
1673 &dim_dcacheline_num,
1674 &dim_dcacheline_num_empty,
c75540e3
JO
1675 NULL,
1676};
1677
1678static void fmt_free(struct perf_hpp_fmt *fmt)
1679{
1680 struct c2c_fmt *c2c_fmt;
1681
1682 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1683 free(c2c_fmt);
1684}
1685
1686static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1687{
1688 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1689 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1690
1691 return c2c_a->dim == c2c_b->dim;
1692}
1693
1694static struct c2c_dimension *get_dimension(const char *name)
1695{
1696 unsigned int i;
1697
1698 for (i = 0; dimensions[i]; i++) {
1699 struct c2c_dimension *dim = dimensions[i];
1700
1701 if (!strcmp(dim->name, name))
1702 return dim;
1703 };
1704
1705 return NULL;
1706}
1707
8d3f938d
JO
1708static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1709 struct hist_entry *he)
1710{
1711 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1712 struct c2c_dimension *dim = c2c_fmt->dim;
1713 size_t len = fmt->user_len;
1714
590b6a3a 1715 if (!len) {
8d3f938d
JO
1716 len = hists__col_len(he->hists, dim->se->se_width_idx);
1717
590b6a3a
JO
1718 if (dim == &dim_symbol || dim == &dim_srcline)
1719 len = symbol_width(he->hists, dim->se);
1720 }
1721
8d3f938d
JO
1722 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1723}
1724
1725static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1726 struct hist_entry *a, struct hist_entry *b)
1727{
1728 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1729 struct c2c_dimension *dim = c2c_fmt->dim;
1730
1731 return dim->se->se_cmp(a, b);
1732}
1733
1734static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1735 struct hist_entry *a, struct hist_entry *b)
1736{
1737 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1738 struct c2c_dimension *dim = c2c_fmt->dim;
1739 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1740
1741 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1742 return collapse_fn(a, b);
1743}
1744
c75540e3
JO
1745static struct c2c_fmt *get_format(const char *name)
1746{
1747 struct c2c_dimension *dim = get_dimension(name);
1748 struct c2c_fmt *c2c_fmt;
1749 struct perf_hpp_fmt *fmt;
1750
1751 if (!dim)
1752 return NULL;
1753
1754 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1755 if (!c2c_fmt)
1756 return NULL;
1757
1758 c2c_fmt->dim = dim;
1759
1760 fmt = &c2c_fmt->fmt;
1761 INIT_LIST_HEAD(&fmt->list);
1762 INIT_LIST_HEAD(&fmt->sort_list);
1763
8d3f938d
JO
1764 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1765 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
9cb3500a 1766 fmt->color = dim->se ? NULL : dim->color;
8d3f938d 1767 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
c75540e3
JO
1768 fmt->header = c2c_header;
1769 fmt->width = c2c_width;
8d3f938d 1770 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
c75540e3
JO
1771 fmt->equal = fmt_equal;
1772 fmt->free = fmt_free;
1773
1774 return c2c_fmt;
1775}
1776
1777static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1778{
1779 struct c2c_fmt *c2c_fmt = get_format(name);
1780
5f2eca83
JO
1781 if (!c2c_fmt) {
1782 reset_dimensions();
1783 return output_field_add(hpp_list, name);
1784 }
c75540e3
JO
1785
1786 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1787 return 0;
1788}
1789
1790static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1791{
1792 struct c2c_fmt *c2c_fmt = get_format(name);
51dedaa4 1793 struct c2c_dimension *dim;
c75540e3 1794
5f2eca83
JO
1795 if (!c2c_fmt) {
1796 reset_dimensions();
1797 return sort_dimension__add(hpp_list, name, NULL, 0);
1798 }
c75540e3 1799
51dedaa4
JO
1800 dim = c2c_fmt->dim;
1801 if (dim == &dim_dso)
1802 hpp_list->dso = 1;
1803
c75540e3
JO
1804 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1805 return 0;
1806}
1807
1808#define PARSE_LIST(_list, _fn) \
1809 do { \
1810 char *tmp, *tok; \
1811 ret = 0; \
1812 \
1813 if (!_list) \
1814 break; \
1815 \
1816 for (tok = strtok_r((char *)_list, ", ", &tmp); \
1817 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
1818 ret = _fn(hpp_list, tok); \
1819 if (ret == -EINVAL) { \
62d94b00 1820 pr_err("Invalid --fields key: `%s'", tok); \
c75540e3
JO
1821 break; \
1822 } else if (ret == -ESRCH) { \
62d94b00 1823 pr_err("Unknown --fields key: `%s'", tok); \
c75540e3
JO
1824 break; \
1825 } \
1826 } \
1827 } while (0)
1828
1829static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1830 const char *output_,
1831 const char *sort_)
1832{
1833 char *output = output_ ? strdup(output_) : NULL;
1834 char *sort = sort_ ? strdup(sort_) : NULL;
1835 int ret;
1836
1837 PARSE_LIST(output, c2c_hists__init_output);
1838 PARSE_LIST(sort, c2c_hists__init_sort);
1839
1840 /* copy sort keys to output fields */
1841 perf_hpp__setup_output_field(hpp_list);
1842
1843 /*
1844 * We dont need other sorting keys other than those
1845 * we already specified. It also really slows down
1846 * the processing a lot with big number of output
1847 * fields, so switching this off for c2c.
1848 */
1849
1850#if 0
1851 /* and then copy output fields to sort keys */
1852 perf_hpp__append_sort_keys(&hists->list);
1853#endif
1854
1855 free(output);
1856 free(sort);
1857 return ret;
1858}
1859
1860static int c2c_hists__init(struct c2c_hists *hists,
1d62fcd6
JO
1861 const char *sort,
1862 int nr_header_lines)
c75540e3
JO
1863{
1864 __hists__init(&hists->hists, &hists->list);
1865
1866 /*
1867 * Initialize only with sort fields, we need to resort
1868 * later anyway, and that's where we add output fields
1869 * as well.
1870 */
1871 perf_hpp_list__init(&hists->list);
1872
1d62fcd6
JO
1873 /* Overload number of header lines.*/
1874 hists->list.nr_header_lines = nr_header_lines;
1875
c75540e3
JO
1876 return hpp_list__parse(&hists->list, NULL, sort);
1877}
1878
c75540e3
JO
1879static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1880 const char *output,
1881 const char *sort)
1882{
1883 perf_hpp__reset_output_field(&c2c_hists->list);
1884 return hpp_list__parse(&c2c_hists->list, output, sort);
1885}
1886
c4a75bb9 1887#define DISPLAY_LINE_LIMIT 0.001
9857b717
JO
1888
1889static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
1890{
1891 struct c2c_hist_entry *c2c_he;
1892 double ld_dist;
1893
af09b2d3
JO
1894 if (c2c.show_all)
1895 return true;
9857b717
JO
1896
1897 c2c_he = container_of(he, struct c2c_hist_entry, he);
1898
55b95776
JO
1899#define FILTER_HITM(__h) \
1900 if (stats->__h) { \
1901 ld_dist = ((double)c2c_he->stats.__h / stats->__h); \
1902 if (ld_dist < DISPLAY_LINE_LIMIT) \
1903 he->filtered = HIST_FILTER__C2C; \
1904 } else { \
1905 he->filtered = HIST_FILTER__C2C; \
9857b717
JO
1906 }
1907
55b95776
JO
1908 switch (c2c.display) {
1909 case DISPLAY_LCL:
1910 FILTER_HITM(lcl_hitm);
1911 break;
1912 case DISPLAY_RMT:
1913 FILTER_HITM(rmt_hitm);
d940bacc
JO
1914 break;
1915 case DISPLAY_TOT:
1916 FILTER_HITM(tot_hitm);
55b95776
JO
1917 default:
1918 break;
1919 };
1920
1921#undef FILTER_HITM
1922
9857b717
JO
1923 return he->filtered == 0;
1924}
1925
1926static inline int valid_hitm_or_store(struct hist_entry *he)
1927{
1928 struct c2c_hist_entry *c2c_he;
55b95776 1929 bool has_hitm;
9857b717
JO
1930
1931 c2c_he = container_of(he, struct c2c_hist_entry, he);
d940bacc
JO
1932 has_hitm = c2c.display == DISPLAY_TOT ? c2c_he->stats.tot_hitm :
1933 c2c.display == DISPLAY_LCL ? c2c_he->stats.lcl_hitm :
1934 c2c_he->stats.rmt_hitm;
55b95776 1935 return has_hitm || c2c_he->stats.store;
9857b717
JO
1936}
1937
7f834c2e
JO
1938static void set_node_width(struct c2c_hist_entry *c2c_he, int len)
1939{
1940 struct c2c_dimension *dim;
1941
1942 dim = &c2c.hists == c2c_he->hists ?
1943 &dim_dcacheline_node : &dim_offset_node;
1944
1945 if (len > dim->width)
1946 dim->width = len;
1947}
1948
1949static int set_nodestr(struct c2c_hist_entry *c2c_he)
1950{
1951 char buf[30];
1952 int len;
1953
1954 if (c2c_he->nodestr)
1955 return 0;
1956
1957 if (bitmap_weight(c2c_he->nodeset, c2c.nodes_cnt)) {
1958 len = bitmap_scnprintf(c2c_he->nodeset, c2c.nodes_cnt,
1959 buf, sizeof(buf));
1960 } else {
1961 len = scnprintf(buf, sizeof(buf), "N/A");
1962 }
1963
1964 set_node_width(c2c_he, len);
1965 c2c_he->nodestr = strdup(buf);
1966 return c2c_he->nodestr ? 0 : -ENOMEM;
1967}
1968
37731388 1969static void calc_width(struct c2c_hist_entry *c2c_he)
25aa84e3
JO
1970{
1971 struct c2c_hists *c2c_hists;
1972
37731388
JO
1973 c2c_hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
1974 hists__calc_col_len(&c2c_hists->hists, &c2c_he->he);
7f834c2e 1975 set_nodestr(c2c_he);
25aa84e3
JO
1976}
1977
e4c38fd4 1978static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
ec06f9b9 1979{
37731388
JO
1980 struct c2c_hist_entry *c2c_he;
1981
1982 c2c_he = container_of(he, struct c2c_hist_entry, he);
1983
89d9ba8f 1984 if (c2c.show_src && !he->srcline)
6a53da05 1985 he->srcline = hist_entry__srcline(he);
89d9ba8f 1986
37731388 1987 calc_width(c2c_he);
25aa84e3 1988
9857b717
JO
1989 if (!valid_hitm_or_store(he))
1990 he->filtered = HIST_FILTER__C2C;
1991
ec06f9b9
JO
1992 return 0;
1993}
1994
e4c38fd4 1995static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
ec06f9b9
JO
1996{
1997 struct c2c_hist_entry *c2c_he;
1998 struct c2c_hists *c2c_hists;
9857b717 1999 bool display = he__display(he, &c2c.hitm_stats);
ec06f9b9
JO
2000
2001 c2c_he = container_of(he, struct c2c_hist_entry, he);
2002 c2c_hists = c2c_he->hists;
2003
9857b717 2004 if (display && c2c_hists) {
bb342dae
JO
2005 static unsigned int idx;
2006
2007 c2c_he->cacheline_idx = idx++;
bc229c21 2008 calc_width(c2c_he);
bb342dae 2009
fc9c630e 2010 c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort);
22dd59d1 2011
ec06f9b9
JO
2012 hists__collapse_resort(&c2c_hists->hists, NULL);
2013 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
2014 }
2015
2016 return 0;
2017}
2018
1e181b92
JO
2019static void setup_nodes_header(void)
2020{
2021 dim_node.header = header_node[c2c.node_info];
2022}
2023
2024static int setup_nodes(struct perf_session *session)
2025{
2026 struct numa_node *n;
2027 unsigned long **nodes;
2028 int node, cpu;
2029 int *cpu2node;
2030
2031 if (c2c.node_info > 2)
2032 c2c.node_info = 2;
2033
2034 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1ea770f6 2035 c2c.cpus_cnt = session->header.env.nr_cpus_avail;
1e181b92
JO
2036
2037 n = session->header.env.numa_nodes;
2038 if (!n)
2039 return -EINVAL;
2040
2041 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
2042 if (!nodes)
2043 return -ENOMEM;
2044
2045 c2c.nodes = nodes;
2046
2047 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
2048 if (!cpu2node)
2049 return -ENOMEM;
2050
2051 for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
2052 cpu2node[cpu] = -1;
2053
2054 c2c.cpu2node = cpu2node;
2055
2056 for (node = 0; node < c2c.nodes_cnt; node++) {
f854839b 2057 struct perf_cpu_map *map = n[node].map;
1e181b92
JO
2058 unsigned long *set;
2059
2060 set = bitmap_alloc(c2c.cpus_cnt);
2061 if (!set)
2062 return -ENOMEM;
2063
e34c9402
JO
2064 nodes[node] = set;
2065
2066 /* empty node, skip */
315c0a1f 2067 if (perf_cpu_map__empty(map))
e34c9402
JO
2068 continue;
2069
1e181b92
JO
2070 for (cpu = 0; cpu < map->nr; cpu++) {
2071 set_bit(map->map[cpu], set);
2072
2073 if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
2074 return -EINVAL;
2075
2076 cpu2node[map->map[cpu]] = node;
2077 }
1e181b92
JO
2078 }
2079
2080 setup_nodes_header();
2081 return 0;
2082}
2083
7ef2efaa
JO
2084#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
2085
e4c38fd4 2086static int resort_hitm_cb(struct hist_entry *he, void *arg __maybe_unused)
7ef2efaa
JO
2087{
2088 struct c2c_hist_entry *c2c_he;
2089 c2c_he = container_of(he, struct c2c_hist_entry, he);
2090
2091 if (HAS_HITMS(c2c_he)) {
2092 c2c.shared_clines++;
2093 c2c_add_stats(&c2c.hitm_stats, &c2c_he->stats);
2094 }
2095
2096 return 0;
2097}
2098
2099static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
2100{
2eb3d689 2101 struct rb_node *next = rb_first_cached(&hists->entries);
7ef2efaa
JO
2102 int ret = 0;
2103
2104 while (next) {
2105 struct hist_entry *he;
2106
2107 he = rb_entry(next, struct hist_entry, rb_node);
e4c38fd4 2108 ret = cb(he, NULL);
7ef2efaa
JO
2109 if (ret)
2110 break;
2111 next = rb_next(&he->rb_node);
2112 }
2113
2114 return ret;
2115}
2116
74c63a25
JO
2117static void print_c2c__display_stats(FILE *out)
2118{
2119 int llc_misses;
2120 struct c2c_stats *stats = &c2c.hists.stats;
2121
2122 llc_misses = stats->lcl_dram +
2123 stats->rmt_dram +
2124 stats->rmt_hit +
2125 stats->rmt_hitm;
2126
2127 fprintf(out, "=================================================\n");
2128 fprintf(out, " Trace Event Information \n");
2129 fprintf(out, "=================================================\n");
2130 fprintf(out, " Total records : %10d\n", stats->nr_entries);
2131 fprintf(out, " Locked Load/Store Operations : %10d\n", stats->locks);
2132 fprintf(out, " Load Operations : %10d\n", stats->load);
2133 fprintf(out, " Loads - uncacheable : %10d\n", stats->ld_uncache);
2134 fprintf(out, " Loads - IO : %10d\n", stats->ld_io);
2135 fprintf(out, " Loads - Miss : %10d\n", stats->ld_miss);
2136 fprintf(out, " Loads - no mapping : %10d\n", stats->ld_noadrs);
2137 fprintf(out, " Load Fill Buffer Hit : %10d\n", stats->ld_fbhit);
2138 fprintf(out, " Load L1D hit : %10d\n", stats->ld_l1hit);
2139 fprintf(out, " Load L2D hit : %10d\n", stats->ld_l2hit);
2140 fprintf(out, " Load LLC hit : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2141 fprintf(out, " Load Local HITM : %10d\n", stats->lcl_hitm);
2142 fprintf(out, " Load Remote HITM : %10d\n", stats->rmt_hitm);
2143 fprintf(out, " Load Remote HIT : %10d\n", stats->rmt_hit);
2144 fprintf(out, " Load Local DRAM : %10d\n", stats->lcl_dram);
2145 fprintf(out, " Load Remote DRAM : %10d\n", stats->rmt_dram);
2146 fprintf(out, " Load MESI State Exclusive : %10d\n", stats->ld_excl);
2147 fprintf(out, " Load MESI State Shared : %10d\n", stats->ld_shared);
2148 fprintf(out, " Load LLC Misses : %10d\n", llc_misses);
2149 fprintf(out, " LLC Misses to Local DRAM : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);
2150 fprintf(out, " LLC Misses to Remote DRAM : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);
2151 fprintf(out, " LLC Misses to Remote cache (HIT) : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.);
2152 fprintf(out, " LLC Misses to Remote cache (HITM) : %10.1f%%\n", ((double)stats->rmt_hitm/(double)llc_misses) * 100.);
2153 fprintf(out, " Store Operations : %10d\n", stats->store);
2154 fprintf(out, " Store - uncacheable : %10d\n", stats->st_uncache);
2155 fprintf(out, " Store - no mapping : %10d\n", stats->st_noadrs);
2156 fprintf(out, " Store L1D Hit : %10d\n", stats->st_l1hit);
2157 fprintf(out, " Store L1D Miss : %10d\n", stats->st_l1miss);
2158 fprintf(out, " No Page Map Rejects : %10d\n", stats->nomap);
2159 fprintf(out, " Unable to parse data source : %10d\n", stats->noparse);
2160}
2161
7ef2efaa
JO
2162static void print_shared_cacheline_info(FILE *out)
2163{
2164 struct c2c_stats *stats = &c2c.hitm_stats;
2165 int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
2166
2167 fprintf(out, "=================================================\n");
2168 fprintf(out, " Global Shared Cache Line Event Information \n");
2169 fprintf(out, "=================================================\n");
2170 fprintf(out, " Total Shared Cache Lines : %10d\n", c2c.shared_clines);
2171 fprintf(out, " Load HITs on shared lines : %10d\n", stats->load);
2172 fprintf(out, " Fill Buffer Hits on shared lines : %10d\n", stats->ld_fbhit);
2173 fprintf(out, " L1D hits on shared lines : %10d\n", stats->ld_l1hit);
2174 fprintf(out, " L2D hits on shared lines : %10d\n", stats->ld_l2hit);
2175 fprintf(out, " LLC hits on shared lines : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2176 fprintf(out, " Locked Access on shared lines : %10d\n", stats->locks);
2177 fprintf(out, " Store HITs on shared lines : %10d\n", stats->store);
2178 fprintf(out, " Store L1D hits on shared lines : %10d\n", stats->st_l1hit);
2179 fprintf(out, " Total Merged records : %10d\n", hitm_cnt + stats->store);
2180}
2181
2d388bd0
JO
2182static void print_cacheline(struct c2c_hists *c2c_hists,
2183 struct hist_entry *he_cl,
2184 struct perf_hpp_list *hpp_list,
2185 FILE *out)
2186{
2187 char bf[1000];
2188 struct perf_hpp hpp = {
2189 .buf = bf,
2190 .size = 1000,
2191 };
2192 static bool once;
2193
2194 if (!once) {
2195 hists__fprintf_headers(&c2c_hists->hists, out);
2196 once = true;
2197 } else {
2198 fprintf(out, "\n");
2199 }
2200
bb342dae 2201 fprintf(out, " -------------------------------------------------------------\n");
2d388bd0
JO
2202 __hist_entry__snprintf(he_cl, &hpp, hpp_list);
2203 fprintf(out, "%s\n", bf);
bb342dae 2204 fprintf(out, " -------------------------------------------------------------\n");
2d388bd0 2205
e9de7e2f 2206 hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, false);
2d388bd0
JO
2207}
2208
2209static void print_pareto(FILE *out)
2210{
2211 struct perf_hpp_list hpp_list;
2212 struct rb_node *nd;
2213 int ret;
2214
2215 perf_hpp_list__init(&hpp_list);
2216 ret = hpp_list__parse(&hpp_list,
bb342dae 2217 "cl_num,"
2d388bd0
JO
2218 "cl_rmt_hitm,"
2219 "cl_lcl_hitm,"
2220 "cl_stores_l1hit,"
2221 "cl_stores_l1miss,"
2222 "dcacheline",
2223 NULL);
2224
2225 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
2226 return;
2227
2eb3d689 2228 nd = rb_first_cached(&c2c.hists.hists.entries);
2d388bd0
JO
2229
2230 for (; nd; nd = rb_next(nd)) {
2231 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2232 struct c2c_hist_entry *c2c_he;
2233
2234 if (he->filtered)
2235 continue;
2236
2237 c2c_he = container_of(he, struct c2c_hist_entry, he);
2238 print_cacheline(c2c_he->hists, he, &hpp_list, out);
2239 }
2240}
2241
2709b97d
JO
2242static void print_c2c_info(FILE *out, struct perf_session *session)
2243{
63503dba 2244 struct evlist *evlist = session->evlist;
32dcd021 2245 struct evsel *evsel;
2709b97d
JO
2246 bool first = true;
2247
2248 fprintf(out, "=================================================\n");
2249 fprintf(out, " c2c details \n");
2250 fprintf(out, "=================================================\n");
2251
2252 evlist__for_each_entry(evlist, evsel) {
2253 fprintf(out, "%-36s: %s\n", first ? " Events" : "",
2254 perf_evsel__name(evsel));
2255 first = false;
2256 }
55b95776 2257 fprintf(out, " Cachelines sort on : %s HITMs\n",
d940bacc 2258 display_str[c2c.display]);
fc9c630e 2259 fprintf(out, " Cacheline data grouping : %s\n", c2c.cl_sort);
2709b97d
JO
2260}
2261
2262static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
2d388bd0
JO
2263{
2264 setup_pager();
2265
74c63a25 2266 print_c2c__display_stats(out);
7ef2efaa
JO
2267 fprintf(out, "\n");
2268 print_shared_cacheline_info(out);
2709b97d
JO
2269 fprintf(out, "\n");
2270 print_c2c_info(out, session);
74c63a25
JO
2271
2272 if (c2c.stats_only)
2273 return;
2274
2d388bd0
JO
2275 fprintf(out, "\n");
2276 fprintf(out, "=================================================\n");
2277 fprintf(out, " Shared Data Cache Line Table \n");
2278 fprintf(out, "=================================================\n");
2279 fprintf(out, "#\n");
2280
e9de7e2f 2281 hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, true);
2d388bd0
JO
2282
2283 fprintf(out, "\n");
2284 fprintf(out, "=================================================\n");
2285 fprintf(out, " Shared Cache Line Distribution Pareto \n");
2286 fprintf(out, "=================================================\n");
2287 fprintf(out, "#\n");
2288
2289 print_pareto(out);
2290}
1e181b92 2291
5a1a99cd
JO
2292#ifdef HAVE_SLANG_SUPPORT
2293static void c2c_browser__update_nr_entries(struct hist_browser *hb)
2294{
2295 u64 nr_entries = 0;
2eb3d689 2296 struct rb_node *nd = rb_first_cached(&hb->hists->entries);
5a1a99cd
JO
2297
2298 while (nd) {
2299 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2300
2301 if (!he->filtered)
2302 nr_entries++;
2303
2304 nd = rb_next(nd);
2305 }
2306
2307 hb->nr_non_filtered_entries = nr_entries;
2308}
2309
f1c5fd4d
JO
2310struct c2c_cacheline_browser {
2311 struct hist_browser hb;
2312 struct hist_entry *he;
2313};
2314
2315static int
2316perf_c2c_cacheline_browser__title(struct hist_browser *browser,
2317 char *bf, size_t size)
2318{
2319 struct c2c_cacheline_browser *cl_browser;
2320 struct hist_entry *he;
2321 uint64_t addr = 0;
2322
2323 cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
2324 he = cl_browser->he;
2325
2326 if (he->mem_info)
2327 addr = cl_address(he->mem_info->daddr.addr);
2328
2329 scnprintf(bf, size, "Cacheline 0x%lx", addr);
2330 return 0;
2331}
2332
2333static struct c2c_cacheline_browser*
2334c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
2335{
2336 struct c2c_cacheline_browser *browser;
2337
2338 browser = zalloc(sizeof(*browser));
2339 if (browser) {
2340 hist_browser__init(&browser->hb, hists);
2341 browser->hb.c2c_filter = true;
2342 browser->hb.title = perf_c2c_cacheline_browser__title;
2343 browser->he = he;
2344 }
2345
2346 return browser;
2347}
2348
2349static int perf_c2c__browse_cacheline(struct hist_entry *he)
2350{
2351 struct c2c_hist_entry *c2c_he;
2352 struct c2c_hists *c2c_hists;
2353 struct c2c_cacheline_browser *cl_browser;
2354 struct hist_browser *browser;
2355 int key = -1;
49b8e2be 2356 static const char help[] =
239fb4fe
KP
2357 " ENTER Toggle callchains (if present) \n"
2358 " n Toggle Node details info \n"
2359 " s Toggle full length of symbol and source line columns \n"
9a406eb6 2360 " q Return back to cacheline list \n";
73978332
JO
2361
2362 if (!he)
2363 return 0;
f1c5fd4d 2364
590b6a3a
JO
2365 /* Display compact version first. */
2366 c2c.symbol_full = false;
2367
f1c5fd4d
JO
2368 c2c_he = container_of(he, struct c2c_hist_entry, he);
2369 c2c_hists = c2c_he->hists;
2370
2371 cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
2372 if (cl_browser == NULL)
2373 return -1;
2374
2375 browser = &cl_browser->hb;
2376
2377 /* reset abort key so that it can get Ctrl-C as a key */
2378 SLang_reset_tty();
2379 SLang_init_tty(0, 0, 0);
2380
2381 c2c_browser__update_nr_entries(browser);
2382
2383 while (1) {
06cc1a47 2384 key = hist_browser__run(browser, "? - help", true);
f1c5fd4d
JO
2385
2386 switch (key) {
590b6a3a
JO
2387 case 's':
2388 c2c.symbol_full = !c2c.symbol_full;
2389 break;
1a56a425
JO
2390 case 'n':
2391 c2c.node_info = (c2c.node_info + 1) % 3;
2392 setup_nodes_header();
2393 break;
f1c5fd4d
JO
2394 case 'q':
2395 goto out;
9a406eb6
JO
2396 case '?':
2397 ui_browser__help_window(&browser->b, help);
2398 break;
f1c5fd4d
JO
2399 default:
2400 break;
2401 }
2402 }
2403
2404out:
2405 free(cl_browser);
2406 return 0;
2407}
2408
5a1a99cd
JO
2409static int perf_c2c_browser__title(struct hist_browser *browser,
2410 char *bf, size_t size)
2411{
2412 scnprintf(bf, size,
55b95776
JO
2413 "Shared Data Cache Line Table "
2414 "(%lu entries, sorted on %s HITMs)",
2415 browser->nr_non_filtered_entries,
d940bacc 2416 display_str[c2c.display]);
5a1a99cd
JO
2417 return 0;
2418}
2419
2420static struct hist_browser*
2421perf_c2c_browser__new(struct hists *hists)
2422{
2423 struct hist_browser *browser = hist_browser__new(hists);
2424
2425 if (browser) {
2426 browser->title = perf_c2c_browser__title;
2427 browser->c2c_filter = true;
2428 }
2429
2430 return browser;
2431}
2432
2433static int perf_c2c__hists_browse(struct hists *hists)
2434{
2435 struct hist_browser *browser;
2436 int key = -1;
49b8e2be 2437 static const char help[] =
9a406eb6 2438 " d Display cacheline details \n"
239fb4fe 2439 " ENTER Toggle callchains (if present) \n"
9a406eb6 2440 " q Quit \n";
5a1a99cd
JO
2441
2442 browser = perf_c2c_browser__new(hists);
2443 if (browser == NULL)
2444 return -1;
2445
2446 /* reset abort key so that it can get Ctrl-C as a key */
2447 SLang_reset_tty();
2448 SLang_init_tty(0, 0, 0);
2449
2450 c2c_browser__update_nr_entries(browser);
2451
2452 while (1) {
06cc1a47 2453 key = hist_browser__run(browser, "? - help", true);
5a1a99cd
JO
2454
2455 switch (key) {
2456 case 'q':
2457 goto out;
f1c5fd4d
JO
2458 case 'd':
2459 perf_c2c__browse_cacheline(browser->he_selection);
2460 break;
9a406eb6
JO
2461 case '?':
2462 ui_browser__help_window(&browser->b, help);
2463 break;
5a1a99cd
JO
2464 default:
2465 break;
2466 }
2467 }
2468
2469out:
2470 hist_browser__delete(browser);
2471 return 0;
2472}
2473
2709b97d 2474static void perf_c2c_display(struct perf_session *session)
5a1a99cd 2475{
1936feae 2476 if (use_browser == 0)
2709b97d 2477 perf_c2c__hists_fprintf(stdout, session);
5a1a99cd
JO
2478 else
2479 perf_c2c__hists_browse(&c2c.hists.hists);
2480}
2481#else
2709b97d 2482static void perf_c2c_display(struct perf_session *session)
5a1a99cd
JO
2483{
2484 use_browser = 0;
2709b97d 2485 perf_c2c__hists_fprintf(stdout, session);
5a1a99cd
JO
2486}
2487#endif /* HAVE_SLANG_SUPPORT */
2488
d0802b1e 2489static char *fill_line(const char *orig, int len)
5a1a99cd 2490{
d0802b1e
JO
2491 int i, j, olen = strlen(orig);
2492 char *buf;
2493
2494 buf = zalloc(len + 1);
2495 if (!buf)
2496 return NULL;
2497
2498 j = len / 2 - olen / 2;
2499
2500 for (i = 0; i < j - 1; i++)
2501 buf[i] = '-';
2502
2503 buf[i++] = ' ';
2504
2505 strcpy(buf + i, orig);
2506
2507 i += olen;
2508
2509 buf[i++] = ' ';
2510
2511 for (; i < len; i++)
2512 buf[i] = '-';
2513
2514 return buf;
2515}
2516
2517static int ui_quirks(void)
2518{
2519 const char *nodestr = "Data address";
2520 char *buf;
2521
5a1a99cd
JO
2522 if (!c2c.use_stdio) {
2523 dim_offset.width = 5;
2524 dim_offset.header = header_offset_tui;
d0802b1e 2525 nodestr = "CL";
5a1a99cd 2526 }
55b95776
JO
2527
2528 dim_percent_hitm.header = percent_hitm_header[c2c.display];
d0802b1e
JO
2529
2530 /* Fix the zero line for dcacheline column. */
2531 buf = fill_line("Cacheline", dim_dcacheline.width +
03d9fcb7
JO
2532 dim_dcacheline_node.width +
2533 dim_dcacheline_count.width + 4);
d0802b1e
JO
2534 if (!buf)
2535 return -ENOMEM;
2536
2537 dim_dcacheline.header.line[0].text = buf;
2538
2539 /* Fix the zero line for offset column. */
2540 buf = fill_line(nodestr, dim_offset.width +
03d9fcb7
JO
2541 dim_offset_node.width +
2542 dim_dcacheline_count.width + 4);
d0802b1e
JO
2543 if (!buf)
2544 return -ENOMEM;
2545
2546 dim_offset.header.line[0].text = buf;
2547
2548 return 0;
5a1a99cd
JO
2549}
2550
dd805768
JO
2551#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
2552
2553const char callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
2554 CALLCHAIN_REPORT_HELP
2555 "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
2556
2557static int
2558parse_callchain_opt(const struct option *opt, const char *arg, int unset)
2559{
2560 struct callchain_param *callchain = opt->value;
2561
2562 callchain->enabled = !unset;
2563 /*
2564 * --no-call-graph
2565 */
2566 if (unset) {
2567 symbol_conf.use_callchain = false;
2568 callchain->mode = CHAIN_NONE;
2569 return 0;
2570 }
2571
2572 return parse_callchain_report_opt(arg);
2573}
2574
63503dba 2575static int setup_callchain(struct evlist *evlist)
dd805768
JO
2576{
2577 u64 sample_type = perf_evlist__combined_sample_type(evlist);
2578 enum perf_call_graph_mode mode = CALLCHAIN_NONE;
2579
2580 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
eabad8c6 2581 (sample_type & PERF_SAMPLE_STACK_USER)) {
dd805768 2582 mode = CALLCHAIN_DWARF;
eabad8c6
ACM
2583 dwarf_callchain_users = true;
2584 } else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
dd805768
JO
2585 mode = CALLCHAIN_LBR;
2586 else if (sample_type & PERF_SAMPLE_CALLCHAIN)
2587 mode = CALLCHAIN_FP;
2588
2589 if (!callchain_param.enabled &&
2590 callchain_param.mode != CHAIN_NONE &&
2591 mode != CALLCHAIN_NONE) {
2592 symbol_conf.use_callchain = true;
2593 if (callchain_register_param(&callchain_param) < 0) {
2594 ui__error("Can't register callchain params.\n");
2595 return -EINVAL;
2596 }
2597 }
2598
2599 callchain_param.record_mode = mode;
2600 callchain_param.min_percent = 0;
2601 return 0;
2602}
2603
55b95776
JO
2604static int setup_display(const char *str)
2605{
d940bacc 2606 const char *display = str ?: "tot";
55b95776 2607
d940bacc
JO
2608 if (!strcmp(display, "tot"))
2609 c2c.display = DISPLAY_TOT;
2610 else if (!strcmp(display, "rmt"))
55b95776
JO
2611 c2c.display = DISPLAY_RMT;
2612 else if (!strcmp(display, "lcl"))
2613 c2c.display = DISPLAY_LCL;
2614 else {
2615 pr_err("failed: unknown display type: %s\n", str);
2616 return -1;
2617 }
2618
2619 return 0;
2620}
2621
fc9c630e
JO
2622#define for_each_token(__tok, __buf, __sep, __tmp) \
2623 for (__tok = strtok_r(__buf, __sep, &__tmp); __tok; \
2624 __tok = strtok_r(NULL, __sep, &__tmp))
2625
18f278d2 2626static int build_cl_output(char *cl_sort, bool no_source)
fc9c630e
JO
2627{
2628 char *tok, *tmp, *buf = strdup(cl_sort);
2629 bool add_pid = false;
2630 bool add_tid = false;
2631 bool add_iaddr = false;
2632 bool add_sym = false;
2633 bool add_dso = false;
2634 bool add_src = false;
2635
2636 if (!buf)
2637 return -ENOMEM;
2638
2639 for_each_token(tok, buf, ",", tmp) {
2640 if (!strcmp(tok, "tid")) {
2641 add_tid = true;
2642 } else if (!strcmp(tok, "pid")) {
2643 add_pid = true;
2644 } else if (!strcmp(tok, "iaddr")) {
2645 add_iaddr = true;
2646 add_sym = true;
2647 add_dso = true;
18f278d2 2648 add_src = no_source ? false : true;
fc9c630e
JO
2649 } else if (!strcmp(tok, "dso")) {
2650 add_dso = true;
2651 } else if (strcmp(tok, "offset")) {
2652 pr_err("unrecognized sort token: %s\n", tok);
2653 return -EINVAL;
2654 }
2655 }
2656
2657 if (asprintf(&c2c.cl_output,
bb342dae
JO
2658 "%s%s%s%s%s%s%s%s%s%s",
2659 c2c.use_stdio ? "cl_num_empty," : "",
fc9c630e
JO
2660 "percent_rmt_hitm,"
2661 "percent_lcl_hitm,"
2662 "percent_stores_l1hit,"
2663 "percent_stores_l1miss,"
03d9fcb7 2664 "offset,offset_node,dcacheline_count,",
fc9c630e
JO
2665 add_pid ? "pid," : "",
2666 add_tid ? "tid," : "",
2667 add_iaddr ? "iaddr," : "",
2668 "mean_rmt,"
2669 "mean_lcl,"
2670 "mean_load,"
8763e6ac 2671 "tot_recs,"
fc9c630e
JO
2672 "cpucnt,",
2673 add_sym ? "symbol," : "",
2674 add_dso ? "dso," : "",
2675 add_src ? "cl_srcline," : "",
2676 "node") < 0)
2677 return -ENOMEM;
2678
2679 c2c.show_src = add_src;
2680
2681 free(buf);
2682 return 0;
2683}
2684
18f278d2 2685static int setup_coalesce(const char *coalesce, bool no_source)
fc9c630e
JO
2686{
2687 const char *c = coalesce ?: coalesce_default;
2688
2689 if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)
2690 return -ENOMEM;
2691
18f278d2 2692 if (build_cl_output(c2c.cl_sort, no_source))
fc9c630e
JO
2693 return -1;
2694
2695 if (asprintf(&c2c.cl_resort, "offset,%s",
d940bacc
JO
2696 c2c.display == DISPLAY_TOT ?
2697 "tot_hitm" :
fc9c630e
JO
2698 c2c.display == DISPLAY_RMT ?
2699 "rmt_hitm,lcl_hitm" :
2700 "lcl_hitm,rmt_hitm") < 0)
2701 return -ENOMEM;
2702
2703 pr_debug("coalesce sort fields: %s\n", c2c.cl_sort);
2704 pr_debug("coalesce resort fields: %s\n", c2c.cl_resort);
2705 pr_debug("coalesce output fields: %s\n", c2c.cl_output);
2706 return 0;
2707}
2708
903a6f15
JO
2709static int perf_c2c__report(int argc, const char **argv)
2710{
2711 struct perf_session *session;
78b27543 2712 struct ui_progress prog;
8ceb41d7 2713 struct perf_data data = {
903a6f15
JO
2714 .mode = PERF_DATA_MODE_READ,
2715 };
dd805768 2716 char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
55b95776 2717 const char *display = NULL;
fc9c630e 2718 const char *coalesce = NULL;
18f278d2 2719 bool no_source = false;
3a5bfab6 2720 const struct option options[] = {
903a6f15
JO
2721 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
2722 "file", "vmlinux pathname"),
903a6f15
JO
2723 OPT_STRING('i', "input", &input_name, "file",
2724 "the input file to process"),
1e181b92
JO
2725 OPT_INCR('N', "node-info", &c2c.node_info,
2726 "show extra node info in report (repeat for more info)"),
5a1a99cd
JO
2727#ifdef HAVE_SLANG_SUPPORT
2728 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2729#endif
74c63a25 2730 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
f75d2895 2731 "Display only statistic tables (implies --stdio)"),
590b6a3a
JO
2732 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
2733 "Display full length of symbols"),
18f278d2
JO
2734 OPT_BOOLEAN(0, "no-source", &no_source,
2735 "Do not display Source Line column"),
af09b2d3
JO
2736 OPT_BOOLEAN(0, "show-all", &c2c.show_all,
2737 "Show all captured HITM lines."),
dd805768
JO
2738 OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
2739 "print_type,threshold[,print_limit],order,sort_key[,branch],value",
2740 callchain_help, &parse_callchain_opt,
2741 callchain_default_opt),
d940bacc 2742 OPT_STRING('d', "display", &display, "Switch HITM output type", "lcl,rmt"),
fc9c630e
JO
2743 OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
2744 "coalesce fields: pid,tid,iaddr,dso"),
b7ac4f9f 2745 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
3a5bfab6 2746 OPT_PARENT(c2c_options),
903a6f15
JO
2747 OPT_END()
2748 };
2749 int err = 0;
2750
3a5bfab6 2751 argc = parse_options(argc, argv, options, report_c2c_usage,
903a6f15 2752 PARSE_OPT_STOP_AT_NON_OPTION);
78b27543 2753 if (argc)
3a5bfab6 2754 usage_with_options(report_c2c_usage, options);
903a6f15 2755
74c63a25
JO
2756 if (c2c.stats_only)
2757 c2c.use_stdio = true;
2758
78b27543
JO
2759 if (!input_name || !strlen(input_name))
2760 input_name = "perf.data";
2761
2d4f2799
JO
2762 data.path = input_name;
2763 data.force = symbol_conf.force;
903a6f15 2764
55b95776
JO
2765 err = setup_display(display);
2766 if (err)
2767 goto out;
2768
18f278d2 2769 err = setup_coalesce(coalesce, no_source);
fc9c630e
JO
2770 if (err) {
2771 pr_debug("Failed to initialize hists\n");
2772 goto out;
2773 }
2774
1d62fcd6 2775 err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
c75540e3
JO
2776 if (err) {
2777 pr_debug("Failed to initialize hists\n");
2778 goto out;
2779 }
2780
8ceb41d7 2781 session = perf_session__new(&data, 0, &c2c.tool);
903a6f15
JO
2782 if (session == NULL) {
2783 pr_debug("No memory for session\n");
2784 goto out;
2785 }
e8c5fe10 2786
1e181b92
JO
2787 err = setup_nodes(session);
2788 if (err) {
2789 pr_err("Failed setup nodes\n");
2790 goto out;
2791 }
903a6f15 2792
7f834c2e 2793 err = mem2node__init(&c2c.mem2node, &session->header.env);
dd805768
JO
2794 if (err)
2795 goto out_session;
2796
7f834c2e
JO
2797 err = setup_callchain(session->evlist);
2798 if (err)
2799 goto out_mem2node;
2800
903a6f15 2801 if (symbol__init(&session->header.env) < 0)
7f834c2e 2802 goto out_mem2node;
903a6f15
JO
2803
2804 /* No pipe support at the moment. */
8ceb41d7 2805 if (perf_data__is_pipe(session->data)) {
903a6f15 2806 pr_debug("No pipe support at the moment.\n");
7f834c2e 2807 goto out_mem2node;
903a6f15
JO
2808 }
2809
e8c5fe10
JO
2810 if (c2c.use_stdio)
2811 use_browser = 0;
2812 else
2813 use_browser = 1;
2814
2815 setup_browser(false);
2816
78b27543
JO
2817 err = perf_session__process_events(session);
2818 if (err) {
2819 pr_err("failed to process sample\n");
7f834c2e 2820 goto out_mem2node;
78b27543
JO
2821 }
2822
22dd59d1 2823 c2c_hists__reinit(&c2c.hists,
bb342dae 2824 "cl_idx,"
22dd59d1 2825 "dcacheline,"
7f834c2e 2826 "dcacheline_node,"
03d9fcb7 2827 "dcacheline_count,"
22dd59d1
JO
2828 "tot_recs,"
2829 "percent_hitm,"
2830 "tot_hitm,lcl_hitm,rmt_hitm,"
2831 "stores,stores_l1hit,stores_l1miss,"
2832 "dram_lcl,dram_rmt,"
2833 "ld_llcmiss,"
2834 "tot_loads,"
2835 "ld_fbhit,ld_l1hit,ld_l2hit,"
2836 "ld_lclhit,ld_rmthit",
d940bacc 2837 c2c.display == DISPLAY_TOT ? "tot_hitm" :
55b95776 2838 c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm"
22dd59d1
JO
2839 );
2840
78b27543
JO
2841 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
2842
2843 hists__collapse_resort(&c2c.hists.hists, NULL);
7ef2efaa
JO
2844 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_hitm_cb);
2845 hists__iterate_cb(&c2c.hists.hists, resort_cl_cb);
78b27543
JO
2846
2847 ui_progress__finish();
2848
d0802b1e
JO
2849 if (ui_quirks()) {
2850 pr_err("failed to setup UI\n");
2851 goto out_mem2node;
2852 }
5a1a99cd 2853
2709b97d 2854 perf_c2c_display(session);
2d388bd0 2855
7f834c2e
JO
2856out_mem2node:
2857 mem2node__exit(&c2c.mem2node);
903a6f15
JO
2858out_session:
2859 perf_session__delete(session);
2860out:
2861 return err;
2862}
2863
7e6a7998 2864static int parse_record_events(const struct option *opt,
39bcd4a4
JO
2865 const char *str, int unset __maybe_unused)
2866{
2867 bool *event_set = (bool *) opt->value;
2868
2869 *event_set = true;
2870 return perf_mem_events__parse(str);
2871}
2872
2873
2874static const char * const __usage_record[] = {
2875 "perf c2c record [<options>] [<command>]",
2876 "perf c2c record [<options>] -- <command> [<options>]",
2877 NULL
2878};
2879
2880static const char * const *record_mem_usage = __usage_record;
2881
2882static int perf_c2c__record(int argc, const char **argv)
2883{
2884 int rec_argc, i = 0, j;
2885 const char **rec_argv;
2886 int ret;
2887 bool all_user = false, all_kernel = false;
2888 bool event_set = false;
2889 struct option options[] = {
2890 OPT_CALLBACK('e', "event", &event_set, "event",
2891 "event selector. Use 'perf mem record -e list' to list available events",
2892 parse_record_events),
39bcd4a4
JO
2893 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
2894 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
2895 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
3a5bfab6 2896 OPT_PARENT(c2c_options),
39bcd4a4
JO
2897 OPT_END()
2898 };
2899
2900 if (perf_mem_events__init()) {
2901 pr_err("failed: memory events not supported\n");
2902 return -1;
2903 }
2904
2905 argc = parse_options(argc, argv, options, record_mem_usage,
2906 PARSE_OPT_KEEP_UNKNOWN);
2907
8fab7843 2908 rec_argc = argc + 11; /* max number of arguments */
39bcd4a4
JO
2909 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2910 if (!rec_argv)
2911 return -1;
2912
2913 rec_argv[i++] = "record";
2914
2915 if (!event_set) {
2916 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
2917 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
2918 }
2919
2920 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
2921 rec_argv[i++] = "-W";
2922
2923 rec_argv[i++] = "-d";
8fab7843 2924 rec_argv[i++] = "--phys-data";
39bcd4a4
JO
2925 rec_argv[i++] = "--sample-cpu";
2926
2927 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
2928 if (!perf_mem_events[j].record)
2929 continue;
2930
2931 if (!perf_mem_events[j].supported) {
2932 pr_err("failed: event '%s' not supported\n",
2933 perf_mem_events[j].name);
c896f85a 2934 free(rec_argv);
39bcd4a4
JO
2935 return -1;
2936 }
2937
2938 rec_argv[i++] = "-e";
2939 rec_argv[i++] = perf_mem_events__name(j);
2940 };
2941
2942 if (all_user)
2943 rec_argv[i++] = "--all-user";
2944
2945 if (all_kernel)
2946 rec_argv[i++] = "--all-kernel";
2947
2948 for (j = 0; j < argc; j++, i++)
2949 rec_argv[i] = argv[j];
2950
2951 if (verbose > 0) {
2952 pr_debug("calling: ");
2953
2954 j = 0;
2955
2956 while (rec_argv[j]) {
2957 pr_debug("%s ", rec_argv[j]);
2958 j++;
2959 }
2960 pr_debug("\n");
2961 }
2962
b0ad8ea6 2963 ret = cmd_record(i, rec_argv);
39bcd4a4
JO
2964 free(rec_argv);
2965 return ret;
2966}
2967
b0ad8ea6 2968int cmd_c2c(int argc, const char **argv)
7aef3bf3 2969{
7aef3bf3
JO
2970 argc = parse_options(argc, argv, c2c_options, c2c_usage,
2971 PARSE_OPT_STOP_AT_NON_OPTION);
39bcd4a4
JO
2972
2973 if (!argc)
2974 usage_with_options(c2c_usage, c2c_options);
2975
2976 if (!strncmp(argv[0], "rec", 3)) {
2977 return perf_c2c__record(argc, argv);
903a6f15
JO
2978 } else if (!strncmp(argv[0], "rep", 3)) {
2979 return perf_c2c__report(argc, argv);
39bcd4a4
JO
2980 } else {
2981 usage_with_options(c2c_usage, c2c_options);
2982 }
2983
7aef3bf3
JO
2984 return 0;
2985}