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