]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/builtin-c2c.c
perf c2c report: Add stdio output support
[karo-tx-linux.git] / tools / perf / builtin-c2c.c
1 #include <linux/compiler.h>
2 #include <linux/kernel.h>
3 #include <linux/stringify.h>
4 #include <asm/bug.h>
5 #include "util.h"
6 #include "debug.h"
7 #include "builtin.h"
8 #include <subcmd/parse-options.h>
9 #include "mem-events.h"
10 #include "session.h"
11 #include "hist.h"
12 #include "sort.h"
13 #include "tool.h"
14 #include "data.h"
15 #include "sort.h"
16 #include <asm/bug.h>
17
18 struct c2c_hists {
19         struct hists            hists;
20         struct perf_hpp_list    list;
21         struct c2c_stats        stats;
22 };
23
24 struct compute_stats {
25         struct stats             lcl_hitm;
26         struct stats             rmt_hitm;
27         struct stats             load;
28 };
29
30 struct c2c_hist_entry {
31         struct c2c_hists        *hists;
32         struct c2c_stats         stats;
33         unsigned long           *cpuset;
34         struct c2c_stats        *node_stats;
35
36         struct compute_stats     cstats;
37
38         /*
39          * must be at the end,
40          * because of its callchain dynamic entry
41          */
42         struct hist_entry       he;
43 };
44
45 struct perf_c2c {
46         struct perf_tool        tool;
47         struct c2c_hists        hists;
48
49         unsigned long           **nodes;
50         int                      nodes_cnt;
51         int                      cpus_cnt;
52         int                     *cpu2node;
53         int                      node_info;
54
55         bool                     show_src;
56 };
57
58 static struct perf_c2c c2c;
59
60 static void *c2c_he_zalloc(size_t size)
61 {
62         struct c2c_hist_entry *c2c_he;
63
64         c2c_he = zalloc(size + sizeof(*c2c_he));
65         if (!c2c_he)
66                 return NULL;
67
68         c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
69         if (!c2c_he->cpuset)
70                 return NULL;
71
72         c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
73         if (!c2c_he->node_stats)
74                 return NULL;
75
76         init_stats(&c2c_he->cstats.lcl_hitm);
77         init_stats(&c2c_he->cstats.rmt_hitm);
78         init_stats(&c2c_he->cstats.load);
79
80         return &c2c_he->he;
81 }
82
83 static void c2c_he_free(void *he)
84 {
85         struct c2c_hist_entry *c2c_he;
86
87         c2c_he = container_of(he, struct c2c_hist_entry, he);
88         if (c2c_he->hists) {
89                 hists__delete_entries(&c2c_he->hists->hists);
90                 free(c2c_he->hists);
91         }
92
93         free(c2c_he->cpuset);
94         free(c2c_he->node_stats);
95         free(c2c_he);
96 }
97
98 static struct hist_entry_ops c2c_entry_ops = {
99         .new    = c2c_he_zalloc,
100         .free   = c2c_he_free,
101 };
102
103 static int c2c_hists__init(struct c2c_hists *hists,
104                            const char *sort,
105                            int nr_header_lines);
106
107 static struct c2c_hists*
108 he__get_c2c_hists(struct hist_entry *he,
109                   const char *sort,
110                   int nr_header_lines)
111 {
112         struct c2c_hist_entry *c2c_he;
113         struct c2c_hists *hists;
114         int ret;
115
116         c2c_he = container_of(he, struct c2c_hist_entry, he);
117         if (c2c_he->hists)
118                 return c2c_he->hists;
119
120         hists = c2c_he->hists = zalloc(sizeof(*hists));
121         if (!hists)
122                 return NULL;
123
124         ret = c2c_hists__init(hists, sort, nr_header_lines);
125         if (ret) {
126                 free(hists);
127                 return NULL;
128         }
129
130         return hists;
131 }
132
133 static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
134                             struct perf_sample *sample)
135 {
136         if (WARN_ONCE(sample->cpu == (unsigned int) -1,
137                       "WARNING: no sample cpu value"))
138                 return;
139
140         set_bit(sample->cpu, c2c_he->cpuset);
141 }
142
143 static void compute_stats(struct c2c_hist_entry *c2c_he,
144                           struct c2c_stats *stats,
145                           u64 weight)
146 {
147         struct compute_stats *cstats = &c2c_he->cstats;
148
149         if (stats->rmt_hitm)
150                 update_stats(&cstats->rmt_hitm, weight);
151         else if (stats->lcl_hitm)
152                 update_stats(&cstats->lcl_hitm, weight);
153         else if (stats->load)
154                 update_stats(&cstats->load, weight);
155 }
156
157 static int process_sample_event(struct perf_tool *tool __maybe_unused,
158                                 union perf_event *event,
159                                 struct perf_sample *sample,
160                                 struct perf_evsel *evsel __maybe_unused,
161                                 struct machine *machine)
162 {
163         struct c2c_hists *c2c_hists = &c2c.hists;
164         struct c2c_hist_entry *c2c_he;
165         struct c2c_stats stats = { .nr_entries = 0, };
166         struct hist_entry *he;
167         struct addr_location al;
168         struct mem_info *mi, *mi_dup;
169         int ret;
170
171         if (machine__resolve(machine, &al, sample) < 0) {
172                 pr_debug("problem processing %d event, skipping it.\n",
173                          event->header.type);
174                 return -1;
175         }
176
177         mi = sample__resolve_mem(sample, &al);
178         if (mi == NULL)
179                 return -ENOMEM;
180
181         mi_dup = memdup(mi, sizeof(*mi));
182         if (!mi_dup)
183                 goto free_mi;
184
185         c2c_decode_stats(&stats, mi);
186
187         he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
188                                   &al, NULL, NULL, mi,
189                                   sample, true);
190         if (he == NULL)
191                 goto free_mi_dup;
192
193         c2c_he = container_of(he, struct c2c_hist_entry, he);
194         c2c_add_stats(&c2c_he->stats, &stats);
195         c2c_add_stats(&c2c_hists->stats, &stats);
196
197         c2c_he__set_cpu(c2c_he, sample);
198
199         hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
200         ret = hist_entry__append_callchain(he, sample);
201
202         if (!ret) {
203                 /*
204                  * There's already been warning about missing
205                  * sample's cpu value. Let's account all to
206                  * node 0 in this case, without any further
207                  * warning.
208                  *
209                  * Doing node stats only for single callchain data.
210                  */
211                 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
212                 int node = c2c.cpu2node[cpu];
213
214                 mi = mi_dup;
215
216                 mi_dup = memdup(mi, sizeof(*mi));
217                 if (!mi_dup)
218                         goto free_mi;
219
220                 c2c_hists = he__get_c2c_hists(he, "offset", 2);
221                 if (!c2c_hists)
222                         goto free_mi_dup;
223
224                 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
225                                           &al, NULL, NULL, mi,
226                                           sample, true);
227                 if (he == NULL)
228                         goto free_mi_dup;
229
230                 c2c_he = container_of(he, struct c2c_hist_entry, he);
231                 c2c_add_stats(&c2c_he->stats, &stats);
232                 c2c_add_stats(&c2c_hists->stats, &stats);
233                 c2c_add_stats(&c2c_he->node_stats[node], &stats);
234
235                 compute_stats(c2c_he, &stats, sample->weight);
236
237                 c2c_he__set_cpu(c2c_he, sample);
238
239                 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
240                 ret = hist_entry__append_callchain(he, sample);
241         }
242
243 out:
244         addr_location__put(&al);
245         return ret;
246
247 free_mi_dup:
248         free(mi_dup);
249 free_mi:
250         free(mi);
251         ret = -ENOMEM;
252         goto out;
253 }
254
255 static struct perf_c2c c2c = {
256         .tool = {
257                 .sample         = process_sample_event,
258                 .mmap           = perf_event__process_mmap,
259                 .mmap2          = perf_event__process_mmap2,
260                 .comm           = perf_event__process_comm,
261                 .exit           = perf_event__process_exit,
262                 .fork           = perf_event__process_fork,
263                 .lost           = perf_event__process_lost,
264                 .ordered_events = true,
265                 .ordering_requires_timestamps = true,
266         },
267 };
268
269 static const char * const c2c_usage[] = {
270         "perf c2c {record|report}",
271         NULL
272 };
273
274 static const char * const __usage_report[] = {
275         "perf c2c report",
276         NULL
277 };
278
279 static const char * const *report_c2c_usage = __usage_report;
280
281 #define C2C_HEADER_MAX 2
282
283 struct c2c_header {
284         struct {
285                 const char *text;
286                 int         span;
287         } line[C2C_HEADER_MAX];
288 };
289
290 struct c2c_dimension {
291         struct c2c_header        header;
292         const char              *name;
293         int                      width;
294         struct sort_entry       *se;
295
296         int64_t (*cmp)(struct perf_hpp_fmt *fmt,
297                        struct hist_entry *, struct hist_entry *);
298         int   (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
299                        struct hist_entry *he);
300         int   (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
301                        struct hist_entry *he);
302 };
303
304 struct c2c_fmt {
305         struct perf_hpp_fmt      fmt;
306         struct c2c_dimension    *dim;
307 };
308
309 static int c2c_width(struct perf_hpp_fmt *fmt,
310                      struct perf_hpp *hpp __maybe_unused,
311                      struct hists *hists __maybe_unused)
312 {
313         struct c2c_fmt *c2c_fmt;
314         struct c2c_dimension *dim;
315
316         c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
317         dim = c2c_fmt->dim;
318
319         return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
320                          c2c_fmt->dim->width;
321 }
322
323 static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
324                       struct hists *hists, int line, int *span)
325 {
326         struct perf_hpp_list *hpp_list = hists->hpp_list;
327         struct c2c_fmt *c2c_fmt;
328         struct c2c_dimension *dim;
329         const char *text = NULL;
330         int width = c2c_width(fmt, hpp, hists);
331
332         c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
333         dim = c2c_fmt->dim;
334
335         if (dim->se) {
336                 text = dim->header.line[line].text;
337                 /* Use the last line from sort_entry if not defined. */
338                 if (!text && (line == hpp_list->nr_header_lines - 1))
339                         text = dim->se->se_header;
340         } else {
341                 text = dim->header.line[line].text;
342
343                 if (*span) {
344                         (*span)--;
345                         return 0;
346                 } else {
347                         *span = dim->header.line[line].span;
348                 }
349         }
350
351         if (text == NULL)
352                 text = "";
353
354         return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
355 }
356
357 #define HEX_STR(__s, __v)                               \
358 ({                                                      \
359         scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
360         __s;                                            \
361 })
362
363 static int64_t
364 dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
365                struct hist_entry *left, struct hist_entry *right)
366 {
367         return sort__dcacheline_cmp(left, right);
368 }
369
370 static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
371                             struct hist_entry *he)
372 {
373         uint64_t addr = 0;
374         int width = c2c_width(fmt, hpp, he->hists);
375         char buf[20];
376
377         if (he->mem_info)
378                 addr = cl_address(he->mem_info->daddr.addr);
379
380         return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
381 }
382
383 static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
384                         struct hist_entry *he)
385 {
386         uint64_t addr = 0;
387         int width = c2c_width(fmt, hpp, he->hists);
388         char buf[20];
389
390         if (he->mem_info)
391                 addr = cl_offset(he->mem_info->daddr.al_addr);
392
393         return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
394 }
395
396 static int64_t
397 offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
398            struct hist_entry *left, struct hist_entry *right)
399 {
400         uint64_t l = 0, r = 0;
401
402         if (left->mem_info)
403                 l = cl_offset(left->mem_info->daddr.addr);
404         if (right->mem_info)
405                 r = cl_offset(right->mem_info->daddr.addr);
406
407         return (int64_t)(r - l);
408 }
409
410 static int
411 iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
412             struct hist_entry *he)
413 {
414         uint64_t addr = 0;
415         int width = c2c_width(fmt, hpp, he->hists);
416         char buf[20];
417
418         if (he->mem_info)
419                 addr = he->mem_info->iaddr.addr;
420
421         return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
422 }
423
424 static int64_t
425 iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
426           struct hist_entry *left, struct hist_entry *right)
427 {
428         return sort__iaddr_cmp(left, right);
429 }
430
431 static int
432 tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
433                struct hist_entry *he)
434 {
435         struct c2c_hist_entry *c2c_he;
436         int width = c2c_width(fmt, hpp, he->hists);
437         unsigned int tot_hitm;
438
439         c2c_he = container_of(he, struct c2c_hist_entry, he);
440         tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
441
442         return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
443 }
444
445 static int64_t
446 tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
447              struct hist_entry *left, struct hist_entry *right)
448 {
449         struct c2c_hist_entry *c2c_left;
450         struct c2c_hist_entry *c2c_right;
451         unsigned int tot_hitm_left;
452         unsigned int tot_hitm_right;
453
454         c2c_left  = container_of(left, struct c2c_hist_entry, he);
455         c2c_right = container_of(right, struct c2c_hist_entry, he);
456
457         tot_hitm_left  = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
458         tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
459
460         return tot_hitm_left - tot_hitm_right;
461 }
462
463 #define STAT_FN_ENTRY(__f)                                      \
464 static int                                                      \
465 __f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,   \
466               struct hist_entry *he)                            \
467 {                                                               \
468         struct c2c_hist_entry *c2c_he;                          \
469         int width = c2c_width(fmt, hpp, he->hists);             \
470                                                                 \
471         c2c_he = container_of(he, struct c2c_hist_entry, he);   \
472         return scnprintf(hpp->buf, hpp->size, "%*u", width,     \
473                          c2c_he->stats.__f);                    \
474 }
475
476 #define STAT_FN_CMP(__f)                                                \
477 static int64_t                                                          \
478 __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused,                    \
479             struct hist_entry *left, struct hist_entry *right)          \
480 {                                                                       \
481         struct c2c_hist_entry *c2c_left, *c2c_right;                    \
482                                                                         \
483         c2c_left  = container_of(left, struct c2c_hist_entry, he);      \
484         c2c_right = container_of(right, struct c2c_hist_entry, he);     \
485         return c2c_left->stats.__f - c2c_right->stats.__f;              \
486 }
487
488 #define STAT_FN(__f)            \
489         STAT_FN_ENTRY(__f)      \
490         STAT_FN_CMP(__f)
491
492 STAT_FN(rmt_hitm)
493 STAT_FN(lcl_hitm)
494 STAT_FN(store)
495 STAT_FN(st_l1hit)
496 STAT_FN(st_l1miss)
497 STAT_FN(ld_fbhit)
498 STAT_FN(ld_l1hit)
499 STAT_FN(ld_l2hit)
500 STAT_FN(ld_llchit)
501 STAT_FN(rmt_hit)
502
503 static uint64_t llc_miss(struct c2c_stats *stats)
504 {
505         uint64_t llcmiss;
506
507         llcmiss = stats->lcl_dram +
508                   stats->rmt_dram +
509                   stats->rmt_hitm +
510                   stats->rmt_hit;
511
512         return llcmiss;
513 }
514
515 static int
516 ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
517                  struct hist_entry *he)
518 {
519         struct c2c_hist_entry *c2c_he;
520         int width = c2c_width(fmt, hpp, he->hists);
521
522         c2c_he = container_of(he, struct c2c_hist_entry, he);
523
524         return scnprintf(hpp->buf, hpp->size, "%*lu", width,
525                          llc_miss(&c2c_he->stats));
526 }
527
528 static int64_t
529 ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
530                struct hist_entry *left, struct hist_entry *right)
531 {
532         struct c2c_hist_entry *c2c_left;
533         struct c2c_hist_entry *c2c_right;
534
535         c2c_left  = container_of(left, struct c2c_hist_entry, he);
536         c2c_right = container_of(right, struct c2c_hist_entry, he);
537
538         return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
539 }
540
541 static uint64_t total_records(struct c2c_stats *stats)
542 {
543         uint64_t lclmiss, ldcnt, total;
544
545         lclmiss  = stats->lcl_dram +
546                    stats->rmt_dram +
547                    stats->rmt_hitm +
548                    stats->rmt_hit;
549
550         ldcnt    = lclmiss +
551                    stats->ld_fbhit +
552                    stats->ld_l1hit +
553                    stats->ld_l2hit +
554                    stats->ld_llchit +
555                    stats->lcl_hitm;
556
557         total    = ldcnt +
558                    stats->st_l1hit +
559                    stats->st_l1miss;
560
561         return total;
562 }
563
564 static int
565 tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
566                 struct hist_entry *he)
567 {
568         struct c2c_hist_entry *c2c_he;
569         int width = c2c_width(fmt, hpp, he->hists);
570         uint64_t tot_recs;
571
572         c2c_he = container_of(he, struct c2c_hist_entry, he);
573         tot_recs = total_records(&c2c_he->stats);
574
575         return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
576 }
577
578 static int64_t
579 tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
580              struct hist_entry *left, struct hist_entry *right)
581 {
582         struct c2c_hist_entry *c2c_left;
583         struct c2c_hist_entry *c2c_right;
584         uint64_t tot_recs_left;
585         uint64_t tot_recs_right;
586
587         c2c_left  = container_of(left, struct c2c_hist_entry, he);
588         c2c_right = container_of(right, struct c2c_hist_entry, he);
589
590         tot_recs_left  = total_records(&c2c_left->stats);
591         tot_recs_right = total_records(&c2c_right->stats);
592
593         return tot_recs_left - tot_recs_right;
594 }
595
596 static uint64_t total_loads(struct c2c_stats *stats)
597 {
598         uint64_t lclmiss, ldcnt;
599
600         lclmiss  = stats->lcl_dram +
601                    stats->rmt_dram +
602                    stats->rmt_hitm +
603                    stats->rmt_hit;
604
605         ldcnt    = lclmiss +
606                    stats->ld_fbhit +
607                    stats->ld_l1hit +
608                    stats->ld_l2hit +
609                    stats->ld_llchit +
610                    stats->lcl_hitm;
611
612         return ldcnt;
613 }
614
615 static int
616 tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
617                 struct hist_entry *he)
618 {
619         struct c2c_hist_entry *c2c_he;
620         int width = c2c_width(fmt, hpp, he->hists);
621         uint64_t tot_recs;
622
623         c2c_he = container_of(he, struct c2c_hist_entry, he);
624         tot_recs = total_loads(&c2c_he->stats);
625
626         return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
627 }
628
629 static int64_t
630 tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
631               struct hist_entry *left, struct hist_entry *right)
632 {
633         struct c2c_hist_entry *c2c_left;
634         struct c2c_hist_entry *c2c_right;
635         uint64_t tot_recs_left;
636         uint64_t tot_recs_right;
637
638         c2c_left  = container_of(left, struct c2c_hist_entry, he);
639         c2c_right = container_of(right, struct c2c_hist_entry, he);
640
641         tot_recs_left  = total_loads(&c2c_left->stats);
642         tot_recs_right = total_loads(&c2c_right->stats);
643
644         return tot_recs_left - tot_recs_right;
645 }
646
647 typedef double (get_percent_cb)(struct c2c_hist_entry *);
648
649 static int
650 percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
651               struct hist_entry *he, get_percent_cb get_percent)
652 {
653         struct c2c_hist_entry *c2c_he;
654         int width = c2c_width(fmt, hpp, he->hists);
655         double per;
656
657         c2c_he = container_of(he, struct c2c_hist_entry, he);
658         per = get_percent(c2c_he);
659
660         return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
661 }
662
663 static double percent_hitm(struct c2c_hist_entry *c2c_he)
664 {
665         struct c2c_hists *hists;
666         struct c2c_stats *stats;
667         struct c2c_stats *total;
668         int tot, st;
669         double p;
670
671         hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
672         stats = &c2c_he->stats;
673         total = &hists->stats;
674
675         st  = stats->rmt_hitm;
676         tot = total->rmt_hitm;
677
678         p = tot ? (double) st / tot : 0;
679
680         return 100 * p;
681 }
682
683 #define PERC_STR(__s, __v)                              \
684 ({                                                      \
685         scnprintf(__s, sizeof(__s), "%.2F%%", __v);     \
686         __s;                                            \
687 })
688
689 static int
690 percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
691                    struct hist_entry *he)
692 {
693         struct c2c_hist_entry *c2c_he;
694         int width = c2c_width(fmt, hpp, he->hists);
695         char buf[10];
696         double per;
697
698         c2c_he = container_of(he, struct c2c_hist_entry, he);
699         per = percent_hitm(c2c_he);
700         return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
701 }
702
703 static int
704 percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
705                    struct hist_entry *he)
706 {
707         return percent_color(fmt, hpp, he, percent_hitm);
708 }
709
710 static int64_t
711 percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
712                  struct hist_entry *left, struct hist_entry *right)
713 {
714         struct c2c_hist_entry *c2c_left;
715         struct c2c_hist_entry *c2c_right;
716         double per_left;
717         double per_right;
718
719         c2c_left  = container_of(left, struct c2c_hist_entry, he);
720         c2c_right = container_of(right, struct c2c_hist_entry, he);
721
722         per_left  = percent_hitm(c2c_left);
723         per_right = percent_hitm(c2c_right);
724
725         return per_left - per_right;
726 }
727
728 static struct c2c_stats *he_stats(struct hist_entry *he)
729 {
730         struct c2c_hist_entry *c2c_he;
731
732         c2c_he = container_of(he, struct c2c_hist_entry, he);
733         return &c2c_he->stats;
734 }
735
736 static struct c2c_stats *total_stats(struct hist_entry *he)
737 {
738         struct c2c_hists *hists;
739
740         hists = container_of(he->hists, struct c2c_hists, hists);
741         return &hists->stats;
742 }
743
744 static double percent(int st, int tot)
745 {
746         return tot ? 100. * (double) st / (double) tot : 0;
747 }
748
749 #define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
750
751 #define PERCENT_FN(__f)                                                         \
752 static double percent_ ## __f(struct c2c_hist_entry *c2c_he)                    \
753 {                                                                               \
754         struct c2c_hists *hists;                                                \
755                                                                                 \
756         hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);        \
757         return percent(c2c_he->stats.__f, hists->stats.__f);                    \
758 }
759
760 PERCENT_FN(rmt_hitm)
761 PERCENT_FN(lcl_hitm)
762 PERCENT_FN(st_l1hit)
763 PERCENT_FN(st_l1miss)
764
765 static int
766 percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
767                        struct hist_entry *he)
768 {
769         int width = c2c_width(fmt, hpp, he->hists);
770         double per = PERCENT(he, rmt_hitm);
771         char buf[10];
772
773         return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
774 }
775
776 static int
777 percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
778                        struct hist_entry *he)
779 {
780         return percent_color(fmt, hpp, he, percent_rmt_hitm);
781 }
782
783 static int64_t
784 percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
785                      struct hist_entry *left, struct hist_entry *right)
786 {
787         double per_left;
788         double per_right;
789
790         per_left  = PERCENT(left, lcl_hitm);
791         per_right = PERCENT(right, lcl_hitm);
792
793         return per_left - per_right;
794 }
795
796 static int
797 percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
798                        struct hist_entry *he)
799 {
800         int width = c2c_width(fmt, hpp, he->hists);
801         double per = PERCENT(he, lcl_hitm);
802         char buf[10];
803
804         return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
805 }
806
807 static int
808 percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
809                        struct hist_entry *he)
810 {
811         return percent_color(fmt, hpp, he, percent_lcl_hitm);
812 }
813
814 static int64_t
815 percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
816                      struct hist_entry *left, struct hist_entry *right)
817 {
818         double per_left;
819         double per_right;
820
821         per_left  = PERCENT(left, lcl_hitm);
822         per_right = PERCENT(right, lcl_hitm);
823
824         return per_left - per_right;
825 }
826
827 static int
828 percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
829                            struct hist_entry *he)
830 {
831         int width = c2c_width(fmt, hpp, he->hists);
832         double per = PERCENT(he, st_l1hit);
833         char buf[10];
834
835         return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
836 }
837
838 static int
839 percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
840                            struct hist_entry *he)
841 {
842         return percent_color(fmt, hpp, he, percent_st_l1hit);
843 }
844
845 static int64_t
846 percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
847                         struct hist_entry *left, struct hist_entry *right)
848 {
849         double per_left;
850         double per_right;
851
852         per_left  = PERCENT(left, st_l1hit);
853         per_right = PERCENT(right, st_l1hit);
854
855         return per_left - per_right;
856 }
857
858 static int
859 percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
860                            struct hist_entry *he)
861 {
862         int width = c2c_width(fmt, hpp, he->hists);
863         double per = PERCENT(he, st_l1miss);
864         char buf[10];
865
866         return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
867 }
868
869 static int
870 percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
871                             struct hist_entry *he)
872 {
873         return percent_color(fmt, hpp, he, percent_st_l1miss);
874 }
875
876 static int64_t
877 percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
878                           struct hist_entry *left, struct hist_entry *right)
879 {
880         double per_left;
881         double per_right;
882
883         per_left  = PERCENT(left, st_l1miss);
884         per_right = PERCENT(right, st_l1miss);
885
886         return per_left - per_right;
887 }
888
889 STAT_FN(lcl_dram)
890 STAT_FN(rmt_dram)
891
892 static int
893 pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
894           struct hist_entry *he)
895 {
896         int width = c2c_width(fmt, hpp, he->hists);
897
898         return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
899 }
900
901 static int64_t
902 pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
903         struct hist_entry *left, struct hist_entry *right)
904 {
905         return left->thread->pid_ - right->thread->pid_;
906 }
907
908 static int64_t
909 empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
910           struct hist_entry *left __maybe_unused,
911           struct hist_entry *right __maybe_unused)
912 {
913         return 0;
914 }
915
916 static int
917 node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
918            struct hist_entry *he)
919 {
920         struct c2c_hist_entry *c2c_he;
921         bool first = true;
922         int node;
923         int ret = 0;
924
925         c2c_he = container_of(he, struct c2c_hist_entry, he);
926
927         for (node = 0; node < c2c.nodes_cnt; node++) {
928                 DECLARE_BITMAP(set, c2c.cpus_cnt);
929
930                 bitmap_zero(set, c2c.cpus_cnt);
931                 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
932
933                 if (!bitmap_weight(set, c2c.cpus_cnt)) {
934                         if (c2c.node_info == 1) {
935                                 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
936                                 advance_hpp(hpp, ret);
937                         }
938                         continue;
939                 }
940
941                 if (!first) {
942                         ret = scnprintf(hpp->buf, hpp->size, " ");
943                         advance_hpp(hpp, ret);
944                 }
945
946                 switch (c2c.node_info) {
947                 case 0:
948                         ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
949                         advance_hpp(hpp, ret);
950                         break;
951                 case 1:
952                 {
953                         int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
954                         struct c2c_stats *stats = &c2c_he->node_stats[node];
955
956                         ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
957                         advance_hpp(hpp, ret);
958
959
960                         if (c2c_he->stats.rmt_hitm > 0) {
961                                 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ",
962                                                 percent(stats->rmt_hitm, c2c_he->stats.rmt_hitm));
963                         } else {
964                                 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a");
965                         }
966
967                         advance_hpp(hpp, ret);
968
969                         if (c2c_he->stats.store > 0) {
970                                 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
971                                                 percent(stats->store, c2c_he->stats.store));
972                         } else {
973                                 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
974                         }
975
976                         advance_hpp(hpp, ret);
977                         break;
978                 }
979                 case 2:
980                         ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
981                         advance_hpp(hpp, ret);
982
983                         ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
984                         advance_hpp(hpp, ret);
985
986                         ret = scnprintf(hpp->buf, hpp->size, "}");
987                         advance_hpp(hpp, ret);
988                         break;
989                 default:
990                         break;
991                 }
992
993                 first = false;
994         }
995
996         return 0;
997 }
998
999 static int
1000 mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1001            struct hist_entry *he, double mean)
1002 {
1003         int width = c2c_width(fmt, hpp, he->hists);
1004         char buf[10];
1005
1006         scnprintf(buf, 10, "%6.0f", mean);
1007         return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1008 }
1009
1010 #define MEAN_ENTRY(__func, __val)                                               \
1011 static int                                                                      \
1012 __func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he)   \
1013 {                                                                               \
1014         struct c2c_hist_entry *c2c_he;                                          \
1015         c2c_he = container_of(he, struct c2c_hist_entry, he);                   \
1016         return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val));      \
1017 }
1018
1019 MEAN_ENTRY(mean_rmt_entry,  rmt_hitm);
1020 MEAN_ENTRY(mean_lcl_entry,  lcl_hitm);
1021 MEAN_ENTRY(mean_load_entry, load);
1022
1023 static int
1024 cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1025              struct hist_entry *he)
1026 {
1027         struct c2c_hist_entry *c2c_he;
1028         int width = c2c_width(fmt, hpp, he->hists);
1029         char buf[10];
1030
1031         c2c_he = container_of(he, struct c2c_hist_entry, he);
1032
1033         scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1034         return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1035 }
1036
1037 #define HEADER_LOW(__h)                 \
1038         {                               \
1039                 .line[1] = {            \
1040                         .text = __h,    \
1041                 },                      \
1042         }
1043
1044 #define HEADER_BOTH(__h0, __h1)         \
1045         {                               \
1046                 .line[0] = {            \
1047                         .text = __h0,   \
1048                 },                      \
1049                 .line[1] = {            \
1050                         .text = __h1,   \
1051                 },                      \
1052         }
1053
1054 #define HEADER_SPAN(__h0, __h1, __s)    \
1055         {                               \
1056                 .line[0] = {            \
1057                         .text = __h0,   \
1058                         .span = __s,    \
1059                 },                      \
1060                 .line[1] = {            \
1061                         .text = __h1,   \
1062                 },                      \
1063         }
1064
1065 #define HEADER_SPAN_LOW(__h)            \
1066         {                               \
1067                 .line[1] = {            \
1068                         .text = __h,    \
1069                 },                      \
1070         }
1071
1072 static struct c2c_dimension dim_dcacheline = {
1073         .header         = HEADER_LOW("Cacheline"),
1074         .name           = "dcacheline",
1075         .cmp            = dcacheline_cmp,
1076         .entry          = dcacheline_entry,
1077         .width          = 18,
1078 };
1079
1080 static struct c2c_dimension dim_offset = {
1081         .header         = HEADER_BOTH("Data address", "Offset"),
1082         .name           = "offset",
1083         .cmp            = offset_cmp,
1084         .entry          = offset_entry,
1085         .width          = 18,
1086 };
1087
1088 static struct c2c_dimension dim_iaddr = {
1089         .header         = HEADER_LOW("Code address"),
1090         .name           = "iaddr",
1091         .cmp            = iaddr_cmp,
1092         .entry          = iaddr_entry,
1093         .width          = 18,
1094 };
1095
1096 static struct c2c_dimension dim_tot_hitm = {
1097         .header         = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1098         .name           = "tot_hitm",
1099         .cmp            = tot_hitm_cmp,
1100         .entry          = tot_hitm_entry,
1101         .width          = 7,
1102 };
1103
1104 static struct c2c_dimension dim_lcl_hitm = {
1105         .header         = HEADER_SPAN_LOW("Lcl"),
1106         .name           = "lcl_hitm",
1107         .cmp            = lcl_hitm_cmp,
1108         .entry          = lcl_hitm_entry,
1109         .width          = 7,
1110 };
1111
1112 static struct c2c_dimension dim_rmt_hitm = {
1113         .header         = HEADER_SPAN_LOW("Rmt"),
1114         .name           = "rmt_hitm",
1115         .cmp            = rmt_hitm_cmp,
1116         .entry          = rmt_hitm_entry,
1117         .width          = 7,
1118 };
1119
1120 static struct c2c_dimension dim_cl_rmt_hitm = {
1121         .header         = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1122         .name           = "cl_rmt_hitm",
1123         .cmp            = rmt_hitm_cmp,
1124         .entry          = rmt_hitm_entry,
1125         .width          = 7,
1126 };
1127
1128 static struct c2c_dimension dim_cl_lcl_hitm = {
1129         .header         = HEADER_SPAN_LOW("Lcl"),
1130         .name           = "cl_lcl_hitm",
1131         .cmp            = lcl_hitm_cmp,
1132         .entry          = lcl_hitm_entry,
1133         .width          = 7,
1134 };
1135
1136 static struct c2c_dimension dim_stores = {
1137         .header         = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1138         .name           = "stores",
1139         .cmp            = store_cmp,
1140         .entry          = store_entry,
1141         .width          = 7,
1142 };
1143
1144 static struct c2c_dimension dim_stores_l1hit = {
1145         .header         = HEADER_SPAN_LOW("L1Hit"),
1146         .name           = "stores_l1hit",
1147         .cmp            = st_l1hit_cmp,
1148         .entry          = st_l1hit_entry,
1149         .width          = 7,
1150 };
1151
1152 static struct c2c_dimension dim_stores_l1miss = {
1153         .header         = HEADER_SPAN_LOW("L1Miss"),
1154         .name           = "stores_l1miss",
1155         .cmp            = st_l1miss_cmp,
1156         .entry          = st_l1miss_entry,
1157         .width          = 7,
1158 };
1159
1160 static struct c2c_dimension dim_cl_stores_l1hit = {
1161         .header         = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1162         .name           = "cl_stores_l1hit",
1163         .cmp            = st_l1hit_cmp,
1164         .entry          = st_l1hit_entry,
1165         .width          = 7,
1166 };
1167
1168 static struct c2c_dimension dim_cl_stores_l1miss = {
1169         .header         = HEADER_SPAN_LOW("L1 Miss"),
1170         .name           = "cl_stores_l1miss",
1171         .cmp            = st_l1miss_cmp,
1172         .entry          = st_l1miss_entry,
1173         .width          = 7,
1174 };
1175
1176 static struct c2c_dimension dim_ld_fbhit = {
1177         .header         = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1178         .name           = "ld_fbhit",
1179         .cmp            = ld_fbhit_cmp,
1180         .entry          = ld_fbhit_entry,
1181         .width          = 7,
1182 };
1183
1184 static struct c2c_dimension dim_ld_l1hit = {
1185         .header         = HEADER_SPAN_LOW("L1"),
1186         .name           = "ld_l1hit",
1187         .cmp            = ld_l1hit_cmp,
1188         .entry          = ld_l1hit_entry,
1189         .width          = 7,
1190 };
1191
1192 static struct c2c_dimension dim_ld_l2hit = {
1193         .header         = HEADER_SPAN_LOW("L2"),
1194         .name           = "ld_l2hit",
1195         .cmp            = ld_l2hit_cmp,
1196         .entry          = ld_l2hit_entry,
1197         .width          = 7,
1198 };
1199
1200 static struct c2c_dimension dim_ld_llchit = {
1201         .header         = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1202         .name           = "ld_lclhit",
1203         .cmp            = ld_llchit_cmp,
1204         .entry          = ld_llchit_entry,
1205         .width          = 8,
1206 };
1207
1208 static struct c2c_dimension dim_ld_rmthit = {
1209         .header         = HEADER_SPAN_LOW("Rmt"),
1210         .name           = "ld_rmthit",
1211         .cmp            = rmt_hit_cmp,
1212         .entry          = rmt_hit_entry,
1213         .width          = 8,
1214 };
1215
1216 static struct c2c_dimension dim_ld_llcmiss = {
1217         .header         = HEADER_BOTH("LLC", "Ld Miss"),
1218         .name           = "ld_llcmiss",
1219         .cmp            = ld_llcmiss_cmp,
1220         .entry          = ld_llcmiss_entry,
1221         .width          = 7,
1222 };
1223
1224 static struct c2c_dimension dim_tot_recs = {
1225         .header         = HEADER_BOTH("Total", "records"),
1226         .name           = "tot_recs",
1227         .cmp            = tot_recs_cmp,
1228         .entry          = tot_recs_entry,
1229         .width          = 7,
1230 };
1231
1232 static struct c2c_dimension dim_tot_loads = {
1233         .header         = HEADER_BOTH("Total", "Loads"),
1234         .name           = "tot_loads",
1235         .cmp            = tot_loads_cmp,
1236         .entry          = tot_loads_entry,
1237         .width          = 7,
1238 };
1239
1240 static struct c2c_dimension dim_percent_hitm = {
1241         .header         = HEADER_LOW("%hitm"),
1242         .name           = "percent_hitm",
1243         .cmp            = percent_hitm_cmp,
1244         .entry          = percent_hitm_entry,
1245         .color          = percent_hitm_color,
1246         .width          = 7,
1247 };
1248
1249 static struct c2c_dimension dim_percent_rmt_hitm = {
1250         .header         = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1251         .name           = "percent_rmt_hitm",
1252         .cmp            = percent_rmt_hitm_cmp,
1253         .entry          = percent_rmt_hitm_entry,
1254         .color          = percent_rmt_hitm_color,
1255         .width          = 7,
1256 };
1257
1258 static struct c2c_dimension dim_percent_lcl_hitm = {
1259         .header         = HEADER_SPAN_LOW("Lcl"),
1260         .name           = "percent_lcl_hitm",
1261         .cmp            = percent_lcl_hitm_cmp,
1262         .entry          = percent_lcl_hitm_entry,
1263         .color          = percent_lcl_hitm_color,
1264         .width          = 7,
1265 };
1266
1267 static struct c2c_dimension dim_percent_stores_l1hit = {
1268         .header         = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1269         .name           = "percent_stores_l1hit",
1270         .cmp            = percent_stores_l1hit_cmp,
1271         .entry          = percent_stores_l1hit_entry,
1272         .color          = percent_stores_l1hit_color,
1273         .width          = 7,
1274 };
1275
1276 static struct c2c_dimension dim_percent_stores_l1miss = {
1277         .header         = HEADER_SPAN_LOW("L1 Miss"),
1278         .name           = "percent_stores_l1miss",
1279         .cmp            = percent_stores_l1miss_cmp,
1280         .entry          = percent_stores_l1miss_entry,
1281         .color          = percent_stores_l1miss_color,
1282         .width          = 7,
1283 };
1284
1285 static struct c2c_dimension dim_dram_lcl = {
1286         .header         = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1287         .name           = "dram_lcl",
1288         .cmp            = lcl_dram_cmp,
1289         .entry          = lcl_dram_entry,
1290         .width          = 8,
1291 };
1292
1293 static struct c2c_dimension dim_dram_rmt = {
1294         .header         = HEADER_SPAN_LOW("Rmt"),
1295         .name           = "dram_rmt",
1296         .cmp            = rmt_dram_cmp,
1297         .entry          = rmt_dram_entry,
1298         .width          = 8,
1299 };
1300
1301 static struct c2c_dimension dim_pid = {
1302         .header         = HEADER_LOW("Pid"),
1303         .name           = "pid",
1304         .cmp            = pid_cmp,
1305         .entry          = pid_entry,
1306         .width          = 7,
1307 };
1308
1309 static struct c2c_dimension dim_tid = {
1310         .header         = HEADER_LOW("Tid"),
1311         .name           = "tid",
1312         .se             = &sort_thread,
1313 };
1314
1315 static struct c2c_dimension dim_symbol = {
1316         .name           = "symbol",
1317         .se             = &sort_sym,
1318 };
1319
1320 static struct c2c_dimension dim_dso = {
1321         .header         = HEADER_BOTH("Shared", "Object"),
1322         .name           = "dso",
1323         .se             = &sort_dso,
1324 };
1325
1326 static struct c2c_header header_node[3] = {
1327         HEADER_LOW("Node"),
1328         HEADER_LOW("Node{cpus %hitms %stores}"),
1329         HEADER_LOW("Node{cpu list}"),
1330 };
1331
1332 static struct c2c_dimension dim_node = {
1333         .name           = "node",
1334         .cmp            = empty_cmp,
1335         .entry          = node_entry,
1336         .width          = 4,
1337 };
1338
1339 static struct c2c_dimension dim_mean_rmt = {
1340         .header         = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1341         .name           = "mean_rmt",
1342         .cmp            = empty_cmp,
1343         .entry          = mean_rmt_entry,
1344         .width          = 8,
1345 };
1346
1347 static struct c2c_dimension dim_mean_lcl = {
1348         .header         = HEADER_SPAN_LOW("lcl hitm"),
1349         .name           = "mean_lcl",
1350         .cmp            = empty_cmp,
1351         .entry          = mean_lcl_entry,
1352         .width          = 8,
1353 };
1354
1355 static struct c2c_dimension dim_mean_load = {
1356         .header         = HEADER_SPAN_LOW("load"),
1357         .name           = "mean_load",
1358         .cmp            = empty_cmp,
1359         .entry          = mean_load_entry,
1360         .width          = 8,
1361 };
1362
1363 static struct c2c_dimension dim_cpucnt = {
1364         .header         = HEADER_BOTH("cpu", "cnt"),
1365         .name           = "cpucnt",
1366         .cmp            = empty_cmp,
1367         .entry          = cpucnt_entry,
1368         .width          = 8,
1369 };
1370
1371 static struct c2c_dimension dim_srcline = {
1372         .name           = "cl_srcline",
1373         .se             = &sort_srcline,
1374 };
1375
1376 static struct c2c_dimension *dimensions[] = {
1377         &dim_dcacheline,
1378         &dim_offset,
1379         &dim_iaddr,
1380         &dim_tot_hitm,
1381         &dim_lcl_hitm,
1382         &dim_rmt_hitm,
1383         &dim_cl_lcl_hitm,
1384         &dim_cl_rmt_hitm,
1385         &dim_stores,
1386         &dim_stores_l1hit,
1387         &dim_stores_l1miss,
1388         &dim_cl_stores_l1hit,
1389         &dim_cl_stores_l1miss,
1390         &dim_ld_fbhit,
1391         &dim_ld_l1hit,
1392         &dim_ld_l2hit,
1393         &dim_ld_llchit,
1394         &dim_ld_rmthit,
1395         &dim_ld_llcmiss,
1396         &dim_tot_recs,
1397         &dim_tot_loads,
1398         &dim_percent_hitm,
1399         &dim_percent_rmt_hitm,
1400         &dim_percent_lcl_hitm,
1401         &dim_percent_stores_l1hit,
1402         &dim_percent_stores_l1miss,
1403         &dim_dram_lcl,
1404         &dim_dram_rmt,
1405         &dim_pid,
1406         &dim_tid,
1407         &dim_symbol,
1408         &dim_dso,
1409         &dim_node,
1410         &dim_mean_rmt,
1411         &dim_mean_lcl,
1412         &dim_mean_load,
1413         &dim_cpucnt,
1414         &dim_srcline,
1415         NULL,
1416 };
1417
1418 static void fmt_free(struct perf_hpp_fmt *fmt)
1419 {
1420         struct c2c_fmt *c2c_fmt;
1421
1422         c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1423         free(c2c_fmt);
1424 }
1425
1426 static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1427 {
1428         struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1429         struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1430
1431         return c2c_a->dim == c2c_b->dim;
1432 }
1433
1434 static struct c2c_dimension *get_dimension(const char *name)
1435 {
1436         unsigned int i;
1437
1438         for (i = 0; dimensions[i]; i++) {
1439                 struct c2c_dimension *dim = dimensions[i];
1440
1441                 if (!strcmp(dim->name, name))
1442                         return dim;
1443         };
1444
1445         return NULL;
1446 }
1447
1448 static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1449                         struct hist_entry *he)
1450 {
1451         struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1452         struct c2c_dimension *dim = c2c_fmt->dim;
1453         size_t len = fmt->user_len;
1454
1455         if (!len)
1456                 len = hists__col_len(he->hists, dim->se->se_width_idx);
1457
1458         return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1459 }
1460
1461 static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1462                           struct hist_entry *a, struct hist_entry *b)
1463 {
1464         struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1465         struct c2c_dimension *dim = c2c_fmt->dim;
1466
1467         return dim->se->se_cmp(a, b);
1468 }
1469
1470 static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1471                                struct hist_entry *a, struct hist_entry *b)
1472 {
1473         struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1474         struct c2c_dimension *dim = c2c_fmt->dim;
1475         int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1476
1477         collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1478         return collapse_fn(a, b);
1479 }
1480
1481 static struct c2c_fmt *get_format(const char *name)
1482 {
1483         struct c2c_dimension *dim = get_dimension(name);
1484         struct c2c_fmt *c2c_fmt;
1485         struct perf_hpp_fmt *fmt;
1486
1487         if (!dim)
1488                 return NULL;
1489
1490         c2c_fmt = zalloc(sizeof(*c2c_fmt));
1491         if (!c2c_fmt)
1492                 return NULL;
1493
1494         c2c_fmt->dim = dim;
1495
1496         fmt = &c2c_fmt->fmt;
1497         INIT_LIST_HEAD(&fmt->list);
1498         INIT_LIST_HEAD(&fmt->sort_list);
1499
1500         fmt->cmp        = dim->se ? c2c_se_cmp   : dim->cmp;
1501         fmt->sort       = dim->se ? c2c_se_cmp   : dim->cmp;
1502         fmt->color      = dim->se ? NULL         : dim->color;
1503         fmt->entry      = dim->se ? c2c_se_entry : dim->entry;
1504         fmt->header     = c2c_header;
1505         fmt->width      = c2c_width;
1506         fmt->collapse   = dim->se ? c2c_se_collapse : dim->cmp;
1507         fmt->equal      = fmt_equal;
1508         fmt->free       = fmt_free;
1509
1510         return c2c_fmt;
1511 }
1512
1513 static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1514 {
1515         struct c2c_fmt *c2c_fmt = get_format(name);
1516
1517         if (!c2c_fmt) {
1518                 reset_dimensions();
1519                 return output_field_add(hpp_list, name);
1520         }
1521
1522         perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1523         return 0;
1524 }
1525
1526 static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1527 {
1528         struct c2c_fmt *c2c_fmt = get_format(name);
1529         struct c2c_dimension *dim;
1530
1531         if (!c2c_fmt) {
1532                 reset_dimensions();
1533                 return sort_dimension__add(hpp_list, name, NULL, 0);
1534         }
1535
1536         dim = c2c_fmt->dim;
1537         if (dim == &dim_dso)
1538                 hpp_list->dso = 1;
1539
1540         perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1541         return 0;
1542 }
1543
1544 #define PARSE_LIST(_list, _fn)                                                  \
1545         do {                                                                    \
1546                 char *tmp, *tok;                                                \
1547                 ret = 0;                                                        \
1548                                                                                 \
1549                 if (!_list)                                                     \
1550                         break;                                                  \
1551                                                                                 \
1552                 for (tok = strtok_r((char *)_list, ", ", &tmp);                 \
1553                                 tok; tok = strtok_r(NULL, ", ", &tmp)) {        \
1554                         ret = _fn(hpp_list, tok);                               \
1555                         if (ret == -EINVAL) {                                   \
1556                                 error("Invalid --fields key: `%s'", tok);       \
1557                                 break;                                          \
1558                         } else if (ret == -ESRCH) {                             \
1559                                 error("Unknown --fields key: `%s'", tok);       \
1560                                 break;                                          \
1561                         }                                                       \
1562                 }                                                               \
1563         } while (0)
1564
1565 static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1566                            const char *output_,
1567                            const char *sort_)
1568 {
1569         char *output = output_ ? strdup(output_) : NULL;
1570         char *sort   = sort_   ? strdup(sort_) : NULL;
1571         int ret;
1572
1573         PARSE_LIST(output, c2c_hists__init_output);
1574         PARSE_LIST(sort,   c2c_hists__init_sort);
1575
1576         /* copy sort keys to output fields */
1577         perf_hpp__setup_output_field(hpp_list);
1578
1579         /*
1580          * We dont need other sorting keys other than those
1581          * we already specified. It also really slows down
1582          * the processing a lot with big number of output
1583          * fields, so switching this off for c2c.
1584          */
1585
1586 #if 0
1587         /* and then copy output fields to sort keys */
1588         perf_hpp__append_sort_keys(&hists->list);
1589 #endif
1590
1591         free(output);
1592         free(sort);
1593         return ret;
1594 }
1595
1596 static int c2c_hists__init(struct c2c_hists *hists,
1597                            const char *sort,
1598                            int nr_header_lines)
1599 {
1600         __hists__init(&hists->hists, &hists->list);
1601
1602         /*
1603          * Initialize only with sort fields, we need to resort
1604          * later anyway, and that's where we add output fields
1605          * as well.
1606          */
1607         perf_hpp_list__init(&hists->list);
1608
1609         /* Overload number of header lines.*/
1610         hists->list.nr_header_lines = nr_header_lines;
1611
1612         return hpp_list__parse(&hists->list, NULL, sort);
1613 }
1614
1615 __maybe_unused
1616 static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1617                              const char *output,
1618                              const char *sort)
1619 {
1620         perf_hpp__reset_output_field(&c2c_hists->list);
1621         return hpp_list__parse(&c2c_hists->list, output, sort);
1622 }
1623
1624 static int filter_cb(struct hist_entry *he)
1625 {
1626         if (c2c.show_src && !he->srcline)
1627                 he->srcline = hist_entry__get_srcline(he);
1628
1629         return 0;
1630 }
1631
1632 static int resort_cl_cb(struct hist_entry *he)
1633 {
1634         struct c2c_hist_entry *c2c_he;
1635         struct c2c_hists *c2c_hists;
1636
1637         c2c_he = container_of(he, struct c2c_hist_entry, he);
1638         c2c_hists = c2c_he->hists;
1639
1640         if (c2c_hists) {
1641                 c2c_hists__reinit(c2c_hists,
1642                         "percent_rmt_hitm,"
1643                         "percent_lcl_hitm,"
1644                         "percent_stores_l1hit,"
1645                         "percent_stores_l1miss,"
1646                         "offset,"
1647                         "pid,"
1648                         "tid,"
1649                         "mean_rmt,"
1650                         "mean_lcl,"
1651                         "mean_load,"
1652                         "cpucnt,"
1653                         "symbol,"
1654                         "dso,"
1655                         "node",
1656                         "offset,rmt_hitm,lcl_hitm");
1657
1658                 hists__collapse_resort(&c2c_hists->hists, NULL);
1659                 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
1660         }
1661
1662         return 0;
1663 }
1664
1665 static void setup_nodes_header(void)
1666 {
1667         dim_node.header = header_node[c2c.node_info];
1668 }
1669
1670 static int setup_nodes(struct perf_session *session)
1671 {
1672         struct numa_node *n;
1673         unsigned long **nodes;
1674         int node, cpu;
1675         int *cpu2node;
1676
1677         if (c2c.node_info > 2)
1678                 c2c.node_info = 2;
1679
1680         c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1681         c2c.cpus_cnt  = session->header.env.nr_cpus_online;
1682
1683         n = session->header.env.numa_nodes;
1684         if (!n)
1685                 return -EINVAL;
1686
1687         nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
1688         if (!nodes)
1689                 return -ENOMEM;
1690
1691         c2c.nodes = nodes;
1692
1693         cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
1694         if (!cpu2node)
1695                 return -ENOMEM;
1696
1697         for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
1698                 cpu2node[cpu] = -1;
1699
1700         c2c.cpu2node = cpu2node;
1701
1702         for (node = 0; node < c2c.nodes_cnt; node++) {
1703                 struct cpu_map *map = n[node].map;
1704                 unsigned long *set;
1705
1706                 set = bitmap_alloc(c2c.cpus_cnt);
1707                 if (!set)
1708                         return -ENOMEM;
1709
1710                 for (cpu = 0; cpu < map->nr; cpu++) {
1711                         set_bit(map->map[cpu], set);
1712
1713                         if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
1714                                 return -EINVAL;
1715
1716                         cpu2node[map->map[cpu]] = node;
1717                 }
1718
1719                 nodes[node] = set;
1720         }
1721
1722         setup_nodes_header();
1723         return 0;
1724 }
1725
1726 static void print_cacheline(struct c2c_hists *c2c_hists,
1727                             struct hist_entry *he_cl,
1728                             struct perf_hpp_list *hpp_list,
1729                             FILE *out)
1730 {
1731         char bf[1000];
1732         struct perf_hpp hpp = {
1733                 .buf            = bf,
1734                 .size           = 1000,
1735         };
1736         static bool once;
1737
1738         if (!once) {
1739                 hists__fprintf_headers(&c2c_hists->hists, out);
1740                 once = true;
1741         } else {
1742                 fprintf(out, "\n");
1743         }
1744
1745         fprintf(out, "  ------------------------------------------------------\n");
1746         __hist_entry__snprintf(he_cl, &hpp, hpp_list);
1747         fprintf(out, "%s\n", bf);
1748         fprintf(out, "  ------------------------------------------------------\n");
1749
1750         hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, true);
1751 }
1752
1753 static void print_pareto(FILE *out)
1754 {
1755         struct perf_hpp_list hpp_list;
1756         struct rb_node *nd;
1757         int ret;
1758
1759         perf_hpp_list__init(&hpp_list);
1760         ret = hpp_list__parse(&hpp_list,
1761                                 "cl_rmt_hitm,"
1762                                 "cl_lcl_hitm,"
1763                                 "cl_stores_l1hit,"
1764                                 "cl_stores_l1miss,"
1765                                 "dcacheline",
1766                                 NULL);
1767
1768         if (WARN_ONCE(ret, "failed to setup sort entries\n"))
1769                 return;
1770
1771         nd = rb_first(&c2c.hists.hists.entries);
1772
1773         for (; nd; nd = rb_next(nd)) {
1774                 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1775                 struct c2c_hist_entry *c2c_he;
1776
1777                 if (he->filtered)
1778                         continue;
1779
1780                 c2c_he = container_of(he, struct c2c_hist_entry, he);
1781                 print_cacheline(c2c_he->hists, he, &hpp_list, out);
1782         }
1783 }
1784
1785 static void perf_c2c__hists_fprintf(FILE *out)
1786 {
1787         setup_pager();
1788
1789         fprintf(out, "\n");
1790         fprintf(out, "=================================================\n");
1791         fprintf(out, "           Shared Data Cache Line Table          \n");
1792         fprintf(out, "=================================================\n");
1793         fprintf(out, "#\n");
1794
1795         hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, false);
1796
1797         fprintf(out, "\n");
1798         fprintf(out, "=================================================\n");
1799         fprintf(out, "      Shared Cache Line Distribution Pareto      \n");
1800         fprintf(out, "=================================================\n");
1801         fprintf(out, "#\n");
1802
1803         print_pareto(out);
1804 }
1805
1806 static int perf_c2c__report(int argc, const char **argv)
1807 {
1808         struct perf_session *session;
1809         struct ui_progress prog;
1810         struct perf_data_file file = {
1811                 .mode = PERF_DATA_MODE_READ,
1812         };
1813         const struct option c2c_options[] = {
1814         OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1815                    "file", "vmlinux pathname"),
1816         OPT_INCR('v', "verbose", &verbose,
1817                  "be more verbose (show counter open errors, etc)"),
1818         OPT_STRING('i', "input", &input_name, "file",
1819                    "the input file to process"),
1820         OPT_INCR('N', "node-info", &c2c.node_info,
1821                  "show extra node info in report (repeat for more info)"),
1822         OPT_END()
1823         };
1824         int err = 0;
1825
1826         argc = parse_options(argc, argv, c2c_options, report_c2c_usage,
1827                              PARSE_OPT_STOP_AT_NON_OPTION);
1828         if (argc)
1829                 usage_with_options(report_c2c_usage, c2c_options);
1830
1831         if (!input_name || !strlen(input_name))
1832                 input_name = "perf.data";
1833
1834         file.path = input_name;
1835
1836         err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
1837         if (err) {
1838                 pr_debug("Failed to initialize hists\n");
1839                 goto out;
1840         }
1841
1842         session = perf_session__new(&file, 0, &c2c.tool);
1843         if (session == NULL) {
1844                 pr_debug("No memory for session\n");
1845                 goto out;
1846         }
1847         err = setup_nodes(session);
1848         if (err) {
1849                 pr_err("Failed setup nodes\n");
1850                 goto out;
1851         }
1852
1853         if (symbol__init(&session->header.env) < 0)
1854                 goto out_session;
1855
1856         /* No pipe support at the moment. */
1857         if (perf_data_file__is_pipe(session->file)) {
1858                 pr_debug("No pipe support at the moment.\n");
1859                 goto out_session;
1860         }
1861
1862         err = perf_session__process_events(session);
1863         if (err) {
1864                 pr_err("failed to process sample\n");
1865                 goto out_session;
1866         }
1867
1868         c2c_hists__reinit(&c2c.hists,
1869                         "dcacheline,"
1870                         "tot_recs,"
1871                         "percent_hitm,"
1872                         "tot_hitm,lcl_hitm,rmt_hitm,"
1873                         "stores,stores_l1hit,stores_l1miss,"
1874                         "dram_lcl,dram_rmt,"
1875                         "ld_llcmiss,"
1876                         "tot_loads,"
1877                         "ld_fbhit,ld_l1hit,ld_l2hit,"
1878                         "ld_lclhit,ld_rmthit",
1879                         "rmt_hitm"
1880                         );
1881
1882         ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
1883
1884         hists__collapse_resort(&c2c.hists.hists, NULL);
1885         hists__output_resort_cb(&c2c.hists.hists, &prog, resort_cl_cb);
1886
1887         ui_progress__finish();
1888
1889         use_browser = 0;
1890         perf_c2c__hists_fprintf(stdout);
1891
1892 out_session:
1893         perf_session__delete(session);
1894 out:
1895         return err;
1896 }
1897
1898 static int parse_record_events(const struct option *opt __maybe_unused,
1899                                const char *str, int unset __maybe_unused)
1900 {
1901         bool *event_set = (bool *) opt->value;
1902
1903         *event_set = true;
1904         return perf_mem_events__parse(str);
1905 }
1906
1907
1908 static const char * const __usage_record[] = {
1909         "perf c2c record [<options>] [<command>]",
1910         "perf c2c record [<options>] -- <command> [<options>]",
1911         NULL
1912 };
1913
1914 static const char * const *record_mem_usage = __usage_record;
1915
1916 static int perf_c2c__record(int argc, const char **argv)
1917 {
1918         int rec_argc, i = 0, j;
1919         const char **rec_argv;
1920         int ret;
1921         bool all_user = false, all_kernel = false;
1922         bool event_set = false;
1923         struct option options[] = {
1924         OPT_CALLBACK('e', "event", &event_set, "event",
1925                      "event selector. Use 'perf mem record -e list' to list available events",
1926                      parse_record_events),
1927         OPT_INCR('v', "verbose", &verbose,
1928                  "be more verbose (show counter open errors, etc)"),
1929         OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
1930         OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
1931         OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
1932         OPT_END()
1933         };
1934
1935         if (perf_mem_events__init()) {
1936                 pr_err("failed: memory events not supported\n");
1937                 return -1;
1938         }
1939
1940         argc = parse_options(argc, argv, options, record_mem_usage,
1941                              PARSE_OPT_KEEP_UNKNOWN);
1942
1943         rec_argc = argc + 10; /* max number of arguments */
1944         rec_argv = calloc(rec_argc + 1, sizeof(char *));
1945         if (!rec_argv)
1946                 return -1;
1947
1948         rec_argv[i++] = "record";
1949
1950         if (!event_set) {
1951                 perf_mem_events[PERF_MEM_EVENTS__LOAD].record  = true;
1952                 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
1953         }
1954
1955         if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
1956                 rec_argv[i++] = "-W";
1957
1958         rec_argv[i++] = "-d";
1959         rec_argv[i++] = "--sample-cpu";
1960
1961         for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
1962                 if (!perf_mem_events[j].record)
1963                         continue;
1964
1965                 if (!perf_mem_events[j].supported) {
1966                         pr_err("failed: event '%s' not supported\n",
1967                                perf_mem_events[j].name);
1968                         return -1;
1969                 }
1970
1971                 rec_argv[i++] = "-e";
1972                 rec_argv[i++] = perf_mem_events__name(j);
1973         };
1974
1975         if (all_user)
1976                 rec_argv[i++] = "--all-user";
1977
1978         if (all_kernel)
1979                 rec_argv[i++] = "--all-kernel";
1980
1981         for (j = 0; j < argc; j++, i++)
1982                 rec_argv[i] = argv[j];
1983
1984         if (verbose > 0) {
1985                 pr_debug("calling: ");
1986
1987                 j = 0;
1988
1989                 while (rec_argv[j]) {
1990                         pr_debug("%s ", rec_argv[j]);
1991                         j++;
1992                 }
1993                 pr_debug("\n");
1994         }
1995
1996         ret = cmd_record(i, rec_argv, NULL);
1997         free(rec_argv);
1998         return ret;
1999 }
2000
2001 int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused)
2002 {
2003         const struct option c2c_options[] = {
2004         OPT_INCR('v', "verbose", &verbose, "be more verbose"),
2005         OPT_END()
2006         };
2007
2008         argc = parse_options(argc, argv, c2c_options, c2c_usage,
2009                              PARSE_OPT_STOP_AT_NON_OPTION);
2010
2011         if (!argc)
2012                 usage_with_options(c2c_usage, c2c_options);
2013
2014         if (!strncmp(argv[0], "rec", 3)) {
2015                 return perf_c2c__record(argc, argv);
2016         } else if (!strncmp(argv[0], "rep", 3)) {
2017                 return perf_c2c__report(argc, argv);
2018         } else {
2019                 usage_with_options(c2c_usage, c2c_options);
2020         }
2021
2022         return 0;
2023 }