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