blob: f7b118b759cf8ae2ba64b1674d14672f17f8653a [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 Olsa74c63a22016-05-02 20:01:59 +020058 bool stats_only;
Jiri Olsa7ef2efa2016-07-01 11:12:11 +020059
60 /* HITM shared clines stats */
61 struct c2c_stats hitm_stats;
62 int shared_clines;
Jiri Olsa903a6f12016-09-22 17:36:40 +020063};
64
65static struct perf_c2c c2c;
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020066
Jiri Olsa78b27542016-09-22 17:36:44 +020067static void *c2c_he_zalloc(size_t size)
68{
69 struct c2c_hist_entry *c2c_he;
70
71 c2c_he = zalloc(size + sizeof(*c2c_he));
72 if (!c2c_he)
73 return NULL;
74
Jiri Olsa1e181b92016-06-03 15:40:28 +020075 c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
76 if (!c2c_he->cpuset)
77 return NULL;
78
79 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
80 if (!c2c_he->node_stats)
81 return NULL;
82
Jiri Olsa92062d52016-06-05 13:40:53 +020083 init_stats(&c2c_he->cstats.lcl_hitm);
84 init_stats(&c2c_he->cstats.rmt_hitm);
85 init_stats(&c2c_he->cstats.load);
86
Jiri Olsa78b27542016-09-22 17:36:44 +020087 return &c2c_he->he;
88}
89
90static void c2c_he_free(void *he)
91{
92 struct c2c_hist_entry *c2c_he;
93
94 c2c_he = container_of(he, struct c2c_hist_entry, he);
95 if (c2c_he->hists) {
96 hists__delete_entries(&c2c_he->hists->hists);
97 free(c2c_he->hists);
98 }
99
Jiri Olsa1e181b92016-06-03 15:40:28 +0200100 free(c2c_he->cpuset);
101 free(c2c_he->node_stats);
Jiri Olsa78b27542016-09-22 17:36:44 +0200102 free(c2c_he);
103}
104
105static struct hist_entry_ops c2c_entry_ops = {
106 .new = c2c_he_zalloc,
107 .free = c2c_he_free,
108};
109
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200110static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200111 const char *sort,
112 int nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200113
Jiri Olsab2252ae2016-09-22 17:36:46 +0200114static struct c2c_hists*
115he__get_c2c_hists(struct hist_entry *he,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200116 const char *sort,
117 int nr_header_lines)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200118{
119 struct c2c_hist_entry *c2c_he;
120 struct c2c_hists *hists;
121 int ret;
122
123 c2c_he = container_of(he, struct c2c_hist_entry, he);
124 if (c2c_he->hists)
Jiri Olsab2252ae2016-09-22 17:36:46 +0200125 return c2c_he->hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200126
127 hists = c2c_he->hists = zalloc(sizeof(*hists));
128 if (!hists)
129 return NULL;
130
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200131 ret = c2c_hists__init(hists, sort, nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200132 if (ret) {
133 free(hists);
134 return NULL;
135 }
136
Jiri Olsab2252ae2016-09-22 17:36:46 +0200137 return hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200138}
139
Jiri Olsa1e181b92016-06-03 15:40:28 +0200140static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
141 struct perf_sample *sample)
142{
143 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
144 "WARNING: no sample cpu value"))
145 return;
146
147 set_bit(sample->cpu, c2c_he->cpuset);
148}
149
Jiri Olsa92062d52016-06-05 13:40:53 +0200150static void compute_stats(struct c2c_hist_entry *c2c_he,
151 struct c2c_stats *stats,
152 u64 weight)
153{
154 struct compute_stats *cstats = &c2c_he->cstats;
155
156 if (stats->rmt_hitm)
157 update_stats(&cstats->rmt_hitm, weight);
158 else if (stats->lcl_hitm)
159 update_stats(&cstats->lcl_hitm, weight);
160 else if (stats->load)
161 update_stats(&cstats->load, weight);
162}
163
Jiri Olsa78b27542016-09-22 17:36:44 +0200164static int process_sample_event(struct perf_tool *tool __maybe_unused,
165 union perf_event *event,
166 struct perf_sample *sample,
167 struct perf_evsel *evsel __maybe_unused,
168 struct machine *machine)
169{
Jiri Olsab2252ae2016-09-22 17:36:46 +0200170 struct c2c_hists *c2c_hists = &c2c.hists;
171 struct c2c_hist_entry *c2c_he;
172 struct c2c_stats stats = { .nr_entries = 0, };
Jiri Olsa78b27542016-09-22 17:36:44 +0200173 struct hist_entry *he;
174 struct addr_location al;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200175 struct mem_info *mi, *mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200176 int ret;
177
178 if (machine__resolve(machine, &al, sample) < 0) {
179 pr_debug("problem processing %d event, skipping it.\n",
180 event->header.type);
181 return -1;
182 }
183
184 mi = sample__resolve_mem(sample, &al);
185 if (mi == NULL)
186 return -ENOMEM;
187
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200188 mi_dup = memdup(mi, sizeof(*mi));
189 if (!mi_dup)
190 goto free_mi;
191
Jiri Olsab2252ae2016-09-22 17:36:46 +0200192 c2c_decode_stats(&stats, mi);
193
194 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsa78b27542016-09-22 17:36:44 +0200195 &al, NULL, NULL, mi,
196 sample, true);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200197 if (he == NULL)
198 goto free_mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200199
Jiri Olsab2252ae2016-09-22 17:36:46 +0200200 c2c_he = container_of(he, struct c2c_hist_entry, he);
201 c2c_add_stats(&c2c_he->stats, &stats);
202 c2c_add_stats(&c2c_hists->stats, &stats);
203
Jiri Olsa1e181b92016-06-03 15:40:28 +0200204 c2c_he__set_cpu(c2c_he, sample);
205
Jiri Olsab2252ae2016-09-22 17:36:46 +0200206 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsa78b27542016-09-22 17:36:44 +0200207 ret = hist_entry__append_callchain(he, sample);
208
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200209 if (!ret) {
Jiri Olsa1e181b92016-06-03 15:40:28 +0200210 /*
211 * There's already been warning about missing
212 * sample's cpu value. Let's account all to
213 * node 0 in this case, without any further
214 * warning.
215 *
216 * Doing node stats only for single callchain data.
217 */
218 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
219 int node = c2c.cpu2node[cpu];
220
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200221 mi = mi_dup;
222
223 mi_dup = memdup(mi, sizeof(*mi));
224 if (!mi_dup)
225 goto free_mi;
226
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200227 c2c_hists = he__get_c2c_hists(he, "offset", 2);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200228 if (!c2c_hists)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200229 goto free_mi_dup;
230
Jiri Olsab2252ae2016-09-22 17:36:46 +0200231 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200232 &al, NULL, NULL, mi,
233 sample, true);
234 if (he == NULL)
235 goto free_mi_dup;
236
Jiri Olsab2252ae2016-09-22 17:36:46 +0200237 c2c_he = container_of(he, struct c2c_hist_entry, he);
238 c2c_add_stats(&c2c_he->stats, &stats);
239 c2c_add_stats(&c2c_hists->stats, &stats);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200240 c2c_add_stats(&c2c_he->node_stats[node], &stats);
241
Jiri Olsa92062d52016-06-05 13:40:53 +0200242 compute_stats(c2c_he, &stats, sample->weight);
243
Jiri Olsa1e181b92016-06-03 15:40:28 +0200244 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200245
246 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200247 ret = hist_entry__append_callchain(he, sample);
248 }
249
250out:
Jiri Olsa78b27542016-09-22 17:36:44 +0200251 addr_location__put(&al);
252 return ret;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200253
254free_mi_dup:
255 free(mi_dup);
256free_mi:
257 free(mi);
258 ret = -ENOMEM;
259 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200260}
261
262static struct perf_c2c c2c = {
263 .tool = {
264 .sample = process_sample_event,
265 .mmap = perf_event__process_mmap,
266 .mmap2 = perf_event__process_mmap2,
267 .comm = perf_event__process_comm,
268 .exit = perf_event__process_exit,
269 .fork = perf_event__process_fork,
270 .lost = perf_event__process_lost,
271 .ordered_events = true,
272 .ordering_requires_timestamps = true,
273 },
274};
275
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200276static const char * const c2c_usage[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +0200277 "perf c2c {record|report}",
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200278 NULL
279};
280
Jiri Olsa903a6f12016-09-22 17:36:40 +0200281static const char * const __usage_report[] = {
282 "perf c2c report",
283 NULL
284};
285
286static const char * const *report_c2c_usage = __usage_report;
287
Jiri Olsac75540e2016-09-22 17:36:41 +0200288#define C2C_HEADER_MAX 2
289
290struct c2c_header {
291 struct {
292 const char *text;
293 int span;
294 } line[C2C_HEADER_MAX];
295};
296
297struct c2c_dimension {
298 struct c2c_header header;
299 const char *name;
300 int width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200301 struct sort_entry *se;
Jiri Olsac75540e2016-09-22 17:36:41 +0200302
303 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
304 struct hist_entry *, struct hist_entry *);
305 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
306 struct hist_entry *he);
307 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
308 struct hist_entry *he);
309};
310
311struct c2c_fmt {
312 struct perf_hpp_fmt fmt;
313 struct c2c_dimension *dim;
314};
315
316static int c2c_width(struct perf_hpp_fmt *fmt,
317 struct perf_hpp *hpp __maybe_unused,
318 struct hists *hists __maybe_unused)
319{
320 struct c2c_fmt *c2c_fmt;
Jiri Olsac75540e2016-09-22 17:36:41 +0200321 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +0200322
323 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
324 dim = c2c_fmt->dim;
325
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200326 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
327 c2c_fmt->dim->width;
328}
329
330static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
331 struct hists *hists, int line, int *span)
332{
333 struct perf_hpp_list *hpp_list = hists->hpp_list;
334 struct c2c_fmt *c2c_fmt;
335 struct c2c_dimension *dim;
336 const char *text = NULL;
337 int width = c2c_width(fmt, hpp, hists);
338
339 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
340 dim = c2c_fmt->dim;
341
342 if (dim->se) {
343 text = dim->header.line[line].text;
344 /* Use the last line from sort_entry if not defined. */
345 if (!text && (line == hpp_list->nr_header_lines - 1))
346 text = dim->se->se_header;
347 } else {
348 text = dim->header.line[line].text;
349
350 if (*span) {
351 (*span)--;
352 return 0;
353 } else {
354 *span = dim->header.line[line].span;
355 }
356 }
357
Jiri Olsac75540e2016-09-22 17:36:41 +0200358 if (text == NULL)
359 text = "";
360
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200361 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
Jiri Olsac75540e2016-09-22 17:36:41 +0200362}
363
Jiri Olsacbb88502016-09-22 17:36:48 +0200364#define HEX_STR(__s, __v) \
365({ \
366 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
367 __s; \
368})
369
370static int64_t
371dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
372 struct hist_entry *left, struct hist_entry *right)
373{
374 return sort__dcacheline_cmp(left, right);
375}
376
377static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
378 struct hist_entry *he)
379{
380 uint64_t addr = 0;
381 int width = c2c_width(fmt, hpp, he->hists);
382 char buf[20];
383
384 if (he->mem_info)
385 addr = cl_address(he->mem_info->daddr.addr);
386
387 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
388}
389
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200390static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
391 struct hist_entry *he)
392{
393 uint64_t addr = 0;
394 int width = c2c_width(fmt, hpp, he->hists);
395 char buf[20];
396
397 if (he->mem_info)
398 addr = cl_offset(he->mem_info->daddr.al_addr);
399
400 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
401}
402
403static int64_t
404offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
405 struct hist_entry *left, struct hist_entry *right)
406{
407 uint64_t l = 0, r = 0;
408
409 if (left->mem_info)
410 l = cl_offset(left->mem_info->daddr.addr);
411 if (right->mem_info)
412 r = cl_offset(right->mem_info->daddr.addr);
413
414 return (int64_t)(r - l);
415}
416
Jiri Olsa43575a92016-05-03 21:48:56 +0200417static int
418iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
419 struct hist_entry *he)
420{
421 uint64_t addr = 0;
422 int width = c2c_width(fmt, hpp, he->hists);
423 char buf[20];
424
425 if (he->mem_info)
426 addr = he->mem_info->iaddr.addr;
427
428 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
429}
430
431static int64_t
432iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
433 struct hist_entry *left, struct hist_entry *right)
434{
435 return sort__iaddr_cmp(left, right);
436}
437
Jiri Olsa97cb4862016-05-23 16:20:14 +0200438static int
439tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
440 struct hist_entry *he)
441{
442 struct c2c_hist_entry *c2c_he;
443 int width = c2c_width(fmt, hpp, he->hists);
444 unsigned int tot_hitm;
445
446 c2c_he = container_of(he, struct c2c_hist_entry, he);
447 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
448
449 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
450}
451
452static int64_t
453tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
454 struct hist_entry *left, struct hist_entry *right)
455{
456 struct c2c_hist_entry *c2c_left;
457 struct c2c_hist_entry *c2c_right;
458 unsigned int tot_hitm_left;
459 unsigned int tot_hitm_right;
460
461 c2c_left = container_of(left, struct c2c_hist_entry, he);
462 c2c_right = container_of(right, struct c2c_hist_entry, he);
463
464 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
465 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
466
467 return tot_hitm_left - tot_hitm_right;
468}
469
470#define STAT_FN_ENTRY(__f) \
471static int \
472__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
473 struct hist_entry *he) \
474{ \
475 struct c2c_hist_entry *c2c_he; \
476 int width = c2c_width(fmt, hpp, he->hists); \
477 \
478 c2c_he = container_of(he, struct c2c_hist_entry, he); \
479 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
480 c2c_he->stats.__f); \
481}
482
483#define STAT_FN_CMP(__f) \
484static int64_t \
485__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
486 struct hist_entry *left, struct hist_entry *right) \
487{ \
488 struct c2c_hist_entry *c2c_left, *c2c_right; \
489 \
490 c2c_left = container_of(left, struct c2c_hist_entry, he); \
491 c2c_right = container_of(right, struct c2c_hist_entry, he); \
492 return c2c_left->stats.__f - c2c_right->stats.__f; \
493}
494
495#define STAT_FN(__f) \
496 STAT_FN_ENTRY(__f) \
497 STAT_FN_CMP(__f)
498
499STAT_FN(rmt_hitm)
500STAT_FN(lcl_hitm)
Jiri Olsa0f188962016-05-04 10:10:11 +0200501STAT_FN(store)
502STAT_FN(st_l1hit)
503STAT_FN(st_l1miss)
Jiri Olsa1295f682016-05-04 10:18:24 +0200504STAT_FN(ld_fbhit)
505STAT_FN(ld_l1hit)
506STAT_FN(ld_l2hit)
Jiri Olsa4d089102016-05-04 10:27:51 +0200507STAT_FN(ld_llchit)
508STAT_FN(rmt_hit)
Jiri Olsa97cb4862016-05-23 16:20:14 +0200509
Jiri Olsa04402d22016-05-19 10:10:51 +0200510static uint64_t llc_miss(struct c2c_stats *stats)
511{
512 uint64_t llcmiss;
513
514 llcmiss = stats->lcl_dram +
515 stats->rmt_dram +
516 stats->rmt_hitm +
517 stats->rmt_hit;
518
519 return llcmiss;
520}
521
522static int
523ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
524 struct hist_entry *he)
525{
526 struct c2c_hist_entry *c2c_he;
527 int width = c2c_width(fmt, hpp, he->hists);
528
529 c2c_he = container_of(he, struct c2c_hist_entry, he);
530
531 return scnprintf(hpp->buf, hpp->size, "%*lu", width,
532 llc_miss(&c2c_he->stats));
533}
534
535static int64_t
536ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
537 struct hist_entry *left, struct hist_entry *right)
538{
539 struct c2c_hist_entry *c2c_left;
540 struct c2c_hist_entry *c2c_right;
541
542 c2c_left = container_of(left, struct c2c_hist_entry, he);
543 c2c_right = container_of(right, struct c2c_hist_entry, he);
544
545 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
546}
547
Jiri Olsa01b84d72016-05-04 10:35:29 +0200548static uint64_t total_records(struct c2c_stats *stats)
549{
550 uint64_t lclmiss, ldcnt, total;
551
552 lclmiss = stats->lcl_dram +
553 stats->rmt_dram +
554 stats->rmt_hitm +
555 stats->rmt_hit;
556
557 ldcnt = lclmiss +
558 stats->ld_fbhit +
559 stats->ld_l1hit +
560 stats->ld_l2hit +
561 stats->ld_llchit +
562 stats->lcl_hitm;
563
564 total = ldcnt +
565 stats->st_l1hit +
566 stats->st_l1miss;
567
568 return total;
569}
570
571static int
572tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
573 struct hist_entry *he)
574{
575 struct c2c_hist_entry *c2c_he;
576 int width = c2c_width(fmt, hpp, he->hists);
577 uint64_t tot_recs;
578
579 c2c_he = container_of(he, struct c2c_hist_entry, he);
580 tot_recs = total_records(&c2c_he->stats);
581
582 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
583}
584
585static int64_t
586tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
587 struct hist_entry *left, struct hist_entry *right)
588{
589 struct c2c_hist_entry *c2c_left;
590 struct c2c_hist_entry *c2c_right;
591 uint64_t tot_recs_left;
592 uint64_t tot_recs_right;
593
594 c2c_left = container_of(left, struct c2c_hist_entry, he);
595 c2c_right = container_of(right, struct c2c_hist_entry, he);
596
597 tot_recs_left = total_records(&c2c_left->stats);
598 tot_recs_right = total_records(&c2c_right->stats);
599
600 return tot_recs_left - tot_recs_right;
601}
602
Jiri Olsa55177c42016-05-19 09:52:37 +0200603static uint64_t total_loads(struct c2c_stats *stats)
604{
605 uint64_t lclmiss, ldcnt;
606
607 lclmiss = stats->lcl_dram +
608 stats->rmt_dram +
609 stats->rmt_hitm +
610 stats->rmt_hit;
611
612 ldcnt = lclmiss +
613 stats->ld_fbhit +
614 stats->ld_l1hit +
615 stats->ld_l2hit +
616 stats->ld_llchit +
617 stats->lcl_hitm;
618
619 return ldcnt;
620}
621
622static int
623tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
624 struct hist_entry *he)
625{
626 struct c2c_hist_entry *c2c_he;
627 int width = c2c_width(fmt, hpp, he->hists);
628 uint64_t tot_recs;
629
630 c2c_he = container_of(he, struct c2c_hist_entry, he);
631 tot_recs = total_loads(&c2c_he->stats);
632
633 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
634}
635
636static int64_t
637tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
638 struct hist_entry *left, struct hist_entry *right)
639{
640 struct c2c_hist_entry *c2c_left;
641 struct c2c_hist_entry *c2c_right;
642 uint64_t tot_recs_left;
643 uint64_t tot_recs_right;
644
645 c2c_left = container_of(left, struct c2c_hist_entry, he);
646 c2c_right = container_of(right, struct c2c_hist_entry, he);
647
648 tot_recs_left = total_loads(&c2c_left->stats);
649 tot_recs_right = total_loads(&c2c_right->stats);
650
651 return tot_recs_left - tot_recs_right;
652}
653
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200654typedef double (get_percent_cb)(struct c2c_hist_entry *);
655
656static int
657percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
658 struct hist_entry *he, get_percent_cb get_percent)
659{
660 struct c2c_hist_entry *c2c_he;
661 int width = c2c_width(fmt, hpp, he->hists);
662 double per;
663
664 c2c_he = container_of(he, struct c2c_hist_entry, he);
665 per = get_percent(c2c_he);
666
Jiri Olsa5a1a99c2016-01-06 16:59:02 +0100667#ifdef HAVE_SLANG_SUPPORT
668 if (use_browser)
669 return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
670#endif
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200671 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
672}
673
674static double percent_hitm(struct c2c_hist_entry *c2c_he)
675{
676 struct c2c_hists *hists;
677 struct c2c_stats *stats;
678 struct c2c_stats *total;
679 int tot, st;
680 double p;
681
682 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
683 stats = &c2c_he->stats;
684 total = &hists->stats;
685
686 st = stats->rmt_hitm;
687 tot = total->rmt_hitm;
688
689 p = tot ? (double) st / tot : 0;
690
691 return 100 * p;
692}
693
694#define PERC_STR(__s, __v) \
695({ \
696 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
697 __s; \
698})
699
700static int
701percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
702 struct hist_entry *he)
703{
704 struct c2c_hist_entry *c2c_he;
705 int width = c2c_width(fmt, hpp, he->hists);
706 char buf[10];
707 double per;
708
709 c2c_he = container_of(he, struct c2c_hist_entry, he);
710 per = percent_hitm(c2c_he);
711 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
712}
713
714static int
715percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
716 struct hist_entry *he)
717{
718 return percent_color(fmt, hpp, he, percent_hitm);
719}
720
721static int64_t
722percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
723 struct hist_entry *left, struct hist_entry *right)
724{
725 struct c2c_hist_entry *c2c_left;
726 struct c2c_hist_entry *c2c_right;
727 double per_left;
728 double per_right;
729
730 c2c_left = container_of(left, struct c2c_hist_entry, he);
731 c2c_right = container_of(right, struct c2c_hist_entry, he);
732
733 per_left = percent_hitm(c2c_left);
734 per_right = percent_hitm(c2c_right);
735
736 return per_left - per_right;
737}
738
Jiri Olsa9cb35002016-05-04 12:16:50 +0200739static struct c2c_stats *he_stats(struct hist_entry *he)
740{
741 struct c2c_hist_entry *c2c_he;
742
743 c2c_he = container_of(he, struct c2c_hist_entry, he);
744 return &c2c_he->stats;
745}
746
747static struct c2c_stats *total_stats(struct hist_entry *he)
748{
749 struct c2c_hists *hists;
750
751 hists = container_of(he->hists, struct c2c_hists, hists);
752 return &hists->stats;
753}
754
755static double percent(int st, int tot)
756{
757 return tot ? 100. * (double) st / (double) tot : 0;
758}
759
760#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
761
762#define PERCENT_FN(__f) \
763static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
764{ \
765 struct c2c_hists *hists; \
766 \
767 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
768 return percent(c2c_he->stats.__f, hists->stats.__f); \
769}
770
771PERCENT_FN(rmt_hitm)
772PERCENT_FN(lcl_hitm)
773PERCENT_FN(st_l1hit)
774PERCENT_FN(st_l1miss)
775
776static int
777percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
778 struct hist_entry *he)
779{
780 int width = c2c_width(fmt, hpp, he->hists);
781 double per = PERCENT(he, rmt_hitm);
782 char buf[10];
783
784 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
785}
786
787static int
788percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
789 struct hist_entry *he)
790{
791 return percent_color(fmt, hpp, he, percent_rmt_hitm);
792}
793
794static int64_t
795percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
796 struct hist_entry *left, struct hist_entry *right)
797{
798 double per_left;
799 double per_right;
800
801 per_left = PERCENT(left, lcl_hitm);
802 per_right = PERCENT(right, lcl_hitm);
803
804 return per_left - per_right;
805}
806
807static int
808percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
809 struct hist_entry *he)
810{
811 int width = c2c_width(fmt, hpp, he->hists);
812 double per = PERCENT(he, lcl_hitm);
813 char buf[10];
814
815 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
816}
817
818static int
819percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
820 struct hist_entry *he)
821{
822 return percent_color(fmt, hpp, he, percent_lcl_hitm);
823}
824
825static int64_t
826percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
827 struct hist_entry *left, struct hist_entry *right)
828{
829 double per_left;
830 double per_right;
831
832 per_left = PERCENT(left, lcl_hitm);
833 per_right = PERCENT(right, lcl_hitm);
834
835 return per_left - per_right;
836}
837
838static int
839percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
840 struct hist_entry *he)
841{
842 int width = c2c_width(fmt, hpp, he->hists);
843 double per = PERCENT(he, st_l1hit);
844 char buf[10];
845
846 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
847}
848
849static int
850percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
851 struct hist_entry *he)
852{
853 return percent_color(fmt, hpp, he, percent_st_l1hit);
854}
855
856static int64_t
857percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
858 struct hist_entry *left, struct hist_entry *right)
859{
860 double per_left;
861 double per_right;
862
863 per_left = PERCENT(left, st_l1hit);
864 per_right = PERCENT(right, st_l1hit);
865
866 return per_left - per_right;
867}
868
869static int
870percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
871 struct hist_entry *he)
872{
873 int width = c2c_width(fmt, hpp, he->hists);
874 double per = PERCENT(he, st_l1miss);
875 char buf[10];
876
877 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
878}
879
880static int
881percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
882 struct hist_entry *he)
883{
884 return percent_color(fmt, hpp, he, percent_st_l1miss);
885}
886
887static int64_t
888percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
889 struct hist_entry *left, struct hist_entry *right)
890{
891 double per_left;
892 double per_right;
893
894 per_left = PERCENT(left, st_l1miss);
895 per_right = PERCENT(right, st_l1miss);
896
897 return per_left - per_right;
898}
899
Jiri Olsa6c70f542016-05-28 12:30:13 +0200900STAT_FN(lcl_dram)
901STAT_FN(rmt_dram)
902
Jiri Olsa36d3deb2016-05-24 13:09:47 +0200903static int
904pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
905 struct hist_entry *he)
906{
907 int width = c2c_width(fmt, hpp, he->hists);
908
909 return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
910}
911
912static int64_t
913pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
914 struct hist_entry *left, struct hist_entry *right)
915{
916 return left->thread->pid_ - right->thread->pid_;
917}
918
Jiri Olsa1e181b92016-06-03 15:40:28 +0200919static int64_t
920empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
921 struct hist_entry *left __maybe_unused,
922 struct hist_entry *right __maybe_unused)
923{
924 return 0;
925}
926
927static int
928node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
929 struct hist_entry *he)
930{
931 struct c2c_hist_entry *c2c_he;
932 bool first = true;
933 int node;
934 int ret = 0;
935
936 c2c_he = container_of(he, struct c2c_hist_entry, he);
937
938 for (node = 0; node < c2c.nodes_cnt; node++) {
939 DECLARE_BITMAP(set, c2c.cpus_cnt);
940
941 bitmap_zero(set, c2c.cpus_cnt);
942 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
943
944 if (!bitmap_weight(set, c2c.cpus_cnt)) {
945 if (c2c.node_info == 1) {
946 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
947 advance_hpp(hpp, ret);
948 }
949 continue;
950 }
951
952 if (!first) {
953 ret = scnprintf(hpp->buf, hpp->size, " ");
954 advance_hpp(hpp, ret);
955 }
956
957 switch (c2c.node_info) {
958 case 0:
959 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
960 advance_hpp(hpp, ret);
961 break;
962 case 1:
963 {
964 int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
965 struct c2c_stats *stats = &c2c_he->node_stats[node];
966
967 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
968 advance_hpp(hpp, ret);
969
970
971 if (c2c_he->stats.rmt_hitm > 0) {
972 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ",
973 percent(stats->rmt_hitm, c2c_he->stats.rmt_hitm));
974 } else {
975 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a");
976 }
977
978 advance_hpp(hpp, ret);
979
980 if (c2c_he->stats.store > 0) {
981 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
982 percent(stats->store, c2c_he->stats.store));
983 } else {
984 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
985 }
986
987 advance_hpp(hpp, ret);
988 break;
989 }
990 case 2:
991 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
992 advance_hpp(hpp, ret);
993
994 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
995 advance_hpp(hpp, ret);
996
997 ret = scnprintf(hpp->buf, hpp->size, "}");
998 advance_hpp(hpp, ret);
999 break;
1000 default:
1001 break;
1002 }
1003
1004 first = false;
1005 }
1006
1007 return 0;
1008}
1009
Jiri Olsa92062d52016-06-05 13:40:53 +02001010static int
1011mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1012 struct hist_entry *he, double mean)
1013{
1014 int width = c2c_width(fmt, hpp, he->hists);
1015 char buf[10];
1016
1017 scnprintf(buf, 10, "%6.0f", mean);
1018 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1019}
1020
1021#define MEAN_ENTRY(__func, __val) \
1022static int \
1023__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1024{ \
1025 struct c2c_hist_entry *c2c_he; \
1026 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1027 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1028}
1029
1030MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1031MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1032MEAN_ENTRY(mean_load_entry, load);
1033
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001034static int
1035cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1036 struct hist_entry *he)
1037{
1038 struct c2c_hist_entry *c2c_he;
1039 int width = c2c_width(fmt, hpp, he->hists);
1040 char buf[10];
1041
1042 c2c_he = container_of(he, struct c2c_hist_entry, he);
1043
1044 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1045 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1046}
1047
Jiri Olsa600a8cf2016-09-22 17:36:47 +02001048#define HEADER_LOW(__h) \
1049 { \
1050 .line[1] = { \
1051 .text = __h, \
1052 }, \
1053 }
1054
1055#define HEADER_BOTH(__h0, __h1) \
1056 { \
1057 .line[0] = { \
1058 .text = __h0, \
1059 }, \
1060 .line[1] = { \
1061 .text = __h1, \
1062 }, \
1063 }
1064
1065#define HEADER_SPAN(__h0, __h1, __s) \
1066 { \
1067 .line[0] = { \
1068 .text = __h0, \
1069 .span = __s, \
1070 }, \
1071 .line[1] = { \
1072 .text = __h1, \
1073 }, \
1074 }
1075
1076#define HEADER_SPAN_LOW(__h) \
1077 { \
1078 .line[1] = { \
1079 .text = __h, \
1080 }, \
1081 }
1082
Jiri Olsacbb88502016-09-22 17:36:48 +02001083static struct c2c_dimension dim_dcacheline = {
1084 .header = HEADER_LOW("Cacheline"),
1085 .name = "dcacheline",
1086 .cmp = dcacheline_cmp,
1087 .entry = dcacheline_entry,
1088 .width = 18,
1089};
1090
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001091static struct c2c_header header_offset_tui = HEADER_LOW("Off");
1092
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001093static struct c2c_dimension dim_offset = {
1094 .header = HEADER_BOTH("Data address", "Offset"),
1095 .name = "offset",
1096 .cmp = offset_cmp,
1097 .entry = offset_entry,
1098 .width = 18,
1099};
1100
Jiri Olsa43575a92016-05-03 21:48:56 +02001101static struct c2c_dimension dim_iaddr = {
1102 .header = HEADER_LOW("Code address"),
1103 .name = "iaddr",
1104 .cmp = iaddr_cmp,
1105 .entry = iaddr_entry,
1106 .width = 18,
1107};
1108
Jiri Olsa97cb4862016-05-23 16:20:14 +02001109static struct c2c_dimension dim_tot_hitm = {
1110 .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1111 .name = "tot_hitm",
1112 .cmp = tot_hitm_cmp,
1113 .entry = tot_hitm_entry,
1114 .width = 7,
1115};
1116
1117static struct c2c_dimension dim_lcl_hitm = {
1118 .header = HEADER_SPAN_LOW("Lcl"),
1119 .name = "lcl_hitm",
1120 .cmp = lcl_hitm_cmp,
1121 .entry = lcl_hitm_entry,
1122 .width = 7,
1123};
1124
1125static struct c2c_dimension dim_rmt_hitm = {
1126 .header = HEADER_SPAN_LOW("Rmt"),
1127 .name = "rmt_hitm",
1128 .cmp = rmt_hitm_cmp,
1129 .entry = rmt_hitm_entry,
1130 .width = 7,
1131};
1132
1133static struct c2c_dimension dim_cl_rmt_hitm = {
1134 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1135 .name = "cl_rmt_hitm",
1136 .cmp = rmt_hitm_cmp,
1137 .entry = rmt_hitm_entry,
1138 .width = 7,
1139};
1140
1141static struct c2c_dimension dim_cl_lcl_hitm = {
1142 .header = HEADER_SPAN_LOW("Lcl"),
1143 .name = "cl_lcl_hitm",
1144 .cmp = lcl_hitm_cmp,
1145 .entry = lcl_hitm_entry,
1146 .width = 7,
1147};
1148
Jiri Olsa0f188962016-05-04 10:10:11 +02001149static struct c2c_dimension dim_stores = {
1150 .header = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1151 .name = "stores",
1152 .cmp = store_cmp,
1153 .entry = store_entry,
1154 .width = 7,
1155};
1156
1157static struct c2c_dimension dim_stores_l1hit = {
1158 .header = HEADER_SPAN_LOW("L1Hit"),
1159 .name = "stores_l1hit",
1160 .cmp = st_l1hit_cmp,
1161 .entry = st_l1hit_entry,
1162 .width = 7,
1163};
1164
1165static struct c2c_dimension dim_stores_l1miss = {
1166 .header = HEADER_SPAN_LOW("L1Miss"),
1167 .name = "stores_l1miss",
1168 .cmp = st_l1miss_cmp,
1169 .entry = st_l1miss_entry,
1170 .width = 7,
1171};
1172
1173static struct c2c_dimension dim_cl_stores_l1hit = {
1174 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1175 .name = "cl_stores_l1hit",
1176 .cmp = st_l1hit_cmp,
1177 .entry = st_l1hit_entry,
1178 .width = 7,
1179};
1180
1181static struct c2c_dimension dim_cl_stores_l1miss = {
1182 .header = HEADER_SPAN_LOW("L1 Miss"),
1183 .name = "cl_stores_l1miss",
1184 .cmp = st_l1miss_cmp,
1185 .entry = st_l1miss_entry,
1186 .width = 7,
1187};
1188
Jiri Olsa1295f682016-05-04 10:18:24 +02001189static struct c2c_dimension dim_ld_fbhit = {
1190 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1191 .name = "ld_fbhit",
1192 .cmp = ld_fbhit_cmp,
1193 .entry = ld_fbhit_entry,
1194 .width = 7,
1195};
1196
1197static struct c2c_dimension dim_ld_l1hit = {
1198 .header = HEADER_SPAN_LOW("L1"),
1199 .name = "ld_l1hit",
1200 .cmp = ld_l1hit_cmp,
1201 .entry = ld_l1hit_entry,
1202 .width = 7,
1203};
1204
1205static struct c2c_dimension dim_ld_l2hit = {
1206 .header = HEADER_SPAN_LOW("L2"),
1207 .name = "ld_l2hit",
1208 .cmp = ld_l2hit_cmp,
1209 .entry = ld_l2hit_entry,
1210 .width = 7,
1211};
1212
Jiri Olsa4d089102016-05-04 10:27:51 +02001213static struct c2c_dimension dim_ld_llchit = {
1214 .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1215 .name = "ld_lclhit",
1216 .cmp = ld_llchit_cmp,
1217 .entry = ld_llchit_entry,
1218 .width = 8,
1219};
1220
1221static struct c2c_dimension dim_ld_rmthit = {
1222 .header = HEADER_SPAN_LOW("Rmt"),
1223 .name = "ld_rmthit",
1224 .cmp = rmt_hit_cmp,
1225 .entry = rmt_hit_entry,
1226 .width = 8,
1227};
1228
Jiri Olsa04402d22016-05-19 10:10:51 +02001229static struct c2c_dimension dim_ld_llcmiss = {
1230 .header = HEADER_BOTH("LLC", "Ld Miss"),
1231 .name = "ld_llcmiss",
1232 .cmp = ld_llcmiss_cmp,
1233 .entry = ld_llcmiss_entry,
1234 .width = 7,
1235};
1236
Jiri Olsa01b84d72016-05-04 10:35:29 +02001237static struct c2c_dimension dim_tot_recs = {
1238 .header = HEADER_BOTH("Total", "records"),
1239 .name = "tot_recs",
1240 .cmp = tot_recs_cmp,
1241 .entry = tot_recs_entry,
1242 .width = 7,
1243};
1244
Jiri Olsa55177c42016-05-19 09:52:37 +02001245static struct c2c_dimension dim_tot_loads = {
1246 .header = HEADER_BOTH("Total", "Loads"),
1247 .name = "tot_loads",
1248 .cmp = tot_loads_cmp,
1249 .entry = tot_loads_entry,
1250 .width = 7,
1251};
1252
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001253static struct c2c_dimension dim_percent_hitm = {
1254 .header = HEADER_LOW("%hitm"),
1255 .name = "percent_hitm",
1256 .cmp = percent_hitm_cmp,
1257 .entry = percent_hitm_entry,
1258 .color = percent_hitm_color,
1259 .width = 7,
1260};
1261
Jiri Olsa9cb35002016-05-04 12:16:50 +02001262static struct c2c_dimension dim_percent_rmt_hitm = {
1263 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1264 .name = "percent_rmt_hitm",
1265 .cmp = percent_rmt_hitm_cmp,
1266 .entry = percent_rmt_hitm_entry,
1267 .color = percent_rmt_hitm_color,
1268 .width = 7,
1269};
1270
1271static struct c2c_dimension dim_percent_lcl_hitm = {
1272 .header = HEADER_SPAN_LOW("Lcl"),
1273 .name = "percent_lcl_hitm",
1274 .cmp = percent_lcl_hitm_cmp,
1275 .entry = percent_lcl_hitm_entry,
1276 .color = percent_lcl_hitm_color,
1277 .width = 7,
1278};
1279
1280static struct c2c_dimension dim_percent_stores_l1hit = {
1281 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1282 .name = "percent_stores_l1hit",
1283 .cmp = percent_stores_l1hit_cmp,
1284 .entry = percent_stores_l1hit_entry,
1285 .color = percent_stores_l1hit_color,
1286 .width = 7,
1287};
1288
1289static struct c2c_dimension dim_percent_stores_l1miss = {
1290 .header = HEADER_SPAN_LOW("L1 Miss"),
1291 .name = "percent_stores_l1miss",
1292 .cmp = percent_stores_l1miss_cmp,
1293 .entry = percent_stores_l1miss_entry,
1294 .color = percent_stores_l1miss_color,
1295 .width = 7,
1296};
1297
Jiri Olsa6c70f542016-05-28 12:30:13 +02001298static struct c2c_dimension dim_dram_lcl = {
1299 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1300 .name = "dram_lcl",
1301 .cmp = lcl_dram_cmp,
1302 .entry = lcl_dram_entry,
1303 .width = 8,
1304};
1305
1306static struct c2c_dimension dim_dram_rmt = {
1307 .header = HEADER_SPAN_LOW("Rmt"),
1308 .name = "dram_rmt",
1309 .cmp = rmt_dram_cmp,
1310 .entry = rmt_dram_entry,
1311 .width = 8,
1312};
1313
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001314static struct c2c_dimension dim_pid = {
1315 .header = HEADER_LOW("Pid"),
1316 .name = "pid",
1317 .cmp = pid_cmp,
1318 .entry = pid_entry,
1319 .width = 7,
1320};
1321
Jiri Olsae87019c2016-05-25 08:50:10 +02001322static struct c2c_dimension dim_tid = {
1323 .header = HEADER_LOW("Tid"),
1324 .name = "tid",
1325 .se = &sort_thread,
1326};
1327
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001328static struct c2c_dimension dim_symbol = {
1329 .name = "symbol",
1330 .se = &sort_sym,
1331};
1332
1333static struct c2c_dimension dim_dso = {
1334 .header = HEADER_BOTH("Shared", "Object"),
1335 .name = "dso",
1336 .se = &sort_dso,
1337};
1338
Jiri Olsa1e181b92016-06-03 15:40:28 +02001339static struct c2c_header header_node[3] = {
1340 HEADER_LOW("Node"),
1341 HEADER_LOW("Node{cpus %hitms %stores}"),
1342 HEADER_LOW("Node{cpu list}"),
1343};
1344
1345static struct c2c_dimension dim_node = {
1346 .name = "node",
1347 .cmp = empty_cmp,
1348 .entry = node_entry,
1349 .width = 4,
1350};
1351
Jiri Olsa92062d52016-06-05 13:40:53 +02001352static struct c2c_dimension dim_mean_rmt = {
1353 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1354 .name = "mean_rmt",
1355 .cmp = empty_cmp,
1356 .entry = mean_rmt_entry,
1357 .width = 8,
1358};
1359
1360static struct c2c_dimension dim_mean_lcl = {
1361 .header = HEADER_SPAN_LOW("lcl hitm"),
1362 .name = "mean_lcl",
1363 .cmp = empty_cmp,
1364 .entry = mean_lcl_entry,
1365 .width = 8,
1366};
1367
1368static struct c2c_dimension dim_mean_load = {
1369 .header = HEADER_SPAN_LOW("load"),
1370 .name = "mean_load",
1371 .cmp = empty_cmp,
1372 .entry = mean_load_entry,
1373 .width = 8,
1374};
1375
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001376static struct c2c_dimension dim_cpucnt = {
1377 .header = HEADER_BOTH("cpu", "cnt"),
1378 .name = "cpucnt",
1379 .cmp = empty_cmp,
1380 .entry = cpucnt_entry,
1381 .width = 8,
1382};
1383
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001384static struct c2c_dimension dim_srcline = {
1385 .name = "cl_srcline",
1386 .se = &sort_srcline,
1387};
1388
Jiri Olsac75540e2016-09-22 17:36:41 +02001389static struct c2c_dimension *dimensions[] = {
Jiri Olsacbb88502016-09-22 17:36:48 +02001390 &dim_dcacheline,
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001391 &dim_offset,
Jiri Olsa43575a92016-05-03 21:48:56 +02001392 &dim_iaddr,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001393 &dim_tot_hitm,
1394 &dim_lcl_hitm,
1395 &dim_rmt_hitm,
1396 &dim_cl_lcl_hitm,
1397 &dim_cl_rmt_hitm,
Jiri Olsa0f188962016-05-04 10:10:11 +02001398 &dim_stores,
1399 &dim_stores_l1hit,
1400 &dim_stores_l1miss,
1401 &dim_cl_stores_l1hit,
1402 &dim_cl_stores_l1miss,
Jiri Olsa1295f682016-05-04 10:18:24 +02001403 &dim_ld_fbhit,
1404 &dim_ld_l1hit,
1405 &dim_ld_l2hit,
Jiri Olsa4d089102016-05-04 10:27:51 +02001406 &dim_ld_llchit,
1407 &dim_ld_rmthit,
Jiri Olsa04402d22016-05-19 10:10:51 +02001408 &dim_ld_llcmiss,
Jiri Olsa01b84d72016-05-04 10:35:29 +02001409 &dim_tot_recs,
Jiri Olsa55177c42016-05-19 09:52:37 +02001410 &dim_tot_loads,
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001411 &dim_percent_hitm,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001412 &dim_percent_rmt_hitm,
1413 &dim_percent_lcl_hitm,
1414 &dim_percent_stores_l1hit,
1415 &dim_percent_stores_l1miss,
Jiri Olsa6c70f542016-05-28 12:30:13 +02001416 &dim_dram_lcl,
1417 &dim_dram_rmt,
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001418 &dim_pid,
Jiri Olsae87019c2016-05-25 08:50:10 +02001419 &dim_tid,
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001420 &dim_symbol,
1421 &dim_dso,
Jiri Olsa1e181b92016-06-03 15:40:28 +02001422 &dim_node,
Jiri Olsa92062d52016-06-05 13:40:53 +02001423 &dim_mean_rmt,
1424 &dim_mean_lcl,
1425 &dim_mean_load,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001426 &dim_cpucnt,
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001427 &dim_srcline,
Jiri Olsac75540e2016-09-22 17:36:41 +02001428 NULL,
1429};
1430
1431static void fmt_free(struct perf_hpp_fmt *fmt)
1432{
1433 struct c2c_fmt *c2c_fmt;
1434
1435 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1436 free(c2c_fmt);
1437}
1438
1439static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1440{
1441 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1442 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1443
1444 return c2c_a->dim == c2c_b->dim;
1445}
1446
1447static struct c2c_dimension *get_dimension(const char *name)
1448{
1449 unsigned int i;
1450
1451 for (i = 0; dimensions[i]; i++) {
1452 struct c2c_dimension *dim = dimensions[i];
1453
1454 if (!strcmp(dim->name, name))
1455 return dim;
1456 };
1457
1458 return NULL;
1459}
1460
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001461static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1462 struct hist_entry *he)
1463{
1464 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1465 struct c2c_dimension *dim = c2c_fmt->dim;
1466 size_t len = fmt->user_len;
1467
1468 if (!len)
1469 len = hists__col_len(he->hists, dim->se->se_width_idx);
1470
1471 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1472}
1473
1474static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1475 struct hist_entry *a, struct hist_entry *b)
1476{
1477 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1478 struct c2c_dimension *dim = c2c_fmt->dim;
1479
1480 return dim->se->se_cmp(a, b);
1481}
1482
1483static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1484 struct hist_entry *a, struct hist_entry *b)
1485{
1486 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1487 struct c2c_dimension *dim = c2c_fmt->dim;
1488 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1489
1490 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1491 return collapse_fn(a, b);
1492}
1493
Jiri Olsac75540e2016-09-22 17:36:41 +02001494static struct c2c_fmt *get_format(const char *name)
1495{
1496 struct c2c_dimension *dim = get_dimension(name);
1497 struct c2c_fmt *c2c_fmt;
1498 struct perf_hpp_fmt *fmt;
1499
1500 if (!dim)
1501 return NULL;
1502
1503 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1504 if (!c2c_fmt)
1505 return NULL;
1506
1507 c2c_fmt->dim = dim;
1508
1509 fmt = &c2c_fmt->fmt;
1510 INIT_LIST_HEAD(&fmt->list);
1511 INIT_LIST_HEAD(&fmt->sort_list);
1512
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001513 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1514 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
Jiri Olsa9cb35002016-05-04 12:16:50 +02001515 fmt->color = dim->se ? NULL : dim->color;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001516 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
Jiri Olsac75540e2016-09-22 17:36:41 +02001517 fmt->header = c2c_header;
1518 fmt->width = c2c_width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001519 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
Jiri Olsac75540e2016-09-22 17:36:41 +02001520 fmt->equal = fmt_equal;
1521 fmt->free = fmt_free;
1522
1523 return c2c_fmt;
1524}
1525
1526static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1527{
1528 struct c2c_fmt *c2c_fmt = get_format(name);
1529
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001530 if (!c2c_fmt) {
1531 reset_dimensions();
1532 return output_field_add(hpp_list, name);
1533 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001534
1535 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1536 return 0;
1537}
1538
1539static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1540{
1541 struct c2c_fmt *c2c_fmt = get_format(name);
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001542 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +02001543
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001544 if (!c2c_fmt) {
1545 reset_dimensions();
1546 return sort_dimension__add(hpp_list, name, NULL, 0);
1547 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001548
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001549 dim = c2c_fmt->dim;
1550 if (dim == &dim_dso)
1551 hpp_list->dso = 1;
1552
Jiri Olsac75540e2016-09-22 17:36:41 +02001553 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1554 return 0;
1555}
1556
1557#define PARSE_LIST(_list, _fn) \
1558 do { \
1559 char *tmp, *tok; \
1560 ret = 0; \
1561 \
1562 if (!_list) \
1563 break; \
1564 \
1565 for (tok = strtok_r((char *)_list, ", ", &tmp); \
1566 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
1567 ret = _fn(hpp_list, tok); \
1568 if (ret == -EINVAL) { \
1569 error("Invalid --fields key: `%s'", tok); \
1570 break; \
1571 } else if (ret == -ESRCH) { \
1572 error("Unknown --fields key: `%s'", tok); \
1573 break; \
1574 } \
1575 } \
1576 } while (0)
1577
1578static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1579 const char *output_,
1580 const char *sort_)
1581{
1582 char *output = output_ ? strdup(output_) : NULL;
1583 char *sort = sort_ ? strdup(sort_) : NULL;
1584 int ret;
1585
1586 PARSE_LIST(output, c2c_hists__init_output);
1587 PARSE_LIST(sort, c2c_hists__init_sort);
1588
1589 /* copy sort keys to output fields */
1590 perf_hpp__setup_output_field(hpp_list);
1591
1592 /*
1593 * We dont need other sorting keys other than those
1594 * we already specified. It also really slows down
1595 * the processing a lot with big number of output
1596 * fields, so switching this off for c2c.
1597 */
1598
1599#if 0
1600 /* and then copy output fields to sort keys */
1601 perf_hpp__append_sort_keys(&hists->list);
1602#endif
1603
1604 free(output);
1605 free(sort);
1606 return ret;
1607}
1608
1609static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001610 const char *sort,
1611 int nr_header_lines)
Jiri Olsac75540e2016-09-22 17:36:41 +02001612{
1613 __hists__init(&hists->hists, &hists->list);
1614
1615 /*
1616 * Initialize only with sort fields, we need to resort
1617 * later anyway, and that's where we add output fields
1618 * as well.
1619 */
1620 perf_hpp_list__init(&hists->list);
1621
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001622 /* Overload number of header lines.*/
1623 hists->list.nr_header_lines = nr_header_lines;
1624
Jiri Olsac75540e2016-09-22 17:36:41 +02001625 return hpp_list__parse(&hists->list, NULL, sort);
1626}
1627
1628__maybe_unused
1629static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1630 const char *output,
1631 const char *sort)
1632{
1633 perf_hpp__reset_output_field(&c2c_hists->list);
1634 return hpp_list__parse(&c2c_hists->list, output, sort);
1635}
1636
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001637static int filter_cb(struct hist_entry *he)
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001638{
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001639 if (c2c.show_src && !he->srcline)
1640 he->srcline = hist_entry__get_srcline(he);
1641
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001642 return 0;
1643}
1644
1645static int resort_cl_cb(struct hist_entry *he)
1646{
1647 struct c2c_hist_entry *c2c_he;
1648 struct c2c_hists *c2c_hists;
1649
1650 c2c_he = container_of(he, struct c2c_hist_entry, he);
1651 c2c_hists = c2c_he->hists;
1652
1653 if (c2c_hists) {
Jiri Olsa22dd59d2016-05-10 14:08:29 +02001654 c2c_hists__reinit(c2c_hists,
1655 "percent_rmt_hitm,"
1656 "percent_lcl_hitm,"
1657 "percent_stores_l1hit,"
1658 "percent_stores_l1miss,"
1659 "offset,"
1660 "pid,"
1661 "tid,"
1662 "mean_rmt,"
1663 "mean_lcl,"
1664 "mean_load,"
1665 "cpucnt,"
1666 "symbol,"
1667 "dso,"
1668 "node",
1669 "offset,rmt_hitm,lcl_hitm");
1670
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001671 hists__collapse_resort(&c2c_hists->hists, NULL);
1672 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
1673 }
1674
1675 return 0;
1676}
1677
Jiri Olsa1e181b92016-06-03 15:40:28 +02001678static void setup_nodes_header(void)
1679{
1680 dim_node.header = header_node[c2c.node_info];
1681}
1682
1683static int setup_nodes(struct perf_session *session)
1684{
1685 struct numa_node *n;
1686 unsigned long **nodes;
1687 int node, cpu;
1688 int *cpu2node;
1689
1690 if (c2c.node_info > 2)
1691 c2c.node_info = 2;
1692
1693 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1694 c2c.cpus_cnt = session->header.env.nr_cpus_online;
1695
1696 n = session->header.env.numa_nodes;
1697 if (!n)
1698 return -EINVAL;
1699
1700 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
1701 if (!nodes)
1702 return -ENOMEM;
1703
1704 c2c.nodes = nodes;
1705
1706 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
1707 if (!cpu2node)
1708 return -ENOMEM;
1709
1710 for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
1711 cpu2node[cpu] = -1;
1712
1713 c2c.cpu2node = cpu2node;
1714
1715 for (node = 0; node < c2c.nodes_cnt; node++) {
1716 struct cpu_map *map = n[node].map;
1717 unsigned long *set;
1718
1719 set = bitmap_alloc(c2c.cpus_cnt);
1720 if (!set)
1721 return -ENOMEM;
1722
1723 for (cpu = 0; cpu < map->nr; cpu++) {
1724 set_bit(map->map[cpu], set);
1725
1726 if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
1727 return -EINVAL;
1728
1729 cpu2node[map->map[cpu]] = node;
1730 }
1731
1732 nodes[node] = set;
1733 }
1734
1735 setup_nodes_header();
1736 return 0;
1737}
1738
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02001739#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
1740
1741static int resort_hitm_cb(struct hist_entry *he)
1742{
1743 struct c2c_hist_entry *c2c_he;
1744 c2c_he = container_of(he, struct c2c_hist_entry, he);
1745
1746 if (HAS_HITMS(c2c_he)) {
1747 c2c.shared_clines++;
1748 c2c_add_stats(&c2c.hitm_stats, &c2c_he->stats);
1749 }
1750
1751 return 0;
1752}
1753
1754static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
1755{
1756 struct rb_node *next = rb_first(&hists->entries);
1757 int ret = 0;
1758
1759 while (next) {
1760 struct hist_entry *he;
1761
1762 he = rb_entry(next, struct hist_entry, rb_node);
1763 ret = cb(he);
1764 if (ret)
1765 break;
1766 next = rb_next(&he->rb_node);
1767 }
1768
1769 return ret;
1770}
1771
Jiri Olsa74c63a22016-05-02 20:01:59 +02001772static void print_c2c__display_stats(FILE *out)
1773{
1774 int llc_misses;
1775 struct c2c_stats *stats = &c2c.hists.stats;
1776
1777 llc_misses = stats->lcl_dram +
1778 stats->rmt_dram +
1779 stats->rmt_hit +
1780 stats->rmt_hitm;
1781
1782 fprintf(out, "=================================================\n");
1783 fprintf(out, " Trace Event Information \n");
1784 fprintf(out, "=================================================\n");
1785 fprintf(out, " Total records : %10d\n", stats->nr_entries);
1786 fprintf(out, " Locked Load/Store Operations : %10d\n", stats->locks);
1787 fprintf(out, " Load Operations : %10d\n", stats->load);
1788 fprintf(out, " Loads - uncacheable : %10d\n", stats->ld_uncache);
1789 fprintf(out, " Loads - IO : %10d\n", stats->ld_io);
1790 fprintf(out, " Loads - Miss : %10d\n", stats->ld_miss);
1791 fprintf(out, " Loads - no mapping : %10d\n", stats->ld_noadrs);
1792 fprintf(out, " Load Fill Buffer Hit : %10d\n", stats->ld_fbhit);
1793 fprintf(out, " Load L1D hit : %10d\n", stats->ld_l1hit);
1794 fprintf(out, " Load L2D hit : %10d\n", stats->ld_l2hit);
1795 fprintf(out, " Load LLC hit : %10d\n", stats->ld_llchit + stats->lcl_hitm);
1796 fprintf(out, " Load Local HITM : %10d\n", stats->lcl_hitm);
1797 fprintf(out, " Load Remote HITM : %10d\n", stats->rmt_hitm);
1798 fprintf(out, " Load Remote HIT : %10d\n", stats->rmt_hit);
1799 fprintf(out, " Load Local DRAM : %10d\n", stats->lcl_dram);
1800 fprintf(out, " Load Remote DRAM : %10d\n", stats->rmt_dram);
1801 fprintf(out, " Load MESI State Exclusive : %10d\n", stats->ld_excl);
1802 fprintf(out, " Load MESI State Shared : %10d\n", stats->ld_shared);
1803 fprintf(out, " Load LLC Misses : %10d\n", llc_misses);
1804 fprintf(out, " LLC Misses to Local DRAM : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);
1805 fprintf(out, " LLC Misses to Remote DRAM : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);
1806 fprintf(out, " LLC Misses to Remote cache (HIT) : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.);
1807 fprintf(out, " LLC Misses to Remote cache (HITM) : %10.1f%%\n", ((double)stats->rmt_hitm/(double)llc_misses) * 100.);
1808 fprintf(out, " Store Operations : %10d\n", stats->store);
1809 fprintf(out, " Store - uncacheable : %10d\n", stats->st_uncache);
1810 fprintf(out, " Store - no mapping : %10d\n", stats->st_noadrs);
1811 fprintf(out, " Store L1D Hit : %10d\n", stats->st_l1hit);
1812 fprintf(out, " Store L1D Miss : %10d\n", stats->st_l1miss);
1813 fprintf(out, " No Page Map Rejects : %10d\n", stats->nomap);
1814 fprintf(out, " Unable to parse data source : %10d\n", stats->noparse);
1815}
1816
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02001817static void print_shared_cacheline_info(FILE *out)
1818{
1819 struct c2c_stats *stats = &c2c.hitm_stats;
1820 int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
1821
1822 fprintf(out, "=================================================\n");
1823 fprintf(out, " Global Shared Cache Line Event Information \n");
1824 fprintf(out, "=================================================\n");
1825 fprintf(out, " Total Shared Cache Lines : %10d\n", c2c.shared_clines);
1826 fprintf(out, " Load HITs on shared lines : %10d\n", stats->load);
1827 fprintf(out, " Fill Buffer Hits on shared lines : %10d\n", stats->ld_fbhit);
1828 fprintf(out, " L1D hits on shared lines : %10d\n", stats->ld_l1hit);
1829 fprintf(out, " L2D hits on shared lines : %10d\n", stats->ld_l2hit);
1830 fprintf(out, " LLC hits on shared lines : %10d\n", stats->ld_llchit + stats->lcl_hitm);
1831 fprintf(out, " Locked Access on shared lines : %10d\n", stats->locks);
1832 fprintf(out, " Store HITs on shared lines : %10d\n", stats->store);
1833 fprintf(out, " Store L1D hits on shared lines : %10d\n", stats->st_l1hit);
1834 fprintf(out, " Total Merged records : %10d\n", hitm_cnt + stats->store);
1835}
1836
Jiri Olsa2d388bd2016-05-03 14:32:56 +02001837static void print_cacheline(struct c2c_hists *c2c_hists,
1838 struct hist_entry *he_cl,
1839 struct perf_hpp_list *hpp_list,
1840 FILE *out)
1841{
1842 char bf[1000];
1843 struct perf_hpp hpp = {
1844 .buf = bf,
1845 .size = 1000,
1846 };
1847 static bool once;
1848
1849 if (!once) {
1850 hists__fprintf_headers(&c2c_hists->hists, out);
1851 once = true;
1852 } else {
1853 fprintf(out, "\n");
1854 }
1855
1856 fprintf(out, " ------------------------------------------------------\n");
1857 __hist_entry__snprintf(he_cl, &hpp, hpp_list);
1858 fprintf(out, "%s\n", bf);
1859 fprintf(out, " ------------------------------------------------------\n");
1860
1861 hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, true);
1862}
1863
1864static void print_pareto(FILE *out)
1865{
1866 struct perf_hpp_list hpp_list;
1867 struct rb_node *nd;
1868 int ret;
1869
1870 perf_hpp_list__init(&hpp_list);
1871 ret = hpp_list__parse(&hpp_list,
1872 "cl_rmt_hitm,"
1873 "cl_lcl_hitm,"
1874 "cl_stores_l1hit,"
1875 "cl_stores_l1miss,"
1876 "dcacheline",
1877 NULL);
1878
1879 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
1880 return;
1881
1882 nd = rb_first(&c2c.hists.hists.entries);
1883
1884 for (; nd; nd = rb_next(nd)) {
1885 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1886 struct c2c_hist_entry *c2c_he;
1887
1888 if (he->filtered)
1889 continue;
1890
1891 c2c_he = container_of(he, struct c2c_hist_entry, he);
1892 print_cacheline(c2c_he->hists, he, &hpp_list, out);
1893 }
1894}
1895
1896static void perf_c2c__hists_fprintf(FILE *out)
1897{
1898 setup_pager();
1899
Jiri Olsa74c63a22016-05-02 20:01:59 +02001900 print_c2c__display_stats(out);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02001901 fprintf(out, "\n");
1902 print_shared_cacheline_info(out);
Jiri Olsa74c63a22016-05-02 20:01:59 +02001903
1904 if (c2c.stats_only)
1905 return;
1906
Jiri Olsa2d388bd2016-05-03 14:32:56 +02001907 fprintf(out, "\n");
1908 fprintf(out, "=================================================\n");
1909 fprintf(out, " Shared Data Cache Line Table \n");
1910 fprintf(out, "=================================================\n");
1911 fprintf(out, "#\n");
1912
1913 hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, false);
1914
1915 fprintf(out, "\n");
1916 fprintf(out, "=================================================\n");
1917 fprintf(out, " Shared Cache Line Distribution Pareto \n");
1918 fprintf(out, "=================================================\n");
1919 fprintf(out, "#\n");
1920
1921 print_pareto(out);
1922}
Jiri Olsa1e181b92016-06-03 15:40:28 +02001923
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001924#ifdef HAVE_SLANG_SUPPORT
1925static void c2c_browser__update_nr_entries(struct hist_browser *hb)
1926{
1927 u64 nr_entries = 0;
1928 struct rb_node *nd = rb_first(&hb->hists->entries);
1929
1930 while (nd) {
1931 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1932
1933 if (!he->filtered)
1934 nr_entries++;
1935
1936 nd = rb_next(nd);
1937 }
1938
1939 hb->nr_non_filtered_entries = nr_entries;
1940}
1941
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02001942struct c2c_cacheline_browser {
1943 struct hist_browser hb;
1944 struct hist_entry *he;
1945};
1946
1947static int
1948perf_c2c_cacheline_browser__title(struct hist_browser *browser,
1949 char *bf, size_t size)
1950{
1951 struct c2c_cacheline_browser *cl_browser;
1952 struct hist_entry *he;
1953 uint64_t addr = 0;
1954
1955 cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
1956 he = cl_browser->he;
1957
1958 if (he->mem_info)
1959 addr = cl_address(he->mem_info->daddr.addr);
1960
1961 scnprintf(bf, size, "Cacheline 0x%lx", addr);
1962 return 0;
1963}
1964
1965static struct c2c_cacheline_browser*
1966c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
1967{
1968 struct c2c_cacheline_browser *browser;
1969
1970 browser = zalloc(sizeof(*browser));
1971 if (browser) {
1972 hist_browser__init(&browser->hb, hists);
1973 browser->hb.c2c_filter = true;
1974 browser->hb.title = perf_c2c_cacheline_browser__title;
1975 browser->he = he;
1976 }
1977
1978 return browser;
1979}
1980
1981static int perf_c2c__browse_cacheline(struct hist_entry *he)
1982{
1983 struct c2c_hist_entry *c2c_he;
1984 struct c2c_hists *c2c_hists;
1985 struct c2c_cacheline_browser *cl_browser;
1986 struct hist_browser *browser;
1987 int key = -1;
1988
1989 c2c_he = container_of(he, struct c2c_hist_entry, he);
1990 c2c_hists = c2c_he->hists;
1991
1992 cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
1993 if (cl_browser == NULL)
1994 return -1;
1995
1996 browser = &cl_browser->hb;
1997
1998 /* reset abort key so that it can get Ctrl-C as a key */
1999 SLang_reset_tty();
2000 SLang_init_tty(0, 0, 0);
2001
2002 c2c_browser__update_nr_entries(browser);
2003
2004 while (1) {
2005 key = hist_browser__run(browser, "help");
2006
2007 switch (key) {
2008 case 'q':
2009 goto out;
2010 default:
2011 break;
2012 }
2013 }
2014
2015out:
2016 free(cl_browser);
2017 return 0;
2018}
2019
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002020static int perf_c2c_browser__title(struct hist_browser *browser,
2021 char *bf, size_t size)
2022{
2023 scnprintf(bf, size,
2024 "Shared Data Cache Line Table "
2025 "(%lu entries)", browser->nr_non_filtered_entries);
2026 return 0;
2027}
2028
2029static struct hist_browser*
2030perf_c2c_browser__new(struct hists *hists)
2031{
2032 struct hist_browser *browser = hist_browser__new(hists);
2033
2034 if (browser) {
2035 browser->title = perf_c2c_browser__title;
2036 browser->c2c_filter = true;
2037 }
2038
2039 return browser;
2040}
2041
2042static int perf_c2c__hists_browse(struct hists *hists)
2043{
2044 struct hist_browser *browser;
2045 int key = -1;
2046
2047 browser = perf_c2c_browser__new(hists);
2048 if (browser == NULL)
2049 return -1;
2050
2051 /* reset abort key so that it can get Ctrl-C as a key */
2052 SLang_reset_tty();
2053 SLang_init_tty(0, 0, 0);
2054
2055 c2c_browser__update_nr_entries(browser);
2056
2057 while (1) {
2058 key = hist_browser__run(browser, "help");
2059
2060 switch (key) {
2061 case 'q':
2062 goto out;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002063 case 'd':
2064 perf_c2c__browse_cacheline(browser->he_selection);
2065 break;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002066 default:
2067 break;
2068 }
2069 }
2070
2071out:
2072 hist_browser__delete(browser);
2073 return 0;
2074}
2075
2076static void perf_c2c_display(void)
2077{
2078 if (c2c.use_stdio)
2079 perf_c2c__hists_fprintf(stdout);
2080 else
2081 perf_c2c__hists_browse(&c2c.hists.hists);
2082}
2083#else
2084static void perf_c2c_display(void)
2085{
2086 use_browser = 0;
2087 perf_c2c__hists_fprintf(stdout);
2088}
2089#endif /* HAVE_SLANG_SUPPORT */
2090
2091static void ui_quirks(void)
2092{
2093 if (!c2c.use_stdio) {
2094 dim_offset.width = 5;
2095 dim_offset.header = header_offset_tui;
2096 }
2097}
2098
Jiri Olsa903a6f12016-09-22 17:36:40 +02002099static int perf_c2c__report(int argc, const char **argv)
2100{
2101 struct perf_session *session;
Jiri Olsa78b27542016-09-22 17:36:44 +02002102 struct ui_progress prog;
Jiri Olsa903a6f12016-09-22 17:36:40 +02002103 struct perf_data_file file = {
2104 .mode = PERF_DATA_MODE_READ,
2105 };
2106 const struct option c2c_options[] = {
2107 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
2108 "file", "vmlinux pathname"),
2109 OPT_INCR('v', "verbose", &verbose,
2110 "be more verbose (show counter open errors, etc)"),
2111 OPT_STRING('i', "input", &input_name, "file",
2112 "the input file to process"),
Jiri Olsa1e181b92016-06-03 15:40:28 +02002113 OPT_INCR('N', "node-info", &c2c.node_info,
2114 "show extra node info in report (repeat for more info)"),
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002115#ifdef HAVE_SLANG_SUPPORT
2116 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2117#endif
Jiri Olsa74c63a22016-05-02 20:01:59 +02002118 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
2119 "Use the stdio interface"),
Jiri Olsa903a6f12016-09-22 17:36:40 +02002120 OPT_END()
2121 };
2122 int err = 0;
2123
2124 argc = parse_options(argc, argv, c2c_options, report_c2c_usage,
2125 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa78b27542016-09-22 17:36:44 +02002126 if (argc)
Jiri Olsa903a6f12016-09-22 17:36:40 +02002127 usage_with_options(report_c2c_usage, c2c_options);
2128
Jiri Olsa74c63a22016-05-02 20:01:59 +02002129 if (c2c.stats_only)
2130 c2c.use_stdio = true;
2131
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002132 if (c2c.use_stdio)
2133 use_browser = 0;
2134 else
2135 use_browser = 1;
2136
2137 setup_browser(false);
2138
Jiri Olsa78b27542016-09-22 17:36:44 +02002139 if (!input_name || !strlen(input_name))
2140 input_name = "perf.data";
2141
Jiri Olsa903a6f12016-09-22 17:36:40 +02002142 file.path = input_name;
2143
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02002144 err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
Jiri Olsac75540e2016-09-22 17:36:41 +02002145 if (err) {
2146 pr_debug("Failed to initialize hists\n");
2147 goto out;
2148 }
2149
Jiri Olsa903a6f12016-09-22 17:36:40 +02002150 session = perf_session__new(&file, 0, &c2c.tool);
2151 if (session == NULL) {
2152 pr_debug("No memory for session\n");
2153 goto out;
2154 }
Jiri Olsa1e181b92016-06-03 15:40:28 +02002155 err = setup_nodes(session);
2156 if (err) {
2157 pr_err("Failed setup nodes\n");
2158 goto out;
2159 }
Jiri Olsa903a6f12016-09-22 17:36:40 +02002160
2161 if (symbol__init(&session->header.env) < 0)
2162 goto out_session;
2163
2164 /* No pipe support at the moment. */
2165 if (perf_data_file__is_pipe(session->file)) {
2166 pr_debug("No pipe support at the moment.\n");
2167 goto out_session;
2168 }
2169
Jiri Olsa78b27542016-09-22 17:36:44 +02002170 err = perf_session__process_events(session);
2171 if (err) {
2172 pr_err("failed to process sample\n");
2173 goto out_session;
2174 }
2175
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002176 c2c_hists__reinit(&c2c.hists,
2177 "dcacheline,"
2178 "tot_recs,"
2179 "percent_hitm,"
2180 "tot_hitm,lcl_hitm,rmt_hitm,"
2181 "stores,stores_l1hit,stores_l1miss,"
2182 "dram_lcl,dram_rmt,"
2183 "ld_llcmiss,"
2184 "tot_loads,"
2185 "ld_fbhit,ld_l1hit,ld_l2hit,"
2186 "ld_lclhit,ld_rmthit",
2187 "rmt_hitm"
2188 );
2189
Jiri Olsa78b27542016-09-22 17:36:44 +02002190 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
2191
2192 hists__collapse_resort(&c2c.hists.hists, NULL);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002193 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_hitm_cb);
2194 hists__iterate_cb(&c2c.hists.hists, resort_cl_cb);
Jiri Olsa78b27542016-09-22 17:36:44 +02002195
2196 ui_progress__finish();
2197
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002198 ui_quirks();
2199
2200 perf_c2c_display();
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002201
Jiri Olsa903a6f12016-09-22 17:36:40 +02002202out_session:
2203 perf_session__delete(session);
2204out:
2205 return err;
2206}
2207
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002208static int parse_record_events(const struct option *opt __maybe_unused,
2209 const char *str, int unset __maybe_unused)
2210{
2211 bool *event_set = (bool *) opt->value;
2212
2213 *event_set = true;
2214 return perf_mem_events__parse(str);
2215}
2216
2217
2218static const char * const __usage_record[] = {
2219 "perf c2c record [<options>] [<command>]",
2220 "perf c2c record [<options>] -- <command> [<options>]",
2221 NULL
2222};
2223
2224static const char * const *record_mem_usage = __usage_record;
2225
2226static int perf_c2c__record(int argc, const char **argv)
2227{
2228 int rec_argc, i = 0, j;
2229 const char **rec_argv;
2230 int ret;
2231 bool all_user = false, all_kernel = false;
2232 bool event_set = false;
2233 struct option options[] = {
2234 OPT_CALLBACK('e', "event", &event_set, "event",
2235 "event selector. Use 'perf mem record -e list' to list available events",
2236 parse_record_events),
2237 OPT_INCR('v', "verbose", &verbose,
2238 "be more verbose (show counter open errors, etc)"),
2239 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
2240 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
2241 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
2242 OPT_END()
2243 };
2244
2245 if (perf_mem_events__init()) {
2246 pr_err("failed: memory events not supported\n");
2247 return -1;
2248 }
2249
2250 argc = parse_options(argc, argv, options, record_mem_usage,
2251 PARSE_OPT_KEEP_UNKNOWN);
2252
2253 rec_argc = argc + 10; /* max number of arguments */
2254 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2255 if (!rec_argv)
2256 return -1;
2257
2258 rec_argv[i++] = "record";
2259
2260 if (!event_set) {
2261 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
2262 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
2263 }
2264
2265 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
2266 rec_argv[i++] = "-W";
2267
2268 rec_argv[i++] = "-d";
2269 rec_argv[i++] = "--sample-cpu";
2270
2271 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
2272 if (!perf_mem_events[j].record)
2273 continue;
2274
2275 if (!perf_mem_events[j].supported) {
2276 pr_err("failed: event '%s' not supported\n",
2277 perf_mem_events[j].name);
2278 return -1;
2279 }
2280
2281 rec_argv[i++] = "-e";
2282 rec_argv[i++] = perf_mem_events__name(j);
2283 };
2284
2285 if (all_user)
2286 rec_argv[i++] = "--all-user";
2287
2288 if (all_kernel)
2289 rec_argv[i++] = "--all-kernel";
2290
2291 for (j = 0; j < argc; j++, i++)
2292 rec_argv[i] = argv[j];
2293
2294 if (verbose > 0) {
2295 pr_debug("calling: ");
2296
2297 j = 0;
2298
2299 while (rec_argv[j]) {
2300 pr_debug("%s ", rec_argv[j]);
2301 j++;
2302 }
2303 pr_debug("\n");
2304 }
2305
2306 ret = cmd_record(i, rec_argv, NULL);
2307 free(rec_argv);
2308 return ret;
2309}
2310
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002311int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused)
2312{
2313 const struct option c2c_options[] = {
2314 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
2315 OPT_END()
2316 };
2317
2318 argc = parse_options(argc, argv, c2c_options, c2c_usage,
2319 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002320
2321 if (!argc)
2322 usage_with_options(c2c_usage, c2c_options);
2323
2324 if (!strncmp(argv[0], "rec", 3)) {
2325 return perf_c2c__record(argc, argv);
Jiri Olsa903a6f12016-09-22 17:36:40 +02002326 } else if (!strncmp(argv[0], "rep", 3)) {
2327 return perf_c2c__report(argc, argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002328 } else {
2329 usage_with_options(c2c_usage, c2c_options);
2330 }
2331
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002332 return 0;
2333}