blob: 1415640c4aca5f8404b00a0f6b2d01902af029a4 [file] [log] [blame]
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02001#include <linux/compiler.h>
2#include <linux/kernel.h>
Jiri Olsacbb88502016-09-22 17:36:48 +02003#include <linux/stringify.h>
Jiri Olsa1e181b92016-06-03 15:40:28 +02004#include <asm/bug.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02005#include "util.h"
6#include "debug.h"
7#include "builtin.h"
8#include <subcmd/parse-options.h>
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02009#include "mem-events.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020010#include "session.h"
11#include "hist.h"
Jiri Olsacbb88502016-09-22 17:36:48 +020012#include "sort.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020013#include "tool.h"
14#include "data.h"
Jiri Olsa8d3f9382016-09-22 17:36:42 +020015#include "sort.h"
Jiri Olsa2d388bd2016-05-03 14:32:56 +020016#include <asm/bug.h>
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010017#include "ui/browsers/hists.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020018
Jiri Olsac75540e2016-09-22 17:36:41 +020019struct c2c_hists {
20 struct hists hists;
21 struct perf_hpp_list list;
Jiri Olsab2252ae2016-09-22 17:36:46 +020022 struct c2c_stats stats;
Jiri Olsac75540e2016-09-22 17:36:41 +020023};
24
Jiri Olsa92062d52016-06-05 13:40:53 +020025struct compute_stats {
26 struct stats lcl_hitm;
27 struct stats rmt_hitm;
28 struct stats load;
29};
30
Jiri Olsa78b27542016-09-22 17:36:44 +020031struct c2c_hist_entry {
32 struct c2c_hists *hists;
Jiri Olsab2252ae2016-09-22 17:36:46 +020033 struct c2c_stats stats;
Jiri Olsa1e181b92016-06-03 15:40:28 +020034 unsigned long *cpuset;
35 struct c2c_stats *node_stats;
Jiri Olsa92062d52016-06-05 13:40:53 +020036
37 struct compute_stats cstats;
38
Jiri Olsa78b27542016-09-22 17:36:44 +020039 /*
40 * must be at the end,
41 * because of its callchain dynamic entry
42 */
43 struct hist_entry he;
44};
45
Jiri Olsa903a6f12016-09-22 17:36:40 +020046struct perf_c2c {
Jiri Olsac75540e2016-09-22 17:36:41 +020047 struct perf_tool tool;
48 struct c2c_hists hists;
Jiri Olsa1e181b92016-06-03 15:40:28 +020049
50 unsigned long **nodes;
51 int nodes_cnt;
52 int cpus_cnt;
53 int *cpu2node;
54 int node_info;
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +020055
56 bool show_src;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010057 bool use_stdio;
Jiri Olsa903a6f12016-09-22 17:36:40 +020058};
59
60static struct perf_c2c c2c;
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020061
Jiri Olsa78b27542016-09-22 17:36:44 +020062static void *c2c_he_zalloc(size_t size)
63{
64 struct c2c_hist_entry *c2c_he;
65
66 c2c_he = zalloc(size + sizeof(*c2c_he));
67 if (!c2c_he)
68 return NULL;
69
Jiri Olsa1e181b92016-06-03 15:40:28 +020070 c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
71 if (!c2c_he->cpuset)
72 return NULL;
73
74 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
75 if (!c2c_he->node_stats)
76 return NULL;
77
Jiri Olsa92062d52016-06-05 13:40:53 +020078 init_stats(&c2c_he->cstats.lcl_hitm);
79 init_stats(&c2c_he->cstats.rmt_hitm);
80 init_stats(&c2c_he->cstats.load);
81
Jiri Olsa78b27542016-09-22 17:36:44 +020082 return &c2c_he->he;
83}
84
85static void c2c_he_free(void *he)
86{
87 struct c2c_hist_entry *c2c_he;
88
89 c2c_he = container_of(he, struct c2c_hist_entry, he);
90 if (c2c_he->hists) {
91 hists__delete_entries(&c2c_he->hists->hists);
92 free(c2c_he->hists);
93 }
94
Jiri Olsa1e181b92016-06-03 15:40:28 +020095 free(c2c_he->cpuset);
96 free(c2c_he->node_stats);
Jiri Olsa78b27542016-09-22 17:36:44 +020097 free(c2c_he);
98}
99
100static struct hist_entry_ops c2c_entry_ops = {
101 .new = c2c_he_zalloc,
102 .free = c2c_he_free,
103};
104
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200105static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200106 const char *sort,
107 int nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200108
Jiri Olsab2252ae2016-09-22 17:36:46 +0200109static struct c2c_hists*
110he__get_c2c_hists(struct hist_entry *he,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200111 const char *sort,
112 int nr_header_lines)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200113{
114 struct c2c_hist_entry *c2c_he;
115 struct c2c_hists *hists;
116 int ret;
117
118 c2c_he = container_of(he, struct c2c_hist_entry, he);
119 if (c2c_he->hists)
Jiri Olsab2252ae2016-09-22 17:36:46 +0200120 return c2c_he->hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200121
122 hists = c2c_he->hists = zalloc(sizeof(*hists));
123 if (!hists)
124 return NULL;
125
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200126 ret = c2c_hists__init(hists, sort, nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200127 if (ret) {
128 free(hists);
129 return NULL;
130 }
131
Jiri Olsab2252ae2016-09-22 17:36:46 +0200132 return hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200133}
134
Jiri Olsa1e181b92016-06-03 15:40:28 +0200135static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
136 struct perf_sample *sample)
137{
138 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
139 "WARNING: no sample cpu value"))
140 return;
141
142 set_bit(sample->cpu, c2c_he->cpuset);
143}
144
Jiri Olsa92062d52016-06-05 13:40:53 +0200145static void compute_stats(struct c2c_hist_entry *c2c_he,
146 struct c2c_stats *stats,
147 u64 weight)
148{
149 struct compute_stats *cstats = &c2c_he->cstats;
150
151 if (stats->rmt_hitm)
152 update_stats(&cstats->rmt_hitm, weight);
153 else if (stats->lcl_hitm)
154 update_stats(&cstats->lcl_hitm, weight);
155 else if (stats->load)
156 update_stats(&cstats->load, weight);
157}
158
Jiri Olsa78b27542016-09-22 17:36:44 +0200159static int process_sample_event(struct perf_tool *tool __maybe_unused,
160 union perf_event *event,
161 struct perf_sample *sample,
162 struct perf_evsel *evsel __maybe_unused,
163 struct machine *machine)
164{
Jiri Olsab2252ae2016-09-22 17:36:46 +0200165 struct c2c_hists *c2c_hists = &c2c.hists;
166 struct c2c_hist_entry *c2c_he;
167 struct c2c_stats stats = { .nr_entries = 0, };
Jiri Olsa78b27542016-09-22 17:36:44 +0200168 struct hist_entry *he;
169 struct addr_location al;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200170 struct mem_info *mi, *mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200171 int ret;
172
173 if (machine__resolve(machine, &al, sample) < 0) {
174 pr_debug("problem processing %d event, skipping it.\n",
175 event->header.type);
176 return -1;
177 }
178
179 mi = sample__resolve_mem(sample, &al);
180 if (mi == NULL)
181 return -ENOMEM;
182
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200183 mi_dup = memdup(mi, sizeof(*mi));
184 if (!mi_dup)
185 goto free_mi;
186
Jiri Olsab2252ae2016-09-22 17:36:46 +0200187 c2c_decode_stats(&stats, mi);
188
189 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsa78b27542016-09-22 17:36:44 +0200190 &al, NULL, NULL, mi,
191 sample, true);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200192 if (he == NULL)
193 goto free_mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200194
Jiri Olsab2252ae2016-09-22 17:36:46 +0200195 c2c_he = container_of(he, struct c2c_hist_entry, he);
196 c2c_add_stats(&c2c_he->stats, &stats);
197 c2c_add_stats(&c2c_hists->stats, &stats);
198
Jiri Olsa1e181b92016-06-03 15:40:28 +0200199 c2c_he__set_cpu(c2c_he, sample);
200
Jiri Olsab2252ae2016-09-22 17:36:46 +0200201 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsa78b27542016-09-22 17:36:44 +0200202 ret = hist_entry__append_callchain(he, sample);
203
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200204 if (!ret) {
Jiri Olsa1e181b92016-06-03 15:40:28 +0200205 /*
206 * There's already been warning about missing
207 * sample's cpu value. Let's account all to
208 * node 0 in this case, without any further
209 * warning.
210 *
211 * Doing node stats only for single callchain data.
212 */
213 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
214 int node = c2c.cpu2node[cpu];
215
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200216 mi = mi_dup;
217
218 mi_dup = memdup(mi, sizeof(*mi));
219 if (!mi_dup)
220 goto free_mi;
221
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200222 c2c_hists = he__get_c2c_hists(he, "offset", 2);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200223 if (!c2c_hists)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200224 goto free_mi_dup;
225
Jiri Olsab2252ae2016-09-22 17:36:46 +0200226 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200227 &al, NULL, NULL, mi,
228 sample, true);
229 if (he == NULL)
230 goto free_mi_dup;
231
Jiri Olsab2252ae2016-09-22 17:36:46 +0200232 c2c_he = container_of(he, struct c2c_hist_entry, he);
233 c2c_add_stats(&c2c_he->stats, &stats);
234 c2c_add_stats(&c2c_hists->stats, &stats);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200235 c2c_add_stats(&c2c_he->node_stats[node], &stats);
236
Jiri Olsa92062d52016-06-05 13:40:53 +0200237 compute_stats(c2c_he, &stats, sample->weight);
238
Jiri Olsa1e181b92016-06-03 15:40:28 +0200239 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200240
241 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200242 ret = hist_entry__append_callchain(he, sample);
243 }
244
245out:
Jiri Olsa78b27542016-09-22 17:36:44 +0200246 addr_location__put(&al);
247 return ret;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200248
249free_mi_dup:
250 free(mi_dup);
251free_mi:
252 free(mi);
253 ret = -ENOMEM;
254 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200255}
256
257static struct perf_c2c c2c = {
258 .tool = {
259 .sample = process_sample_event,
260 .mmap = perf_event__process_mmap,
261 .mmap2 = perf_event__process_mmap2,
262 .comm = perf_event__process_comm,
263 .exit = perf_event__process_exit,
264 .fork = perf_event__process_fork,
265 .lost = perf_event__process_lost,
266 .ordered_events = true,
267 .ordering_requires_timestamps = true,
268 },
269};
270
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200271static const char * const c2c_usage[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +0200272 "perf c2c {record|report}",
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200273 NULL
274};
275
Jiri Olsa903a6f12016-09-22 17:36:40 +0200276static const char * const __usage_report[] = {
277 "perf c2c report",
278 NULL
279};
280
281static const char * const *report_c2c_usage = __usage_report;
282
Jiri Olsac75540e2016-09-22 17:36:41 +0200283#define C2C_HEADER_MAX 2
284
285struct c2c_header {
286 struct {
287 const char *text;
288 int span;
289 } line[C2C_HEADER_MAX];
290};
291
292struct c2c_dimension {
293 struct c2c_header header;
294 const char *name;
295 int width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200296 struct sort_entry *se;
Jiri Olsac75540e2016-09-22 17:36:41 +0200297
298 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
299 struct hist_entry *, struct hist_entry *);
300 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
301 struct hist_entry *he);
302 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
303 struct hist_entry *he);
304};
305
306struct c2c_fmt {
307 struct perf_hpp_fmt fmt;
308 struct c2c_dimension *dim;
309};
310
311static int c2c_width(struct perf_hpp_fmt *fmt,
312 struct perf_hpp *hpp __maybe_unused,
313 struct hists *hists __maybe_unused)
314{
315 struct c2c_fmt *c2c_fmt;
Jiri Olsac75540e2016-09-22 17:36:41 +0200316 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +0200317
318 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
319 dim = c2c_fmt->dim;
320
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200321 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
322 c2c_fmt->dim->width;
323}
324
325static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
326 struct hists *hists, int line, int *span)
327{
328 struct perf_hpp_list *hpp_list = hists->hpp_list;
329 struct c2c_fmt *c2c_fmt;
330 struct c2c_dimension *dim;
331 const char *text = NULL;
332 int width = c2c_width(fmt, hpp, hists);
333
334 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
335 dim = c2c_fmt->dim;
336
337 if (dim->se) {
338 text = dim->header.line[line].text;
339 /* Use the last line from sort_entry if not defined. */
340 if (!text && (line == hpp_list->nr_header_lines - 1))
341 text = dim->se->se_header;
342 } else {
343 text = dim->header.line[line].text;
344
345 if (*span) {
346 (*span)--;
347 return 0;
348 } else {
349 *span = dim->header.line[line].span;
350 }
351 }
352
Jiri Olsac75540e2016-09-22 17:36:41 +0200353 if (text == NULL)
354 text = "";
355
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200356 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
Jiri Olsac75540e2016-09-22 17:36:41 +0200357}
358
Jiri Olsacbb88502016-09-22 17:36:48 +0200359#define HEX_STR(__s, __v) \
360({ \
361 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
362 __s; \
363})
364
365static int64_t
366dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
367 struct hist_entry *left, struct hist_entry *right)
368{
369 return sort__dcacheline_cmp(left, right);
370}
371
372static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
373 struct hist_entry *he)
374{
375 uint64_t addr = 0;
376 int width = c2c_width(fmt, hpp, he->hists);
377 char buf[20];
378
379 if (he->mem_info)
380 addr = cl_address(he->mem_info->daddr.addr);
381
382 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
383}
384
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200385static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
386 struct hist_entry *he)
387{
388 uint64_t addr = 0;
389 int width = c2c_width(fmt, hpp, he->hists);
390 char buf[20];
391
392 if (he->mem_info)
393 addr = cl_offset(he->mem_info->daddr.al_addr);
394
395 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
396}
397
398static int64_t
399offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
400 struct hist_entry *left, struct hist_entry *right)
401{
402 uint64_t l = 0, r = 0;
403
404 if (left->mem_info)
405 l = cl_offset(left->mem_info->daddr.addr);
406 if (right->mem_info)
407 r = cl_offset(right->mem_info->daddr.addr);
408
409 return (int64_t)(r - l);
410}
411
Jiri Olsa43575a92016-05-03 21:48:56 +0200412static int
413iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
414 struct hist_entry *he)
415{
416 uint64_t addr = 0;
417 int width = c2c_width(fmt, hpp, he->hists);
418 char buf[20];
419
420 if (he->mem_info)
421 addr = he->mem_info->iaddr.addr;
422
423 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
424}
425
426static int64_t
427iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
428 struct hist_entry *left, struct hist_entry *right)
429{
430 return sort__iaddr_cmp(left, right);
431}
432
Jiri Olsa97cb4862016-05-23 16:20:14 +0200433static int
434tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
435 struct hist_entry *he)
436{
437 struct c2c_hist_entry *c2c_he;
438 int width = c2c_width(fmt, hpp, he->hists);
439 unsigned int tot_hitm;
440
441 c2c_he = container_of(he, struct c2c_hist_entry, he);
442 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
443
444 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
445}
446
447static int64_t
448tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
449 struct hist_entry *left, struct hist_entry *right)
450{
451 struct c2c_hist_entry *c2c_left;
452 struct c2c_hist_entry *c2c_right;
453 unsigned int tot_hitm_left;
454 unsigned int tot_hitm_right;
455
456 c2c_left = container_of(left, struct c2c_hist_entry, he);
457 c2c_right = container_of(right, struct c2c_hist_entry, he);
458
459 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
460 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
461
462 return tot_hitm_left - tot_hitm_right;
463}
464
465#define STAT_FN_ENTRY(__f) \
466static int \
467__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
468 struct hist_entry *he) \
469{ \
470 struct c2c_hist_entry *c2c_he; \
471 int width = c2c_width(fmt, hpp, he->hists); \
472 \
473 c2c_he = container_of(he, struct c2c_hist_entry, he); \
474 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
475 c2c_he->stats.__f); \
476}
477
478#define STAT_FN_CMP(__f) \
479static int64_t \
480__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
481 struct hist_entry *left, struct hist_entry *right) \
482{ \
483 struct c2c_hist_entry *c2c_left, *c2c_right; \
484 \
485 c2c_left = container_of(left, struct c2c_hist_entry, he); \
486 c2c_right = container_of(right, struct c2c_hist_entry, he); \
487 return c2c_left->stats.__f - c2c_right->stats.__f; \
488}
489
490#define STAT_FN(__f) \
491 STAT_FN_ENTRY(__f) \
492 STAT_FN_CMP(__f)
493
494STAT_FN(rmt_hitm)
495STAT_FN(lcl_hitm)
Jiri Olsa0f188962016-05-04 10:10:11 +0200496STAT_FN(store)
497STAT_FN(st_l1hit)
498STAT_FN(st_l1miss)
Jiri Olsa1295f682016-05-04 10:18:24 +0200499STAT_FN(ld_fbhit)
500STAT_FN(ld_l1hit)
501STAT_FN(ld_l2hit)
Jiri Olsa4d089102016-05-04 10:27:51 +0200502STAT_FN(ld_llchit)
503STAT_FN(rmt_hit)
Jiri Olsa97cb4862016-05-23 16:20:14 +0200504
Jiri Olsa04402d22016-05-19 10:10:51 +0200505static uint64_t llc_miss(struct c2c_stats *stats)
506{
507 uint64_t llcmiss;
508
509 llcmiss = stats->lcl_dram +
510 stats->rmt_dram +
511 stats->rmt_hitm +
512 stats->rmt_hit;
513
514 return llcmiss;
515}
516
517static int
518ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
519 struct hist_entry *he)
520{
521 struct c2c_hist_entry *c2c_he;
522 int width = c2c_width(fmt, hpp, he->hists);
523
524 c2c_he = container_of(he, struct c2c_hist_entry, he);
525
526 return scnprintf(hpp->buf, hpp->size, "%*lu", width,
527 llc_miss(&c2c_he->stats));
528}
529
530static int64_t
531ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
532 struct hist_entry *left, struct hist_entry *right)
533{
534 struct c2c_hist_entry *c2c_left;
535 struct c2c_hist_entry *c2c_right;
536
537 c2c_left = container_of(left, struct c2c_hist_entry, he);
538 c2c_right = container_of(right, struct c2c_hist_entry, he);
539
540 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
541}
542
Jiri Olsa01b84d72016-05-04 10:35:29 +0200543static uint64_t total_records(struct c2c_stats *stats)
544{
545 uint64_t lclmiss, ldcnt, total;
546
547 lclmiss = stats->lcl_dram +
548 stats->rmt_dram +
549 stats->rmt_hitm +
550 stats->rmt_hit;
551
552 ldcnt = lclmiss +
553 stats->ld_fbhit +
554 stats->ld_l1hit +
555 stats->ld_l2hit +
556 stats->ld_llchit +
557 stats->lcl_hitm;
558
559 total = ldcnt +
560 stats->st_l1hit +
561 stats->st_l1miss;
562
563 return total;
564}
565
566static int
567tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
568 struct hist_entry *he)
569{
570 struct c2c_hist_entry *c2c_he;
571 int width = c2c_width(fmt, hpp, he->hists);
572 uint64_t tot_recs;
573
574 c2c_he = container_of(he, struct c2c_hist_entry, he);
575 tot_recs = total_records(&c2c_he->stats);
576
577 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
578}
579
580static int64_t
581tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
582 struct hist_entry *left, struct hist_entry *right)
583{
584 struct c2c_hist_entry *c2c_left;
585 struct c2c_hist_entry *c2c_right;
586 uint64_t tot_recs_left;
587 uint64_t tot_recs_right;
588
589 c2c_left = container_of(left, struct c2c_hist_entry, he);
590 c2c_right = container_of(right, struct c2c_hist_entry, he);
591
592 tot_recs_left = total_records(&c2c_left->stats);
593 tot_recs_right = total_records(&c2c_right->stats);
594
595 return tot_recs_left - tot_recs_right;
596}
597
Jiri Olsa55177c42016-05-19 09:52:37 +0200598static uint64_t total_loads(struct c2c_stats *stats)
599{
600 uint64_t lclmiss, ldcnt;
601
602 lclmiss = stats->lcl_dram +
603 stats->rmt_dram +
604 stats->rmt_hitm +
605 stats->rmt_hit;
606
607 ldcnt = lclmiss +
608 stats->ld_fbhit +
609 stats->ld_l1hit +
610 stats->ld_l2hit +
611 stats->ld_llchit +
612 stats->lcl_hitm;
613
614 return ldcnt;
615}
616
617static int
618tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
619 struct hist_entry *he)
620{
621 struct c2c_hist_entry *c2c_he;
622 int width = c2c_width(fmt, hpp, he->hists);
623 uint64_t tot_recs;
624
625 c2c_he = container_of(he, struct c2c_hist_entry, he);
626 tot_recs = total_loads(&c2c_he->stats);
627
628 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
629}
630
631static int64_t
632tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
633 struct hist_entry *left, struct hist_entry *right)
634{
635 struct c2c_hist_entry *c2c_left;
636 struct c2c_hist_entry *c2c_right;
637 uint64_t tot_recs_left;
638 uint64_t tot_recs_right;
639
640 c2c_left = container_of(left, struct c2c_hist_entry, he);
641 c2c_right = container_of(right, struct c2c_hist_entry, he);
642
643 tot_recs_left = total_loads(&c2c_left->stats);
644 tot_recs_right = total_loads(&c2c_right->stats);
645
646 return tot_recs_left - tot_recs_right;
647}
648
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200649typedef double (get_percent_cb)(struct c2c_hist_entry *);
650
651static int
652percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
653 struct hist_entry *he, get_percent_cb get_percent)
654{
655 struct c2c_hist_entry *c2c_he;
656 int width = c2c_width(fmt, hpp, he->hists);
657 double per;
658
659 c2c_he = container_of(he, struct c2c_hist_entry, he);
660 per = get_percent(c2c_he);
661
Jiri Olsa5a1a99c2016-01-06 16:59:02 +0100662#ifdef HAVE_SLANG_SUPPORT
663 if (use_browser)
664 return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
665#endif
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200666 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
667}
668
669static double percent_hitm(struct c2c_hist_entry *c2c_he)
670{
671 struct c2c_hists *hists;
672 struct c2c_stats *stats;
673 struct c2c_stats *total;
674 int tot, st;
675 double p;
676
677 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
678 stats = &c2c_he->stats;
679 total = &hists->stats;
680
681 st = stats->rmt_hitm;
682 tot = total->rmt_hitm;
683
684 p = tot ? (double) st / tot : 0;
685
686 return 100 * p;
687}
688
689#define PERC_STR(__s, __v) \
690({ \
691 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
692 __s; \
693})
694
695static int
696percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
697 struct hist_entry *he)
698{
699 struct c2c_hist_entry *c2c_he;
700 int width = c2c_width(fmt, hpp, he->hists);
701 char buf[10];
702 double per;
703
704 c2c_he = container_of(he, struct c2c_hist_entry, he);
705 per = percent_hitm(c2c_he);
706 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
707}
708
709static int
710percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
711 struct hist_entry *he)
712{
713 return percent_color(fmt, hpp, he, percent_hitm);
714}
715
716static int64_t
717percent_hitm_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 double per_left;
723 double per_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 per_left = percent_hitm(c2c_left);
729 per_right = percent_hitm(c2c_right);
730
731 return per_left - per_right;
732}
733
Jiri Olsa9cb35002016-05-04 12:16:50 +0200734static struct c2c_stats *he_stats(struct hist_entry *he)
735{
736 struct c2c_hist_entry *c2c_he;
737
738 c2c_he = container_of(he, struct c2c_hist_entry, he);
739 return &c2c_he->stats;
740}
741
742static struct c2c_stats *total_stats(struct hist_entry *he)
743{
744 struct c2c_hists *hists;
745
746 hists = container_of(he->hists, struct c2c_hists, hists);
747 return &hists->stats;
748}
749
750static double percent(int st, int tot)
751{
752 return tot ? 100. * (double) st / (double) tot : 0;
753}
754
755#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
756
757#define PERCENT_FN(__f) \
758static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
759{ \
760 struct c2c_hists *hists; \
761 \
762 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
763 return percent(c2c_he->stats.__f, hists->stats.__f); \
764}
765
766PERCENT_FN(rmt_hitm)
767PERCENT_FN(lcl_hitm)
768PERCENT_FN(st_l1hit)
769PERCENT_FN(st_l1miss)
770
771static int
772percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
773 struct hist_entry *he)
774{
775 int width = c2c_width(fmt, hpp, he->hists);
776 double per = PERCENT(he, rmt_hitm);
777 char buf[10];
778
779 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
780}
781
782static int
783percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
784 struct hist_entry *he)
785{
786 return percent_color(fmt, hpp, he, percent_rmt_hitm);
787}
788
789static int64_t
790percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
791 struct hist_entry *left, struct hist_entry *right)
792{
793 double per_left;
794 double per_right;
795
796 per_left = PERCENT(left, lcl_hitm);
797 per_right = PERCENT(right, lcl_hitm);
798
799 return per_left - per_right;
800}
801
802static int
803percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
804 struct hist_entry *he)
805{
806 int width = c2c_width(fmt, hpp, he->hists);
807 double per = PERCENT(he, lcl_hitm);
808 char buf[10];
809
810 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
811}
812
813static int
814percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
815 struct hist_entry *he)
816{
817 return percent_color(fmt, hpp, he, percent_lcl_hitm);
818}
819
820static int64_t
821percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
822 struct hist_entry *left, struct hist_entry *right)
823{
824 double per_left;
825 double per_right;
826
827 per_left = PERCENT(left, lcl_hitm);
828 per_right = PERCENT(right, lcl_hitm);
829
830 return per_left - per_right;
831}
832
833static int
834percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
835 struct hist_entry *he)
836{
837 int width = c2c_width(fmt, hpp, he->hists);
838 double per = PERCENT(he, st_l1hit);
839 char buf[10];
840
841 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
842}
843
844static int
845percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
846 struct hist_entry *he)
847{
848 return percent_color(fmt, hpp, he, percent_st_l1hit);
849}
850
851static int64_t
852percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
853 struct hist_entry *left, struct hist_entry *right)
854{
855 double per_left;
856 double per_right;
857
858 per_left = PERCENT(left, st_l1hit);
859 per_right = PERCENT(right, st_l1hit);
860
861 return per_left - per_right;
862}
863
864static int
865percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
866 struct hist_entry *he)
867{
868 int width = c2c_width(fmt, hpp, he->hists);
869 double per = PERCENT(he, st_l1miss);
870 char buf[10];
871
872 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
873}
874
875static int
876percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
877 struct hist_entry *he)
878{
879 return percent_color(fmt, hpp, he, percent_st_l1miss);
880}
881
882static int64_t
883percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
884 struct hist_entry *left, struct hist_entry *right)
885{
886 double per_left;
887 double per_right;
888
889 per_left = PERCENT(left, st_l1miss);
890 per_right = PERCENT(right, st_l1miss);
891
892 return per_left - per_right;
893}
894
Jiri Olsa6c70f542016-05-28 12:30:13 +0200895STAT_FN(lcl_dram)
896STAT_FN(rmt_dram)
897
Jiri Olsa36d3deb2016-05-24 13:09:47 +0200898static int
899pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
900 struct hist_entry *he)
901{
902 int width = c2c_width(fmt, hpp, he->hists);
903
904 return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
905}
906
907static int64_t
908pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
909 struct hist_entry *left, struct hist_entry *right)
910{
911 return left->thread->pid_ - right->thread->pid_;
912}
913
Jiri Olsa1e181b92016-06-03 15:40:28 +0200914static int64_t
915empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
916 struct hist_entry *left __maybe_unused,
917 struct hist_entry *right __maybe_unused)
918{
919 return 0;
920}
921
922static int
923node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
924 struct hist_entry *he)
925{
926 struct c2c_hist_entry *c2c_he;
927 bool first = true;
928 int node;
929 int ret = 0;
930
931 c2c_he = container_of(he, struct c2c_hist_entry, he);
932
933 for (node = 0; node < c2c.nodes_cnt; node++) {
934 DECLARE_BITMAP(set, c2c.cpus_cnt);
935
936 bitmap_zero(set, c2c.cpus_cnt);
937 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
938
939 if (!bitmap_weight(set, c2c.cpus_cnt)) {
940 if (c2c.node_info == 1) {
941 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
942 advance_hpp(hpp, ret);
943 }
944 continue;
945 }
946
947 if (!first) {
948 ret = scnprintf(hpp->buf, hpp->size, " ");
949 advance_hpp(hpp, ret);
950 }
951
952 switch (c2c.node_info) {
953 case 0:
954 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
955 advance_hpp(hpp, ret);
956 break;
957 case 1:
958 {
959 int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
960 struct c2c_stats *stats = &c2c_he->node_stats[node];
961
962 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
963 advance_hpp(hpp, ret);
964
965
966 if (c2c_he->stats.rmt_hitm > 0) {
967 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ",
968 percent(stats->rmt_hitm, c2c_he->stats.rmt_hitm));
969 } else {
970 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a");
971 }
972
973 advance_hpp(hpp, ret);
974
975 if (c2c_he->stats.store > 0) {
976 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
977 percent(stats->store, c2c_he->stats.store));
978 } else {
979 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
980 }
981
982 advance_hpp(hpp, ret);
983 break;
984 }
985 case 2:
986 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
987 advance_hpp(hpp, ret);
988
989 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
990 advance_hpp(hpp, ret);
991
992 ret = scnprintf(hpp->buf, hpp->size, "}");
993 advance_hpp(hpp, ret);
994 break;
995 default:
996 break;
997 }
998
999 first = false;
1000 }
1001
1002 return 0;
1003}
1004
Jiri Olsa92062d52016-06-05 13:40:53 +02001005static int
1006mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1007 struct hist_entry *he, double mean)
1008{
1009 int width = c2c_width(fmt, hpp, he->hists);
1010 char buf[10];
1011
1012 scnprintf(buf, 10, "%6.0f", mean);
1013 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1014}
1015
1016#define MEAN_ENTRY(__func, __val) \
1017static int \
1018__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1019{ \
1020 struct c2c_hist_entry *c2c_he; \
1021 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1022 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1023}
1024
1025MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1026MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1027MEAN_ENTRY(mean_load_entry, load);
1028
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001029static int
1030cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1031 struct hist_entry *he)
1032{
1033 struct c2c_hist_entry *c2c_he;
1034 int width = c2c_width(fmt, hpp, he->hists);
1035 char buf[10];
1036
1037 c2c_he = container_of(he, struct c2c_hist_entry, he);
1038
1039 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1040 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1041}
1042
Jiri Olsa600a8cf2016-09-22 17:36:47 +02001043#define HEADER_LOW(__h) \
1044 { \
1045 .line[1] = { \
1046 .text = __h, \
1047 }, \
1048 }
1049
1050#define HEADER_BOTH(__h0, __h1) \
1051 { \
1052 .line[0] = { \
1053 .text = __h0, \
1054 }, \
1055 .line[1] = { \
1056 .text = __h1, \
1057 }, \
1058 }
1059
1060#define HEADER_SPAN(__h0, __h1, __s) \
1061 { \
1062 .line[0] = { \
1063 .text = __h0, \
1064 .span = __s, \
1065 }, \
1066 .line[1] = { \
1067 .text = __h1, \
1068 }, \
1069 }
1070
1071#define HEADER_SPAN_LOW(__h) \
1072 { \
1073 .line[1] = { \
1074 .text = __h, \
1075 }, \
1076 }
1077
Jiri Olsacbb88502016-09-22 17:36:48 +02001078static struct c2c_dimension dim_dcacheline = {
1079 .header = HEADER_LOW("Cacheline"),
1080 .name = "dcacheline",
1081 .cmp = dcacheline_cmp,
1082 .entry = dcacheline_entry,
1083 .width = 18,
1084};
1085
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001086static struct c2c_header header_offset_tui = HEADER_LOW("Off");
1087
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001088static struct c2c_dimension dim_offset = {
1089 .header = HEADER_BOTH("Data address", "Offset"),
1090 .name = "offset",
1091 .cmp = offset_cmp,
1092 .entry = offset_entry,
1093 .width = 18,
1094};
1095
Jiri Olsa43575a92016-05-03 21:48:56 +02001096static struct c2c_dimension dim_iaddr = {
1097 .header = HEADER_LOW("Code address"),
1098 .name = "iaddr",
1099 .cmp = iaddr_cmp,
1100 .entry = iaddr_entry,
1101 .width = 18,
1102};
1103
Jiri Olsa97cb4862016-05-23 16:20:14 +02001104static struct c2c_dimension dim_tot_hitm = {
1105 .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1106 .name = "tot_hitm",
1107 .cmp = tot_hitm_cmp,
1108 .entry = tot_hitm_entry,
1109 .width = 7,
1110};
1111
1112static struct c2c_dimension dim_lcl_hitm = {
1113 .header = HEADER_SPAN_LOW("Lcl"),
1114 .name = "lcl_hitm",
1115 .cmp = lcl_hitm_cmp,
1116 .entry = lcl_hitm_entry,
1117 .width = 7,
1118};
1119
1120static struct c2c_dimension dim_rmt_hitm = {
1121 .header = HEADER_SPAN_LOW("Rmt"),
1122 .name = "rmt_hitm",
1123 .cmp = rmt_hitm_cmp,
1124 .entry = rmt_hitm_entry,
1125 .width = 7,
1126};
1127
1128static struct c2c_dimension dim_cl_rmt_hitm = {
1129 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1130 .name = "cl_rmt_hitm",
1131 .cmp = rmt_hitm_cmp,
1132 .entry = rmt_hitm_entry,
1133 .width = 7,
1134};
1135
1136static struct c2c_dimension dim_cl_lcl_hitm = {
1137 .header = HEADER_SPAN_LOW("Lcl"),
1138 .name = "cl_lcl_hitm",
1139 .cmp = lcl_hitm_cmp,
1140 .entry = lcl_hitm_entry,
1141 .width = 7,
1142};
1143
Jiri Olsa0f188962016-05-04 10:10:11 +02001144static struct c2c_dimension dim_stores = {
1145 .header = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1146 .name = "stores",
1147 .cmp = store_cmp,
1148 .entry = store_entry,
1149 .width = 7,
1150};
1151
1152static struct c2c_dimension dim_stores_l1hit = {
1153 .header = HEADER_SPAN_LOW("L1Hit"),
1154 .name = "stores_l1hit",
1155 .cmp = st_l1hit_cmp,
1156 .entry = st_l1hit_entry,
1157 .width = 7,
1158};
1159
1160static struct c2c_dimension dim_stores_l1miss = {
1161 .header = HEADER_SPAN_LOW("L1Miss"),
1162 .name = "stores_l1miss",
1163 .cmp = st_l1miss_cmp,
1164 .entry = st_l1miss_entry,
1165 .width = 7,
1166};
1167
1168static struct c2c_dimension dim_cl_stores_l1hit = {
1169 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1170 .name = "cl_stores_l1hit",
1171 .cmp = st_l1hit_cmp,
1172 .entry = st_l1hit_entry,
1173 .width = 7,
1174};
1175
1176static struct c2c_dimension dim_cl_stores_l1miss = {
1177 .header = HEADER_SPAN_LOW("L1 Miss"),
1178 .name = "cl_stores_l1miss",
1179 .cmp = st_l1miss_cmp,
1180 .entry = st_l1miss_entry,
1181 .width = 7,
1182};
1183
Jiri Olsa1295f682016-05-04 10:18:24 +02001184static struct c2c_dimension dim_ld_fbhit = {
1185 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1186 .name = "ld_fbhit",
1187 .cmp = ld_fbhit_cmp,
1188 .entry = ld_fbhit_entry,
1189 .width = 7,
1190};
1191
1192static struct c2c_dimension dim_ld_l1hit = {
1193 .header = HEADER_SPAN_LOW("L1"),
1194 .name = "ld_l1hit",
1195 .cmp = ld_l1hit_cmp,
1196 .entry = ld_l1hit_entry,
1197 .width = 7,
1198};
1199
1200static struct c2c_dimension dim_ld_l2hit = {
1201 .header = HEADER_SPAN_LOW("L2"),
1202 .name = "ld_l2hit",
1203 .cmp = ld_l2hit_cmp,
1204 .entry = ld_l2hit_entry,
1205 .width = 7,
1206};
1207
Jiri Olsa4d089102016-05-04 10:27:51 +02001208static struct c2c_dimension dim_ld_llchit = {
1209 .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1210 .name = "ld_lclhit",
1211 .cmp = ld_llchit_cmp,
1212 .entry = ld_llchit_entry,
1213 .width = 8,
1214};
1215
1216static struct c2c_dimension dim_ld_rmthit = {
1217 .header = HEADER_SPAN_LOW("Rmt"),
1218 .name = "ld_rmthit",
1219 .cmp = rmt_hit_cmp,
1220 .entry = rmt_hit_entry,
1221 .width = 8,
1222};
1223
Jiri Olsa04402d22016-05-19 10:10:51 +02001224static struct c2c_dimension dim_ld_llcmiss = {
1225 .header = HEADER_BOTH("LLC", "Ld Miss"),
1226 .name = "ld_llcmiss",
1227 .cmp = ld_llcmiss_cmp,
1228 .entry = ld_llcmiss_entry,
1229 .width = 7,
1230};
1231
Jiri Olsa01b84d72016-05-04 10:35:29 +02001232static struct c2c_dimension dim_tot_recs = {
1233 .header = HEADER_BOTH("Total", "records"),
1234 .name = "tot_recs",
1235 .cmp = tot_recs_cmp,
1236 .entry = tot_recs_entry,
1237 .width = 7,
1238};
1239
Jiri Olsa55177c42016-05-19 09:52:37 +02001240static struct c2c_dimension dim_tot_loads = {
1241 .header = HEADER_BOTH("Total", "Loads"),
1242 .name = "tot_loads",
1243 .cmp = tot_loads_cmp,
1244 .entry = tot_loads_entry,
1245 .width = 7,
1246};
1247
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001248static struct c2c_dimension dim_percent_hitm = {
1249 .header = HEADER_LOW("%hitm"),
1250 .name = "percent_hitm",
1251 .cmp = percent_hitm_cmp,
1252 .entry = percent_hitm_entry,
1253 .color = percent_hitm_color,
1254 .width = 7,
1255};
1256
Jiri Olsa9cb35002016-05-04 12:16:50 +02001257static struct c2c_dimension dim_percent_rmt_hitm = {
1258 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1259 .name = "percent_rmt_hitm",
1260 .cmp = percent_rmt_hitm_cmp,
1261 .entry = percent_rmt_hitm_entry,
1262 .color = percent_rmt_hitm_color,
1263 .width = 7,
1264};
1265
1266static struct c2c_dimension dim_percent_lcl_hitm = {
1267 .header = HEADER_SPAN_LOW("Lcl"),
1268 .name = "percent_lcl_hitm",
1269 .cmp = percent_lcl_hitm_cmp,
1270 .entry = percent_lcl_hitm_entry,
1271 .color = percent_lcl_hitm_color,
1272 .width = 7,
1273};
1274
1275static struct c2c_dimension dim_percent_stores_l1hit = {
1276 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1277 .name = "percent_stores_l1hit",
1278 .cmp = percent_stores_l1hit_cmp,
1279 .entry = percent_stores_l1hit_entry,
1280 .color = percent_stores_l1hit_color,
1281 .width = 7,
1282};
1283
1284static struct c2c_dimension dim_percent_stores_l1miss = {
1285 .header = HEADER_SPAN_LOW("L1 Miss"),
1286 .name = "percent_stores_l1miss",
1287 .cmp = percent_stores_l1miss_cmp,
1288 .entry = percent_stores_l1miss_entry,
1289 .color = percent_stores_l1miss_color,
1290 .width = 7,
1291};
1292
Jiri Olsa6c70f542016-05-28 12:30:13 +02001293static struct c2c_dimension dim_dram_lcl = {
1294 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1295 .name = "dram_lcl",
1296 .cmp = lcl_dram_cmp,
1297 .entry = lcl_dram_entry,
1298 .width = 8,
1299};
1300
1301static struct c2c_dimension dim_dram_rmt = {
1302 .header = HEADER_SPAN_LOW("Rmt"),
1303 .name = "dram_rmt",
1304 .cmp = rmt_dram_cmp,
1305 .entry = rmt_dram_entry,
1306 .width = 8,
1307};
1308
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001309static struct c2c_dimension dim_pid = {
1310 .header = HEADER_LOW("Pid"),
1311 .name = "pid",
1312 .cmp = pid_cmp,
1313 .entry = pid_entry,
1314 .width = 7,
1315};
1316
Jiri Olsae87019c2016-05-25 08:50:10 +02001317static struct c2c_dimension dim_tid = {
1318 .header = HEADER_LOW("Tid"),
1319 .name = "tid",
1320 .se = &sort_thread,
1321};
1322
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001323static struct c2c_dimension dim_symbol = {
1324 .name = "symbol",
1325 .se = &sort_sym,
1326};
1327
1328static struct c2c_dimension dim_dso = {
1329 .header = HEADER_BOTH("Shared", "Object"),
1330 .name = "dso",
1331 .se = &sort_dso,
1332};
1333
Jiri Olsa1e181b92016-06-03 15:40:28 +02001334static struct c2c_header header_node[3] = {
1335 HEADER_LOW("Node"),
1336 HEADER_LOW("Node{cpus %hitms %stores}"),
1337 HEADER_LOW("Node{cpu list}"),
1338};
1339
1340static struct c2c_dimension dim_node = {
1341 .name = "node",
1342 .cmp = empty_cmp,
1343 .entry = node_entry,
1344 .width = 4,
1345};
1346
Jiri Olsa92062d52016-06-05 13:40:53 +02001347static struct c2c_dimension dim_mean_rmt = {
1348 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1349 .name = "mean_rmt",
1350 .cmp = empty_cmp,
1351 .entry = mean_rmt_entry,
1352 .width = 8,
1353};
1354
1355static struct c2c_dimension dim_mean_lcl = {
1356 .header = HEADER_SPAN_LOW("lcl hitm"),
1357 .name = "mean_lcl",
1358 .cmp = empty_cmp,
1359 .entry = mean_lcl_entry,
1360 .width = 8,
1361};
1362
1363static struct c2c_dimension dim_mean_load = {
1364 .header = HEADER_SPAN_LOW("load"),
1365 .name = "mean_load",
1366 .cmp = empty_cmp,
1367 .entry = mean_load_entry,
1368 .width = 8,
1369};
1370
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001371static struct c2c_dimension dim_cpucnt = {
1372 .header = HEADER_BOTH("cpu", "cnt"),
1373 .name = "cpucnt",
1374 .cmp = empty_cmp,
1375 .entry = cpucnt_entry,
1376 .width = 8,
1377};
1378
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001379static struct c2c_dimension dim_srcline = {
1380 .name = "cl_srcline",
1381 .se = &sort_srcline,
1382};
1383
Jiri Olsac75540e2016-09-22 17:36:41 +02001384static struct c2c_dimension *dimensions[] = {
Jiri Olsacbb88502016-09-22 17:36:48 +02001385 &dim_dcacheline,
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001386 &dim_offset,
Jiri Olsa43575a92016-05-03 21:48:56 +02001387 &dim_iaddr,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001388 &dim_tot_hitm,
1389 &dim_lcl_hitm,
1390 &dim_rmt_hitm,
1391 &dim_cl_lcl_hitm,
1392 &dim_cl_rmt_hitm,
Jiri Olsa0f188962016-05-04 10:10:11 +02001393 &dim_stores,
1394 &dim_stores_l1hit,
1395 &dim_stores_l1miss,
1396 &dim_cl_stores_l1hit,
1397 &dim_cl_stores_l1miss,
Jiri Olsa1295f682016-05-04 10:18:24 +02001398 &dim_ld_fbhit,
1399 &dim_ld_l1hit,
1400 &dim_ld_l2hit,
Jiri Olsa4d089102016-05-04 10:27:51 +02001401 &dim_ld_llchit,
1402 &dim_ld_rmthit,
Jiri Olsa04402d22016-05-19 10:10:51 +02001403 &dim_ld_llcmiss,
Jiri Olsa01b84d72016-05-04 10:35:29 +02001404 &dim_tot_recs,
Jiri Olsa55177c42016-05-19 09:52:37 +02001405 &dim_tot_loads,
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001406 &dim_percent_hitm,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001407 &dim_percent_rmt_hitm,
1408 &dim_percent_lcl_hitm,
1409 &dim_percent_stores_l1hit,
1410 &dim_percent_stores_l1miss,
Jiri Olsa6c70f542016-05-28 12:30:13 +02001411 &dim_dram_lcl,
1412 &dim_dram_rmt,
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001413 &dim_pid,
Jiri Olsae87019c2016-05-25 08:50:10 +02001414 &dim_tid,
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001415 &dim_symbol,
1416 &dim_dso,
Jiri Olsa1e181b92016-06-03 15:40:28 +02001417 &dim_node,
Jiri Olsa92062d52016-06-05 13:40:53 +02001418 &dim_mean_rmt,
1419 &dim_mean_lcl,
1420 &dim_mean_load,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001421 &dim_cpucnt,
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001422 &dim_srcline,
Jiri Olsac75540e2016-09-22 17:36:41 +02001423 NULL,
1424};
1425
1426static void fmt_free(struct perf_hpp_fmt *fmt)
1427{
1428 struct c2c_fmt *c2c_fmt;
1429
1430 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1431 free(c2c_fmt);
1432}
1433
1434static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1435{
1436 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1437 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1438
1439 return c2c_a->dim == c2c_b->dim;
1440}
1441
1442static struct c2c_dimension *get_dimension(const char *name)
1443{
1444 unsigned int i;
1445
1446 for (i = 0; dimensions[i]; i++) {
1447 struct c2c_dimension *dim = dimensions[i];
1448
1449 if (!strcmp(dim->name, name))
1450 return dim;
1451 };
1452
1453 return NULL;
1454}
1455
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001456static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1457 struct hist_entry *he)
1458{
1459 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1460 struct c2c_dimension *dim = c2c_fmt->dim;
1461 size_t len = fmt->user_len;
1462
1463 if (!len)
1464 len = hists__col_len(he->hists, dim->se->se_width_idx);
1465
1466 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1467}
1468
1469static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1470 struct hist_entry *a, struct hist_entry *b)
1471{
1472 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1473 struct c2c_dimension *dim = c2c_fmt->dim;
1474
1475 return dim->se->se_cmp(a, b);
1476}
1477
1478static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1479 struct hist_entry *a, struct hist_entry *b)
1480{
1481 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1482 struct c2c_dimension *dim = c2c_fmt->dim;
1483 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1484
1485 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1486 return collapse_fn(a, b);
1487}
1488
Jiri Olsac75540e2016-09-22 17:36:41 +02001489static struct c2c_fmt *get_format(const char *name)
1490{
1491 struct c2c_dimension *dim = get_dimension(name);
1492 struct c2c_fmt *c2c_fmt;
1493 struct perf_hpp_fmt *fmt;
1494
1495 if (!dim)
1496 return NULL;
1497
1498 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1499 if (!c2c_fmt)
1500 return NULL;
1501
1502 c2c_fmt->dim = dim;
1503
1504 fmt = &c2c_fmt->fmt;
1505 INIT_LIST_HEAD(&fmt->list);
1506 INIT_LIST_HEAD(&fmt->sort_list);
1507
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001508 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1509 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
Jiri Olsa9cb35002016-05-04 12:16:50 +02001510 fmt->color = dim->se ? NULL : dim->color;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001511 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
Jiri Olsac75540e2016-09-22 17:36:41 +02001512 fmt->header = c2c_header;
1513 fmt->width = c2c_width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001514 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
Jiri Olsac75540e2016-09-22 17:36:41 +02001515 fmt->equal = fmt_equal;
1516 fmt->free = fmt_free;
1517
1518 return c2c_fmt;
1519}
1520
1521static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1522{
1523 struct c2c_fmt *c2c_fmt = get_format(name);
1524
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001525 if (!c2c_fmt) {
1526 reset_dimensions();
1527 return output_field_add(hpp_list, name);
1528 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001529
1530 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1531 return 0;
1532}
1533
1534static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1535{
1536 struct c2c_fmt *c2c_fmt = get_format(name);
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001537 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +02001538
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001539 if (!c2c_fmt) {
1540 reset_dimensions();
1541 return sort_dimension__add(hpp_list, name, NULL, 0);
1542 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001543
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001544 dim = c2c_fmt->dim;
1545 if (dim == &dim_dso)
1546 hpp_list->dso = 1;
1547
Jiri Olsac75540e2016-09-22 17:36:41 +02001548 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1549 return 0;
1550}
1551
1552#define PARSE_LIST(_list, _fn) \
1553 do { \
1554 char *tmp, *tok; \
1555 ret = 0; \
1556 \
1557 if (!_list) \
1558 break; \
1559 \
1560 for (tok = strtok_r((char *)_list, ", ", &tmp); \
1561 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
1562 ret = _fn(hpp_list, tok); \
1563 if (ret == -EINVAL) { \
1564 error("Invalid --fields key: `%s'", tok); \
1565 break; \
1566 } else if (ret == -ESRCH) { \
1567 error("Unknown --fields key: `%s'", tok); \
1568 break; \
1569 } \
1570 } \
1571 } while (0)
1572
1573static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1574 const char *output_,
1575 const char *sort_)
1576{
1577 char *output = output_ ? strdup(output_) : NULL;
1578 char *sort = sort_ ? strdup(sort_) : NULL;
1579 int ret;
1580
1581 PARSE_LIST(output, c2c_hists__init_output);
1582 PARSE_LIST(sort, c2c_hists__init_sort);
1583
1584 /* copy sort keys to output fields */
1585 perf_hpp__setup_output_field(hpp_list);
1586
1587 /*
1588 * We dont need other sorting keys other than those
1589 * we already specified. It also really slows down
1590 * the processing a lot with big number of output
1591 * fields, so switching this off for c2c.
1592 */
1593
1594#if 0
1595 /* and then copy output fields to sort keys */
1596 perf_hpp__append_sort_keys(&hists->list);
1597#endif
1598
1599 free(output);
1600 free(sort);
1601 return ret;
1602}
1603
1604static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001605 const char *sort,
1606 int nr_header_lines)
Jiri Olsac75540e2016-09-22 17:36:41 +02001607{
1608 __hists__init(&hists->hists, &hists->list);
1609
1610 /*
1611 * Initialize only with sort fields, we need to resort
1612 * later anyway, and that's where we add output fields
1613 * as well.
1614 */
1615 perf_hpp_list__init(&hists->list);
1616
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001617 /* Overload number of header lines.*/
1618 hists->list.nr_header_lines = nr_header_lines;
1619
Jiri Olsac75540e2016-09-22 17:36:41 +02001620 return hpp_list__parse(&hists->list, NULL, sort);
1621}
1622
1623__maybe_unused
1624static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1625 const char *output,
1626 const char *sort)
1627{
1628 perf_hpp__reset_output_field(&c2c_hists->list);
1629 return hpp_list__parse(&c2c_hists->list, output, sort);
1630}
1631
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001632static int filter_cb(struct hist_entry *he)
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001633{
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001634 if (c2c.show_src && !he->srcline)
1635 he->srcline = hist_entry__get_srcline(he);
1636
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001637 return 0;
1638}
1639
1640static int resort_cl_cb(struct hist_entry *he)
1641{
1642 struct c2c_hist_entry *c2c_he;
1643 struct c2c_hists *c2c_hists;
1644
1645 c2c_he = container_of(he, struct c2c_hist_entry, he);
1646 c2c_hists = c2c_he->hists;
1647
1648 if (c2c_hists) {
Jiri Olsa22dd59d2016-05-10 14:08:29 +02001649 c2c_hists__reinit(c2c_hists,
1650 "percent_rmt_hitm,"
1651 "percent_lcl_hitm,"
1652 "percent_stores_l1hit,"
1653 "percent_stores_l1miss,"
1654 "offset,"
1655 "pid,"
1656 "tid,"
1657 "mean_rmt,"
1658 "mean_lcl,"
1659 "mean_load,"
1660 "cpucnt,"
1661 "symbol,"
1662 "dso,"
1663 "node",
1664 "offset,rmt_hitm,lcl_hitm");
1665
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001666 hists__collapse_resort(&c2c_hists->hists, NULL);
1667 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
1668 }
1669
1670 return 0;
1671}
1672
Jiri Olsa1e181b92016-06-03 15:40:28 +02001673static void setup_nodes_header(void)
1674{
1675 dim_node.header = header_node[c2c.node_info];
1676}
1677
1678static int setup_nodes(struct perf_session *session)
1679{
1680 struct numa_node *n;
1681 unsigned long **nodes;
1682 int node, cpu;
1683 int *cpu2node;
1684
1685 if (c2c.node_info > 2)
1686 c2c.node_info = 2;
1687
1688 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1689 c2c.cpus_cnt = session->header.env.nr_cpus_online;
1690
1691 n = session->header.env.numa_nodes;
1692 if (!n)
1693 return -EINVAL;
1694
1695 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
1696 if (!nodes)
1697 return -ENOMEM;
1698
1699 c2c.nodes = nodes;
1700
1701 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
1702 if (!cpu2node)
1703 return -ENOMEM;
1704
1705 for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
1706 cpu2node[cpu] = -1;
1707
1708 c2c.cpu2node = cpu2node;
1709
1710 for (node = 0; node < c2c.nodes_cnt; node++) {
1711 struct cpu_map *map = n[node].map;
1712 unsigned long *set;
1713
1714 set = bitmap_alloc(c2c.cpus_cnt);
1715 if (!set)
1716 return -ENOMEM;
1717
1718 for (cpu = 0; cpu < map->nr; cpu++) {
1719 set_bit(map->map[cpu], set);
1720
1721 if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
1722 return -EINVAL;
1723
1724 cpu2node[map->map[cpu]] = node;
1725 }
1726
1727 nodes[node] = set;
1728 }
1729
1730 setup_nodes_header();
1731 return 0;
1732}
1733
Jiri Olsa2d388bd2016-05-03 14:32:56 +02001734static void print_cacheline(struct c2c_hists *c2c_hists,
1735 struct hist_entry *he_cl,
1736 struct perf_hpp_list *hpp_list,
1737 FILE *out)
1738{
1739 char bf[1000];
1740 struct perf_hpp hpp = {
1741 .buf = bf,
1742 .size = 1000,
1743 };
1744 static bool once;
1745
1746 if (!once) {
1747 hists__fprintf_headers(&c2c_hists->hists, out);
1748 once = true;
1749 } else {
1750 fprintf(out, "\n");
1751 }
1752
1753 fprintf(out, " ------------------------------------------------------\n");
1754 __hist_entry__snprintf(he_cl, &hpp, hpp_list);
1755 fprintf(out, "%s\n", bf);
1756 fprintf(out, " ------------------------------------------------------\n");
1757
1758 hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, true);
1759}
1760
1761static void print_pareto(FILE *out)
1762{
1763 struct perf_hpp_list hpp_list;
1764 struct rb_node *nd;
1765 int ret;
1766
1767 perf_hpp_list__init(&hpp_list);
1768 ret = hpp_list__parse(&hpp_list,
1769 "cl_rmt_hitm,"
1770 "cl_lcl_hitm,"
1771 "cl_stores_l1hit,"
1772 "cl_stores_l1miss,"
1773 "dcacheline",
1774 NULL);
1775
1776 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
1777 return;
1778
1779 nd = rb_first(&c2c.hists.hists.entries);
1780
1781 for (; nd; nd = rb_next(nd)) {
1782 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1783 struct c2c_hist_entry *c2c_he;
1784
1785 if (he->filtered)
1786 continue;
1787
1788 c2c_he = container_of(he, struct c2c_hist_entry, he);
1789 print_cacheline(c2c_he->hists, he, &hpp_list, out);
1790 }
1791}
1792
1793static void perf_c2c__hists_fprintf(FILE *out)
1794{
1795 setup_pager();
1796
1797 fprintf(out, "\n");
1798 fprintf(out, "=================================================\n");
1799 fprintf(out, " Shared Data Cache Line Table \n");
1800 fprintf(out, "=================================================\n");
1801 fprintf(out, "#\n");
1802
1803 hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, false);
1804
1805 fprintf(out, "\n");
1806 fprintf(out, "=================================================\n");
1807 fprintf(out, " Shared Cache Line Distribution Pareto \n");
1808 fprintf(out, "=================================================\n");
1809 fprintf(out, "#\n");
1810
1811 print_pareto(out);
1812}
Jiri Olsa1e181b92016-06-03 15:40:28 +02001813
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001814#ifdef HAVE_SLANG_SUPPORT
1815static void c2c_browser__update_nr_entries(struct hist_browser *hb)
1816{
1817 u64 nr_entries = 0;
1818 struct rb_node *nd = rb_first(&hb->hists->entries);
1819
1820 while (nd) {
1821 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1822
1823 if (!he->filtered)
1824 nr_entries++;
1825
1826 nd = rb_next(nd);
1827 }
1828
1829 hb->nr_non_filtered_entries = nr_entries;
1830}
1831
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02001832struct c2c_cacheline_browser {
1833 struct hist_browser hb;
1834 struct hist_entry *he;
1835};
1836
1837static int
1838perf_c2c_cacheline_browser__title(struct hist_browser *browser,
1839 char *bf, size_t size)
1840{
1841 struct c2c_cacheline_browser *cl_browser;
1842 struct hist_entry *he;
1843 uint64_t addr = 0;
1844
1845 cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
1846 he = cl_browser->he;
1847
1848 if (he->mem_info)
1849 addr = cl_address(he->mem_info->daddr.addr);
1850
1851 scnprintf(bf, size, "Cacheline 0x%lx", addr);
1852 return 0;
1853}
1854
1855static struct c2c_cacheline_browser*
1856c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
1857{
1858 struct c2c_cacheline_browser *browser;
1859
1860 browser = zalloc(sizeof(*browser));
1861 if (browser) {
1862 hist_browser__init(&browser->hb, hists);
1863 browser->hb.c2c_filter = true;
1864 browser->hb.title = perf_c2c_cacheline_browser__title;
1865 browser->he = he;
1866 }
1867
1868 return browser;
1869}
1870
1871static int perf_c2c__browse_cacheline(struct hist_entry *he)
1872{
1873 struct c2c_hist_entry *c2c_he;
1874 struct c2c_hists *c2c_hists;
1875 struct c2c_cacheline_browser *cl_browser;
1876 struct hist_browser *browser;
1877 int key = -1;
1878
1879 c2c_he = container_of(he, struct c2c_hist_entry, he);
1880 c2c_hists = c2c_he->hists;
1881
1882 cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
1883 if (cl_browser == NULL)
1884 return -1;
1885
1886 browser = &cl_browser->hb;
1887
1888 /* reset abort key so that it can get Ctrl-C as a key */
1889 SLang_reset_tty();
1890 SLang_init_tty(0, 0, 0);
1891
1892 c2c_browser__update_nr_entries(browser);
1893
1894 while (1) {
1895 key = hist_browser__run(browser, "help");
1896
1897 switch (key) {
1898 case 'q':
1899 goto out;
1900 default:
1901 break;
1902 }
1903 }
1904
1905out:
1906 free(cl_browser);
1907 return 0;
1908}
1909
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001910static int perf_c2c_browser__title(struct hist_browser *browser,
1911 char *bf, size_t size)
1912{
1913 scnprintf(bf, size,
1914 "Shared Data Cache Line Table "
1915 "(%lu entries)", browser->nr_non_filtered_entries);
1916 return 0;
1917}
1918
1919static struct hist_browser*
1920perf_c2c_browser__new(struct hists *hists)
1921{
1922 struct hist_browser *browser = hist_browser__new(hists);
1923
1924 if (browser) {
1925 browser->title = perf_c2c_browser__title;
1926 browser->c2c_filter = true;
1927 }
1928
1929 return browser;
1930}
1931
1932static int perf_c2c__hists_browse(struct hists *hists)
1933{
1934 struct hist_browser *browser;
1935 int key = -1;
1936
1937 browser = perf_c2c_browser__new(hists);
1938 if (browser == NULL)
1939 return -1;
1940
1941 /* reset abort key so that it can get Ctrl-C as a key */
1942 SLang_reset_tty();
1943 SLang_init_tty(0, 0, 0);
1944
1945 c2c_browser__update_nr_entries(browser);
1946
1947 while (1) {
1948 key = hist_browser__run(browser, "help");
1949
1950 switch (key) {
1951 case 'q':
1952 goto out;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02001953 case 'd':
1954 perf_c2c__browse_cacheline(browser->he_selection);
1955 break;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001956 default:
1957 break;
1958 }
1959 }
1960
1961out:
1962 hist_browser__delete(browser);
1963 return 0;
1964}
1965
1966static void perf_c2c_display(void)
1967{
1968 if (c2c.use_stdio)
1969 perf_c2c__hists_fprintf(stdout);
1970 else
1971 perf_c2c__hists_browse(&c2c.hists.hists);
1972}
1973#else
1974static void perf_c2c_display(void)
1975{
1976 use_browser = 0;
1977 perf_c2c__hists_fprintf(stdout);
1978}
1979#endif /* HAVE_SLANG_SUPPORT */
1980
1981static void ui_quirks(void)
1982{
1983 if (!c2c.use_stdio) {
1984 dim_offset.width = 5;
1985 dim_offset.header = header_offset_tui;
1986 }
1987}
1988
Jiri Olsa903a6f12016-09-22 17:36:40 +02001989static int perf_c2c__report(int argc, const char **argv)
1990{
1991 struct perf_session *session;
Jiri Olsa78b27542016-09-22 17:36:44 +02001992 struct ui_progress prog;
Jiri Olsa903a6f12016-09-22 17:36:40 +02001993 struct perf_data_file file = {
1994 .mode = PERF_DATA_MODE_READ,
1995 };
1996 const struct option c2c_options[] = {
1997 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1998 "file", "vmlinux pathname"),
1999 OPT_INCR('v', "verbose", &verbose,
2000 "be more verbose (show counter open errors, etc)"),
2001 OPT_STRING('i', "input", &input_name, "file",
2002 "the input file to process"),
Jiri Olsa1e181b92016-06-03 15:40:28 +02002003 OPT_INCR('N', "node-info", &c2c.node_info,
2004 "show extra node info in report (repeat for more info)"),
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002005#ifdef HAVE_SLANG_SUPPORT
2006 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2007#endif
Jiri Olsa903a6f12016-09-22 17:36:40 +02002008 OPT_END()
2009 };
2010 int err = 0;
2011
2012 argc = parse_options(argc, argv, c2c_options, report_c2c_usage,
2013 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa78b27542016-09-22 17:36:44 +02002014 if (argc)
Jiri Olsa903a6f12016-09-22 17:36:40 +02002015 usage_with_options(report_c2c_usage, c2c_options);
2016
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002017 if (c2c.use_stdio)
2018 use_browser = 0;
2019 else
2020 use_browser = 1;
2021
2022 setup_browser(false);
2023
Jiri Olsa78b27542016-09-22 17:36:44 +02002024 if (!input_name || !strlen(input_name))
2025 input_name = "perf.data";
2026
Jiri Olsa903a6f12016-09-22 17:36:40 +02002027 file.path = input_name;
2028
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02002029 err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
Jiri Olsac75540e2016-09-22 17:36:41 +02002030 if (err) {
2031 pr_debug("Failed to initialize hists\n");
2032 goto out;
2033 }
2034
Jiri Olsa903a6f12016-09-22 17:36:40 +02002035 session = perf_session__new(&file, 0, &c2c.tool);
2036 if (session == NULL) {
2037 pr_debug("No memory for session\n");
2038 goto out;
2039 }
Jiri Olsa1e181b92016-06-03 15:40:28 +02002040 err = setup_nodes(session);
2041 if (err) {
2042 pr_err("Failed setup nodes\n");
2043 goto out;
2044 }
Jiri Olsa903a6f12016-09-22 17:36:40 +02002045
2046 if (symbol__init(&session->header.env) < 0)
2047 goto out_session;
2048
2049 /* No pipe support at the moment. */
2050 if (perf_data_file__is_pipe(session->file)) {
2051 pr_debug("No pipe support at the moment.\n");
2052 goto out_session;
2053 }
2054
Jiri Olsa78b27542016-09-22 17:36:44 +02002055 err = perf_session__process_events(session);
2056 if (err) {
2057 pr_err("failed to process sample\n");
2058 goto out_session;
2059 }
2060
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002061 c2c_hists__reinit(&c2c.hists,
2062 "dcacheline,"
2063 "tot_recs,"
2064 "percent_hitm,"
2065 "tot_hitm,lcl_hitm,rmt_hitm,"
2066 "stores,stores_l1hit,stores_l1miss,"
2067 "dram_lcl,dram_rmt,"
2068 "ld_llcmiss,"
2069 "tot_loads,"
2070 "ld_fbhit,ld_l1hit,ld_l2hit,"
2071 "ld_lclhit,ld_rmthit",
2072 "rmt_hitm"
2073 );
2074
Jiri Olsa78b27542016-09-22 17:36:44 +02002075 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
2076
2077 hists__collapse_resort(&c2c.hists.hists, NULL);
Jiri Olsaec06f9b2016-09-22 17:36:45 +02002078 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_cl_cb);
Jiri Olsa78b27542016-09-22 17:36:44 +02002079
2080 ui_progress__finish();
2081
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002082 ui_quirks();
2083
2084 perf_c2c_display();
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002085
Jiri Olsa903a6f12016-09-22 17:36:40 +02002086out_session:
2087 perf_session__delete(session);
2088out:
2089 return err;
2090}
2091
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002092static int parse_record_events(const struct option *opt __maybe_unused,
2093 const char *str, int unset __maybe_unused)
2094{
2095 bool *event_set = (bool *) opt->value;
2096
2097 *event_set = true;
2098 return perf_mem_events__parse(str);
2099}
2100
2101
2102static const char * const __usage_record[] = {
2103 "perf c2c record [<options>] [<command>]",
2104 "perf c2c record [<options>] -- <command> [<options>]",
2105 NULL
2106};
2107
2108static const char * const *record_mem_usage = __usage_record;
2109
2110static int perf_c2c__record(int argc, const char **argv)
2111{
2112 int rec_argc, i = 0, j;
2113 const char **rec_argv;
2114 int ret;
2115 bool all_user = false, all_kernel = false;
2116 bool event_set = false;
2117 struct option options[] = {
2118 OPT_CALLBACK('e', "event", &event_set, "event",
2119 "event selector. Use 'perf mem record -e list' to list available events",
2120 parse_record_events),
2121 OPT_INCR('v', "verbose", &verbose,
2122 "be more verbose (show counter open errors, etc)"),
2123 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
2124 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
2125 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
2126 OPT_END()
2127 };
2128
2129 if (perf_mem_events__init()) {
2130 pr_err("failed: memory events not supported\n");
2131 return -1;
2132 }
2133
2134 argc = parse_options(argc, argv, options, record_mem_usage,
2135 PARSE_OPT_KEEP_UNKNOWN);
2136
2137 rec_argc = argc + 10; /* max number of arguments */
2138 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2139 if (!rec_argv)
2140 return -1;
2141
2142 rec_argv[i++] = "record";
2143
2144 if (!event_set) {
2145 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
2146 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
2147 }
2148
2149 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
2150 rec_argv[i++] = "-W";
2151
2152 rec_argv[i++] = "-d";
2153 rec_argv[i++] = "--sample-cpu";
2154
2155 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
2156 if (!perf_mem_events[j].record)
2157 continue;
2158
2159 if (!perf_mem_events[j].supported) {
2160 pr_err("failed: event '%s' not supported\n",
2161 perf_mem_events[j].name);
2162 return -1;
2163 }
2164
2165 rec_argv[i++] = "-e";
2166 rec_argv[i++] = perf_mem_events__name(j);
2167 };
2168
2169 if (all_user)
2170 rec_argv[i++] = "--all-user";
2171
2172 if (all_kernel)
2173 rec_argv[i++] = "--all-kernel";
2174
2175 for (j = 0; j < argc; j++, i++)
2176 rec_argv[i] = argv[j];
2177
2178 if (verbose > 0) {
2179 pr_debug("calling: ");
2180
2181 j = 0;
2182
2183 while (rec_argv[j]) {
2184 pr_debug("%s ", rec_argv[j]);
2185 j++;
2186 }
2187 pr_debug("\n");
2188 }
2189
2190 ret = cmd_record(i, rec_argv, NULL);
2191 free(rec_argv);
2192 return ret;
2193}
2194
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002195int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused)
2196{
2197 const struct option c2c_options[] = {
2198 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
2199 OPT_END()
2200 };
2201
2202 argc = parse_options(argc, argv, c2c_options, c2c_usage,
2203 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002204
2205 if (!argc)
2206 usage_with_options(c2c_usage, c2c_options);
2207
2208 if (!strncmp(argv[0], "rec", 3)) {
2209 return perf_c2c__record(argc, argv);
Jiri Olsa903a6f12016-09-22 17:36:40 +02002210 } else if (!strncmp(argv[0], "rep", 3)) {
2211 return perf_c2c__report(argc, argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002212 } else {
2213 usage_with_options(c2c_usage, c2c_options);
2214 }
2215
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002216 return 0;
2217}