blob: 579c9e9f73c2be5b65a474038c4aadb006fc8c0e [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 Olsa2709b972016-08-27 11:40:23 +020016#include "evlist.h"
17#include "evsel.h"
Jiri Olsa2d388bd2016-05-03 14:32:56 +020018#include <asm/bug.h>
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010019#include "ui/browsers/hists.h"
Jiri Olsadd805762016-05-11 18:23:48 +020020#include "evlist.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020021
Jiri Olsac75540e2016-09-22 17:36:41 +020022struct c2c_hists {
23 struct hists hists;
24 struct perf_hpp_list list;
Jiri Olsab2252ae2016-09-22 17:36:46 +020025 struct c2c_stats stats;
Jiri Olsac75540e2016-09-22 17:36:41 +020026};
27
Jiri Olsa92062d52016-06-05 13:40:53 +020028struct compute_stats {
29 struct stats lcl_hitm;
30 struct stats rmt_hitm;
31 struct stats load;
32};
33
Jiri Olsa78b27542016-09-22 17:36:44 +020034struct c2c_hist_entry {
35 struct c2c_hists *hists;
Jiri Olsab2252ae2016-09-22 17:36:46 +020036 struct c2c_stats stats;
Jiri Olsa1e181b92016-06-03 15:40:28 +020037 unsigned long *cpuset;
38 struct c2c_stats *node_stats;
Jiri Olsa92062d52016-06-05 13:40:53 +020039
40 struct compute_stats cstats;
41
Jiri Olsa78b27542016-09-22 17:36:44 +020042 /*
43 * must be at the end,
44 * because of its callchain dynamic entry
45 */
46 struct hist_entry he;
47};
48
Jiri Olsafc9c6302016-05-24 14:14:38 +020049static char const *coalesce_default = "pid,tid,iaddr";
50
Jiri Olsa903a6f12016-09-22 17:36:40 +020051struct perf_c2c {
Jiri Olsac75540e2016-09-22 17:36:41 +020052 struct perf_tool tool;
53 struct c2c_hists hists;
Jiri Olsa1e181b92016-06-03 15:40:28 +020054
55 unsigned long **nodes;
56 int nodes_cnt;
57 int cpus_cnt;
58 int *cpu2node;
59 int node_info;
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +020060
61 bool show_src;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010062 bool use_stdio;
Jiri Olsa74c63a22016-05-02 20:01:59 +020063 bool stats_only;
Jiri Olsa7ef2efa2016-07-01 11:12:11 +020064
65 /* HITM shared clines stats */
66 struct c2c_stats hitm_stats;
67 int shared_clines;
Jiri Olsa55b95772016-05-29 10:21:45 +020068
69 int display;
Jiri Olsafc9c6302016-05-24 14:14:38 +020070
71 const char *coalesce;
72 char *cl_sort;
73 char *cl_resort;
74 char *cl_output;
Jiri Olsa55b95772016-05-29 10:21:45 +020075};
76
77enum {
78 DISPLAY_LCL,
79 DISPLAY_RMT,
Jiri Olsa903a6f12016-09-22 17:36:40 +020080};
81
82static struct perf_c2c c2c;
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020083
Jiri Olsa78b27542016-09-22 17:36:44 +020084static void *c2c_he_zalloc(size_t size)
85{
86 struct c2c_hist_entry *c2c_he;
87
88 c2c_he = zalloc(size + sizeof(*c2c_he));
89 if (!c2c_he)
90 return NULL;
91
Jiri Olsa1e181b92016-06-03 15:40:28 +020092 c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
93 if (!c2c_he->cpuset)
94 return NULL;
95
96 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
97 if (!c2c_he->node_stats)
98 return NULL;
99
Jiri Olsa92062d52016-06-05 13:40:53 +0200100 init_stats(&c2c_he->cstats.lcl_hitm);
101 init_stats(&c2c_he->cstats.rmt_hitm);
102 init_stats(&c2c_he->cstats.load);
103
Jiri Olsa78b27542016-09-22 17:36:44 +0200104 return &c2c_he->he;
105}
106
107static void c2c_he_free(void *he)
108{
109 struct c2c_hist_entry *c2c_he;
110
111 c2c_he = container_of(he, struct c2c_hist_entry, he);
112 if (c2c_he->hists) {
113 hists__delete_entries(&c2c_he->hists->hists);
114 free(c2c_he->hists);
115 }
116
Jiri Olsa1e181b92016-06-03 15:40:28 +0200117 free(c2c_he->cpuset);
118 free(c2c_he->node_stats);
Jiri Olsa78b27542016-09-22 17:36:44 +0200119 free(c2c_he);
120}
121
122static struct hist_entry_ops c2c_entry_ops = {
123 .new = c2c_he_zalloc,
124 .free = c2c_he_free,
125};
126
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200127static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200128 const char *sort,
129 int nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200130
Jiri Olsab2252ae2016-09-22 17:36:46 +0200131static struct c2c_hists*
132he__get_c2c_hists(struct hist_entry *he,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200133 const char *sort,
134 int nr_header_lines)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200135{
136 struct c2c_hist_entry *c2c_he;
137 struct c2c_hists *hists;
138 int ret;
139
140 c2c_he = container_of(he, struct c2c_hist_entry, he);
141 if (c2c_he->hists)
Jiri Olsab2252ae2016-09-22 17:36:46 +0200142 return c2c_he->hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200143
144 hists = c2c_he->hists = zalloc(sizeof(*hists));
145 if (!hists)
146 return NULL;
147
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200148 ret = c2c_hists__init(hists, sort, nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200149 if (ret) {
150 free(hists);
151 return NULL;
152 }
153
Jiri Olsab2252ae2016-09-22 17:36:46 +0200154 return hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200155}
156
Jiri Olsa1e181b92016-06-03 15:40:28 +0200157static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
158 struct perf_sample *sample)
159{
160 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
161 "WARNING: no sample cpu value"))
162 return;
163
164 set_bit(sample->cpu, c2c_he->cpuset);
165}
166
Jiri Olsa92062d52016-06-05 13:40:53 +0200167static void compute_stats(struct c2c_hist_entry *c2c_he,
168 struct c2c_stats *stats,
169 u64 weight)
170{
171 struct compute_stats *cstats = &c2c_he->cstats;
172
173 if (stats->rmt_hitm)
174 update_stats(&cstats->rmt_hitm, weight);
175 else if (stats->lcl_hitm)
176 update_stats(&cstats->lcl_hitm, weight);
177 else if (stats->load)
178 update_stats(&cstats->load, weight);
179}
180
Jiri Olsa78b27542016-09-22 17:36:44 +0200181static int process_sample_event(struct perf_tool *tool __maybe_unused,
182 union perf_event *event,
183 struct perf_sample *sample,
184 struct perf_evsel *evsel __maybe_unused,
185 struct machine *machine)
186{
Jiri Olsab2252ae2016-09-22 17:36:46 +0200187 struct c2c_hists *c2c_hists = &c2c.hists;
188 struct c2c_hist_entry *c2c_he;
189 struct c2c_stats stats = { .nr_entries = 0, };
Jiri Olsa78b27542016-09-22 17:36:44 +0200190 struct hist_entry *he;
191 struct addr_location al;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200192 struct mem_info *mi, *mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200193 int ret;
194
195 if (machine__resolve(machine, &al, sample) < 0) {
196 pr_debug("problem processing %d event, skipping it.\n",
197 event->header.type);
198 return -1;
199 }
200
Jiri Olsadd805762016-05-11 18:23:48 +0200201 ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
202 evsel, &al, sysctl_perf_event_max_stack);
203 if (ret)
204 goto out;
205
Jiri Olsa78b27542016-09-22 17:36:44 +0200206 mi = sample__resolve_mem(sample, &al);
207 if (mi == NULL)
208 return -ENOMEM;
209
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200210 mi_dup = memdup(mi, sizeof(*mi));
211 if (!mi_dup)
212 goto free_mi;
213
Jiri Olsab2252ae2016-09-22 17:36:46 +0200214 c2c_decode_stats(&stats, mi);
215
216 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsa78b27542016-09-22 17:36:44 +0200217 &al, NULL, NULL, mi,
218 sample, true);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200219 if (he == NULL)
220 goto free_mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200221
Jiri Olsab2252ae2016-09-22 17:36:46 +0200222 c2c_he = container_of(he, struct c2c_hist_entry, he);
223 c2c_add_stats(&c2c_he->stats, &stats);
224 c2c_add_stats(&c2c_hists->stats, &stats);
225
Jiri Olsa1e181b92016-06-03 15:40:28 +0200226 c2c_he__set_cpu(c2c_he, sample);
227
Jiri Olsab2252ae2016-09-22 17:36:46 +0200228 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsa78b27542016-09-22 17:36:44 +0200229 ret = hist_entry__append_callchain(he, sample);
230
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200231 if (!ret) {
Jiri Olsa1e181b92016-06-03 15:40:28 +0200232 /*
233 * There's already been warning about missing
234 * sample's cpu value. Let's account all to
235 * node 0 in this case, without any further
236 * warning.
237 *
238 * Doing node stats only for single callchain data.
239 */
240 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
241 int node = c2c.cpu2node[cpu];
242
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200243 mi = mi_dup;
244
245 mi_dup = memdup(mi, sizeof(*mi));
246 if (!mi_dup)
247 goto free_mi;
248
Jiri Olsafc9c6302016-05-24 14:14:38 +0200249 c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200250 if (!c2c_hists)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200251 goto free_mi_dup;
252
Jiri Olsab2252ae2016-09-22 17:36:46 +0200253 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200254 &al, NULL, NULL, mi,
255 sample, true);
256 if (he == NULL)
257 goto free_mi_dup;
258
Jiri Olsab2252ae2016-09-22 17:36:46 +0200259 c2c_he = container_of(he, struct c2c_hist_entry, he);
260 c2c_add_stats(&c2c_he->stats, &stats);
261 c2c_add_stats(&c2c_hists->stats, &stats);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200262 c2c_add_stats(&c2c_he->node_stats[node], &stats);
263
Jiri Olsa92062d52016-06-05 13:40:53 +0200264 compute_stats(c2c_he, &stats, sample->weight);
265
Jiri Olsa1e181b92016-06-03 15:40:28 +0200266 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200267
268 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200269 ret = hist_entry__append_callchain(he, sample);
270 }
271
272out:
Jiri Olsa78b27542016-09-22 17:36:44 +0200273 addr_location__put(&al);
274 return ret;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200275
276free_mi_dup:
277 free(mi_dup);
278free_mi:
279 free(mi);
280 ret = -ENOMEM;
281 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200282}
283
284static struct perf_c2c c2c = {
285 .tool = {
286 .sample = process_sample_event,
287 .mmap = perf_event__process_mmap,
288 .mmap2 = perf_event__process_mmap2,
289 .comm = perf_event__process_comm,
290 .exit = perf_event__process_exit,
291 .fork = perf_event__process_fork,
292 .lost = perf_event__process_lost,
293 .ordered_events = true,
294 .ordering_requires_timestamps = true,
295 },
296};
297
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200298static const char * const c2c_usage[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +0200299 "perf c2c {record|report}",
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200300 NULL
301};
302
Jiri Olsa903a6f12016-09-22 17:36:40 +0200303static const char * const __usage_report[] = {
304 "perf c2c report",
305 NULL
306};
307
308static const char * const *report_c2c_usage = __usage_report;
309
Jiri Olsac75540e2016-09-22 17:36:41 +0200310#define C2C_HEADER_MAX 2
311
312struct c2c_header {
313 struct {
314 const char *text;
315 int span;
316 } line[C2C_HEADER_MAX];
317};
318
319struct c2c_dimension {
320 struct c2c_header header;
321 const char *name;
322 int width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200323 struct sort_entry *se;
Jiri Olsac75540e2016-09-22 17:36:41 +0200324
325 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
326 struct hist_entry *, struct hist_entry *);
327 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
328 struct hist_entry *he);
329 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
330 struct hist_entry *he);
331};
332
333struct c2c_fmt {
334 struct perf_hpp_fmt fmt;
335 struct c2c_dimension *dim;
336};
337
338static int c2c_width(struct perf_hpp_fmt *fmt,
339 struct perf_hpp *hpp __maybe_unused,
340 struct hists *hists __maybe_unused)
341{
342 struct c2c_fmt *c2c_fmt;
Jiri Olsac75540e2016-09-22 17:36:41 +0200343 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +0200344
345 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
346 dim = c2c_fmt->dim;
347
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200348 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
349 c2c_fmt->dim->width;
350}
351
352static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
353 struct hists *hists, int line, int *span)
354{
355 struct perf_hpp_list *hpp_list = hists->hpp_list;
356 struct c2c_fmt *c2c_fmt;
357 struct c2c_dimension *dim;
358 const char *text = NULL;
359 int width = c2c_width(fmt, hpp, hists);
360
361 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
362 dim = c2c_fmt->dim;
363
364 if (dim->se) {
365 text = dim->header.line[line].text;
366 /* Use the last line from sort_entry if not defined. */
367 if (!text && (line == hpp_list->nr_header_lines - 1))
368 text = dim->se->se_header;
369 } else {
370 text = dim->header.line[line].text;
371
372 if (*span) {
373 (*span)--;
374 return 0;
375 } else {
376 *span = dim->header.line[line].span;
377 }
378 }
379
Jiri Olsac75540e2016-09-22 17:36:41 +0200380 if (text == NULL)
381 text = "";
382
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200383 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
Jiri Olsac75540e2016-09-22 17:36:41 +0200384}
385
Jiri Olsacbb88502016-09-22 17:36:48 +0200386#define HEX_STR(__s, __v) \
387({ \
388 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
389 __s; \
390})
391
392static int64_t
393dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
394 struct hist_entry *left, struct hist_entry *right)
395{
396 return sort__dcacheline_cmp(left, right);
397}
398
399static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
400 struct hist_entry *he)
401{
402 uint64_t addr = 0;
403 int width = c2c_width(fmt, hpp, he->hists);
404 char buf[20];
405
406 if (he->mem_info)
407 addr = cl_address(he->mem_info->daddr.addr);
408
409 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
410}
411
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200412static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
413 struct hist_entry *he)
414{
415 uint64_t addr = 0;
416 int width = c2c_width(fmt, hpp, he->hists);
417 char buf[20];
418
419 if (he->mem_info)
420 addr = cl_offset(he->mem_info->daddr.al_addr);
421
422 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
423}
424
425static int64_t
426offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
427 struct hist_entry *left, struct hist_entry *right)
428{
429 uint64_t l = 0, r = 0;
430
431 if (left->mem_info)
432 l = cl_offset(left->mem_info->daddr.addr);
433 if (right->mem_info)
434 r = cl_offset(right->mem_info->daddr.addr);
435
436 return (int64_t)(r - l);
437}
438
Jiri Olsa43575a92016-05-03 21:48:56 +0200439static int
440iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
441 struct hist_entry *he)
442{
443 uint64_t addr = 0;
444 int width = c2c_width(fmt, hpp, he->hists);
445 char buf[20];
446
447 if (he->mem_info)
448 addr = he->mem_info->iaddr.addr;
449
450 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
451}
452
453static int64_t
454iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
455 struct hist_entry *left, struct hist_entry *right)
456{
457 return sort__iaddr_cmp(left, right);
458}
459
Jiri Olsa97cb4862016-05-23 16:20:14 +0200460static int
461tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
462 struct hist_entry *he)
463{
464 struct c2c_hist_entry *c2c_he;
465 int width = c2c_width(fmt, hpp, he->hists);
466 unsigned int tot_hitm;
467
468 c2c_he = container_of(he, struct c2c_hist_entry, he);
469 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
470
471 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
472}
473
474static int64_t
475tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
476 struct hist_entry *left, struct hist_entry *right)
477{
478 struct c2c_hist_entry *c2c_left;
479 struct c2c_hist_entry *c2c_right;
480 unsigned int tot_hitm_left;
481 unsigned int tot_hitm_right;
482
483 c2c_left = container_of(left, struct c2c_hist_entry, he);
484 c2c_right = container_of(right, struct c2c_hist_entry, he);
485
486 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
487 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
488
489 return tot_hitm_left - tot_hitm_right;
490}
491
492#define STAT_FN_ENTRY(__f) \
493static int \
494__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
495 struct hist_entry *he) \
496{ \
497 struct c2c_hist_entry *c2c_he; \
498 int width = c2c_width(fmt, hpp, he->hists); \
499 \
500 c2c_he = container_of(he, struct c2c_hist_entry, he); \
501 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
502 c2c_he->stats.__f); \
503}
504
505#define STAT_FN_CMP(__f) \
506static int64_t \
507__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
508 struct hist_entry *left, struct hist_entry *right) \
509{ \
510 struct c2c_hist_entry *c2c_left, *c2c_right; \
511 \
512 c2c_left = container_of(left, struct c2c_hist_entry, he); \
513 c2c_right = container_of(right, struct c2c_hist_entry, he); \
514 return c2c_left->stats.__f - c2c_right->stats.__f; \
515}
516
517#define STAT_FN(__f) \
518 STAT_FN_ENTRY(__f) \
519 STAT_FN_CMP(__f)
520
521STAT_FN(rmt_hitm)
522STAT_FN(lcl_hitm)
Jiri Olsa0f188962016-05-04 10:10:11 +0200523STAT_FN(store)
524STAT_FN(st_l1hit)
525STAT_FN(st_l1miss)
Jiri Olsa1295f682016-05-04 10:18:24 +0200526STAT_FN(ld_fbhit)
527STAT_FN(ld_l1hit)
528STAT_FN(ld_l2hit)
Jiri Olsa4d089102016-05-04 10:27:51 +0200529STAT_FN(ld_llchit)
530STAT_FN(rmt_hit)
Jiri Olsa97cb4862016-05-23 16:20:14 +0200531
Jiri Olsa04402d22016-05-19 10:10:51 +0200532static uint64_t llc_miss(struct c2c_stats *stats)
533{
534 uint64_t llcmiss;
535
536 llcmiss = stats->lcl_dram +
537 stats->rmt_dram +
538 stats->rmt_hitm +
539 stats->rmt_hit;
540
541 return llcmiss;
542}
543
544static int
545ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
546 struct hist_entry *he)
547{
548 struct c2c_hist_entry *c2c_he;
549 int width = c2c_width(fmt, hpp, he->hists);
550
551 c2c_he = container_of(he, struct c2c_hist_entry, he);
552
553 return scnprintf(hpp->buf, hpp->size, "%*lu", width,
554 llc_miss(&c2c_he->stats));
555}
556
557static int64_t
558ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
559 struct hist_entry *left, struct hist_entry *right)
560{
561 struct c2c_hist_entry *c2c_left;
562 struct c2c_hist_entry *c2c_right;
563
564 c2c_left = container_of(left, struct c2c_hist_entry, he);
565 c2c_right = container_of(right, struct c2c_hist_entry, he);
566
567 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
568}
569
Jiri Olsa01b84d72016-05-04 10:35:29 +0200570static uint64_t total_records(struct c2c_stats *stats)
571{
572 uint64_t lclmiss, ldcnt, total;
573
574 lclmiss = stats->lcl_dram +
575 stats->rmt_dram +
576 stats->rmt_hitm +
577 stats->rmt_hit;
578
579 ldcnt = lclmiss +
580 stats->ld_fbhit +
581 stats->ld_l1hit +
582 stats->ld_l2hit +
583 stats->ld_llchit +
584 stats->lcl_hitm;
585
586 total = ldcnt +
587 stats->st_l1hit +
588 stats->st_l1miss;
589
590 return total;
591}
592
593static int
594tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
595 struct hist_entry *he)
596{
597 struct c2c_hist_entry *c2c_he;
598 int width = c2c_width(fmt, hpp, he->hists);
599 uint64_t tot_recs;
600
601 c2c_he = container_of(he, struct c2c_hist_entry, he);
602 tot_recs = total_records(&c2c_he->stats);
603
604 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
605}
606
607static int64_t
608tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
609 struct hist_entry *left, struct hist_entry *right)
610{
611 struct c2c_hist_entry *c2c_left;
612 struct c2c_hist_entry *c2c_right;
613 uint64_t tot_recs_left;
614 uint64_t tot_recs_right;
615
616 c2c_left = container_of(left, struct c2c_hist_entry, he);
617 c2c_right = container_of(right, struct c2c_hist_entry, he);
618
619 tot_recs_left = total_records(&c2c_left->stats);
620 tot_recs_right = total_records(&c2c_right->stats);
621
622 return tot_recs_left - tot_recs_right;
623}
624
Jiri Olsa55177c42016-05-19 09:52:37 +0200625static uint64_t total_loads(struct c2c_stats *stats)
626{
627 uint64_t lclmiss, ldcnt;
628
629 lclmiss = stats->lcl_dram +
630 stats->rmt_dram +
631 stats->rmt_hitm +
632 stats->rmt_hit;
633
634 ldcnt = lclmiss +
635 stats->ld_fbhit +
636 stats->ld_l1hit +
637 stats->ld_l2hit +
638 stats->ld_llchit +
639 stats->lcl_hitm;
640
641 return ldcnt;
642}
643
644static int
645tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
646 struct hist_entry *he)
647{
648 struct c2c_hist_entry *c2c_he;
649 int width = c2c_width(fmt, hpp, he->hists);
650 uint64_t tot_recs;
651
652 c2c_he = container_of(he, struct c2c_hist_entry, he);
653 tot_recs = total_loads(&c2c_he->stats);
654
655 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
656}
657
658static int64_t
659tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
660 struct hist_entry *left, struct hist_entry *right)
661{
662 struct c2c_hist_entry *c2c_left;
663 struct c2c_hist_entry *c2c_right;
664 uint64_t tot_recs_left;
665 uint64_t tot_recs_right;
666
667 c2c_left = container_of(left, struct c2c_hist_entry, he);
668 c2c_right = container_of(right, struct c2c_hist_entry, he);
669
670 tot_recs_left = total_loads(&c2c_left->stats);
671 tot_recs_right = total_loads(&c2c_right->stats);
672
673 return tot_recs_left - tot_recs_right;
674}
675
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200676typedef double (get_percent_cb)(struct c2c_hist_entry *);
677
678static int
679percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
680 struct hist_entry *he, get_percent_cb get_percent)
681{
682 struct c2c_hist_entry *c2c_he;
683 int width = c2c_width(fmt, hpp, he->hists);
684 double per;
685
686 c2c_he = container_of(he, struct c2c_hist_entry, he);
687 per = get_percent(c2c_he);
688
Jiri Olsa5a1a99c2016-01-06 16:59:02 +0100689#ifdef HAVE_SLANG_SUPPORT
690 if (use_browser)
691 return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
692#endif
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200693 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
694}
695
696static double percent_hitm(struct c2c_hist_entry *c2c_he)
697{
698 struct c2c_hists *hists;
699 struct c2c_stats *stats;
700 struct c2c_stats *total;
Jiri Olsa55b95772016-05-29 10:21:45 +0200701 int tot = 0, st = 0;
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200702 double p;
703
704 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
705 stats = &c2c_he->stats;
706 total = &hists->stats;
707
Jiri Olsa55b95772016-05-29 10:21:45 +0200708 switch (c2c.display) {
709 case DISPLAY_RMT:
710 st = stats->rmt_hitm;
711 tot = total->rmt_hitm;
712 break;
713 case DISPLAY_LCL:
714 st = stats->lcl_hitm;
715 tot = total->lcl_hitm;
716 default:
717 break;
718 }
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200719
720 p = tot ? (double) st / tot : 0;
721
722 return 100 * p;
723}
724
725#define PERC_STR(__s, __v) \
726({ \
727 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
728 __s; \
729})
730
731static int
732percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
733 struct hist_entry *he)
734{
735 struct c2c_hist_entry *c2c_he;
736 int width = c2c_width(fmt, hpp, he->hists);
737 char buf[10];
738 double per;
739
740 c2c_he = container_of(he, struct c2c_hist_entry, he);
741 per = percent_hitm(c2c_he);
742 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
743}
744
745static int
746percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
747 struct hist_entry *he)
748{
749 return percent_color(fmt, hpp, he, percent_hitm);
750}
751
752static int64_t
753percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
754 struct hist_entry *left, struct hist_entry *right)
755{
756 struct c2c_hist_entry *c2c_left;
757 struct c2c_hist_entry *c2c_right;
758 double per_left;
759 double per_right;
760
761 c2c_left = container_of(left, struct c2c_hist_entry, he);
762 c2c_right = container_of(right, struct c2c_hist_entry, he);
763
764 per_left = percent_hitm(c2c_left);
765 per_right = percent_hitm(c2c_right);
766
767 return per_left - per_right;
768}
769
Jiri Olsa9cb35002016-05-04 12:16:50 +0200770static struct c2c_stats *he_stats(struct hist_entry *he)
771{
772 struct c2c_hist_entry *c2c_he;
773
774 c2c_he = container_of(he, struct c2c_hist_entry, he);
775 return &c2c_he->stats;
776}
777
778static struct c2c_stats *total_stats(struct hist_entry *he)
779{
780 struct c2c_hists *hists;
781
782 hists = container_of(he->hists, struct c2c_hists, hists);
783 return &hists->stats;
784}
785
786static double percent(int st, int tot)
787{
788 return tot ? 100. * (double) st / (double) tot : 0;
789}
790
791#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
792
793#define PERCENT_FN(__f) \
794static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
795{ \
796 struct c2c_hists *hists; \
797 \
798 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
799 return percent(c2c_he->stats.__f, hists->stats.__f); \
800}
801
802PERCENT_FN(rmt_hitm)
803PERCENT_FN(lcl_hitm)
804PERCENT_FN(st_l1hit)
805PERCENT_FN(st_l1miss)
806
807static int
808percent_rmt_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, rmt_hitm);
813 char buf[10];
814
815 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
816}
817
818static int
819percent_rmt_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_rmt_hitm);
823}
824
825static int64_t
826percent_rmt_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_lcl_hitm_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, lcl_hitm);
844 char buf[10];
845
846 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
847}
848
849static int
850percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
851 struct hist_entry *he)
852{
853 return percent_color(fmt, hpp, he, percent_lcl_hitm);
854}
855
856static int64_t
857percent_lcl_hitm_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, lcl_hitm);
864 per_right = PERCENT(right, lcl_hitm);
865
866 return per_left - per_right;
867}
868
869static int
870percent_stores_l1hit_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_l1hit);
875 char buf[10];
876
877 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
878}
879
880static int
881percent_stores_l1hit_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_l1hit);
885}
886
887static int64_t
888percent_stores_l1hit_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_l1hit);
895 per_right = PERCENT(right, st_l1hit);
896
897 return per_left - per_right;
898}
899
900static int
901percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
902 struct hist_entry *he)
903{
904 int width = c2c_width(fmt, hpp, he->hists);
905 double per = PERCENT(he, st_l1miss);
906 char buf[10];
907
908 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
909}
910
911static int
912percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
913 struct hist_entry *he)
914{
915 return percent_color(fmt, hpp, he, percent_st_l1miss);
916}
917
918static int64_t
919percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
920 struct hist_entry *left, struct hist_entry *right)
921{
922 double per_left;
923 double per_right;
924
925 per_left = PERCENT(left, st_l1miss);
926 per_right = PERCENT(right, st_l1miss);
927
928 return per_left - per_right;
929}
930
Jiri Olsa6c70f542016-05-28 12:30:13 +0200931STAT_FN(lcl_dram)
932STAT_FN(rmt_dram)
933
Jiri Olsa36d3deb2016-05-24 13:09:47 +0200934static int
935pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
936 struct hist_entry *he)
937{
938 int width = c2c_width(fmt, hpp, he->hists);
939
940 return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
941}
942
943static int64_t
944pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
945 struct hist_entry *left, struct hist_entry *right)
946{
947 return left->thread->pid_ - right->thread->pid_;
948}
949
Jiri Olsa1e181b92016-06-03 15:40:28 +0200950static int64_t
951empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
952 struct hist_entry *left __maybe_unused,
953 struct hist_entry *right __maybe_unused)
954{
955 return 0;
956}
957
958static int
959node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
960 struct hist_entry *he)
961{
962 struct c2c_hist_entry *c2c_he;
963 bool first = true;
964 int node;
965 int ret = 0;
966
967 c2c_he = container_of(he, struct c2c_hist_entry, he);
968
969 for (node = 0; node < c2c.nodes_cnt; node++) {
970 DECLARE_BITMAP(set, c2c.cpus_cnt);
971
972 bitmap_zero(set, c2c.cpus_cnt);
973 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
974
975 if (!bitmap_weight(set, c2c.cpus_cnt)) {
976 if (c2c.node_info == 1) {
977 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
978 advance_hpp(hpp, ret);
979 }
980 continue;
981 }
982
983 if (!first) {
984 ret = scnprintf(hpp->buf, hpp->size, " ");
985 advance_hpp(hpp, ret);
986 }
987
988 switch (c2c.node_info) {
989 case 0:
990 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
991 advance_hpp(hpp, ret);
992 break;
993 case 1:
994 {
995 int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
996 struct c2c_stats *stats = &c2c_he->node_stats[node];
997
998 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
999 advance_hpp(hpp, ret);
1000
Jiri Olsa55b95772016-05-29 10:21:45 +02001001 #define DISPLAY_HITM(__h) \
1002 if (c2c_he->stats.__h> 0) { \
1003 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", \
1004 percent(stats->__h, c2c_he->stats.__h));\
1005 } else { \
1006 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); \
Jiri Olsa1e181b92016-06-03 15:40:28 +02001007 }
1008
Jiri Olsa55b95772016-05-29 10:21:45 +02001009 switch (c2c.display) {
1010 case DISPLAY_RMT:
1011 DISPLAY_HITM(rmt_hitm);
1012 break;
1013 case DISPLAY_LCL:
1014 DISPLAY_HITM(lcl_hitm);
1015 default:
1016 break;
1017 }
1018
1019 #undef DISPLAY_HITM
1020
Jiri Olsa1e181b92016-06-03 15:40:28 +02001021 advance_hpp(hpp, ret);
1022
1023 if (c2c_he->stats.store > 0) {
1024 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
1025 percent(stats->store, c2c_he->stats.store));
1026 } else {
1027 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
1028 }
1029
1030 advance_hpp(hpp, ret);
1031 break;
1032 }
1033 case 2:
1034 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
1035 advance_hpp(hpp, ret);
1036
1037 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
1038 advance_hpp(hpp, ret);
1039
1040 ret = scnprintf(hpp->buf, hpp->size, "}");
1041 advance_hpp(hpp, ret);
1042 break;
1043 default:
1044 break;
1045 }
1046
1047 first = false;
1048 }
1049
1050 return 0;
1051}
1052
Jiri Olsa92062d52016-06-05 13:40:53 +02001053static int
1054mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1055 struct hist_entry *he, double mean)
1056{
1057 int width = c2c_width(fmt, hpp, he->hists);
1058 char buf[10];
1059
1060 scnprintf(buf, 10, "%6.0f", mean);
1061 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1062}
1063
1064#define MEAN_ENTRY(__func, __val) \
1065static int \
1066__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1067{ \
1068 struct c2c_hist_entry *c2c_he; \
1069 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1070 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1071}
1072
1073MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1074MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1075MEAN_ENTRY(mean_load_entry, load);
1076
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001077static int
1078cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1079 struct hist_entry *he)
1080{
1081 struct c2c_hist_entry *c2c_he;
1082 int width = c2c_width(fmt, hpp, he->hists);
1083 char buf[10];
1084
1085 c2c_he = container_of(he, struct c2c_hist_entry, he);
1086
1087 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1088 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1089}
1090
Jiri Olsa600a8cf2016-09-22 17:36:47 +02001091#define HEADER_LOW(__h) \
1092 { \
1093 .line[1] = { \
1094 .text = __h, \
1095 }, \
1096 }
1097
1098#define HEADER_BOTH(__h0, __h1) \
1099 { \
1100 .line[0] = { \
1101 .text = __h0, \
1102 }, \
1103 .line[1] = { \
1104 .text = __h1, \
1105 }, \
1106 }
1107
1108#define HEADER_SPAN(__h0, __h1, __s) \
1109 { \
1110 .line[0] = { \
1111 .text = __h0, \
1112 .span = __s, \
1113 }, \
1114 .line[1] = { \
1115 .text = __h1, \
1116 }, \
1117 }
1118
1119#define HEADER_SPAN_LOW(__h) \
1120 { \
1121 .line[1] = { \
1122 .text = __h, \
1123 }, \
1124 }
1125
Jiri Olsacbb88502016-09-22 17:36:48 +02001126static struct c2c_dimension dim_dcacheline = {
1127 .header = HEADER_LOW("Cacheline"),
1128 .name = "dcacheline",
1129 .cmp = dcacheline_cmp,
1130 .entry = dcacheline_entry,
1131 .width = 18,
1132};
1133
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001134static struct c2c_header header_offset_tui = HEADER_LOW("Off");
1135
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001136static struct c2c_dimension dim_offset = {
1137 .header = HEADER_BOTH("Data address", "Offset"),
1138 .name = "offset",
1139 .cmp = offset_cmp,
1140 .entry = offset_entry,
1141 .width = 18,
1142};
1143
Jiri Olsa43575a92016-05-03 21:48:56 +02001144static struct c2c_dimension dim_iaddr = {
1145 .header = HEADER_LOW("Code address"),
1146 .name = "iaddr",
1147 .cmp = iaddr_cmp,
1148 .entry = iaddr_entry,
1149 .width = 18,
1150};
1151
Jiri Olsa97cb4862016-05-23 16:20:14 +02001152static struct c2c_dimension dim_tot_hitm = {
1153 .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1154 .name = "tot_hitm",
1155 .cmp = tot_hitm_cmp,
1156 .entry = tot_hitm_entry,
1157 .width = 7,
1158};
1159
1160static struct c2c_dimension dim_lcl_hitm = {
1161 .header = HEADER_SPAN_LOW("Lcl"),
1162 .name = "lcl_hitm",
1163 .cmp = lcl_hitm_cmp,
1164 .entry = lcl_hitm_entry,
1165 .width = 7,
1166};
1167
1168static struct c2c_dimension dim_rmt_hitm = {
1169 .header = HEADER_SPAN_LOW("Rmt"),
1170 .name = "rmt_hitm",
1171 .cmp = rmt_hitm_cmp,
1172 .entry = rmt_hitm_entry,
1173 .width = 7,
1174};
1175
1176static struct c2c_dimension dim_cl_rmt_hitm = {
1177 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1178 .name = "cl_rmt_hitm",
1179 .cmp = rmt_hitm_cmp,
1180 .entry = rmt_hitm_entry,
1181 .width = 7,
1182};
1183
1184static struct c2c_dimension dim_cl_lcl_hitm = {
1185 .header = HEADER_SPAN_LOW("Lcl"),
1186 .name = "cl_lcl_hitm",
1187 .cmp = lcl_hitm_cmp,
1188 .entry = lcl_hitm_entry,
1189 .width = 7,
1190};
1191
Jiri Olsa0f188962016-05-04 10:10:11 +02001192static struct c2c_dimension dim_stores = {
1193 .header = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1194 .name = "stores",
1195 .cmp = store_cmp,
1196 .entry = store_entry,
1197 .width = 7,
1198};
1199
1200static struct c2c_dimension dim_stores_l1hit = {
1201 .header = HEADER_SPAN_LOW("L1Hit"),
1202 .name = "stores_l1hit",
1203 .cmp = st_l1hit_cmp,
1204 .entry = st_l1hit_entry,
1205 .width = 7,
1206};
1207
1208static struct c2c_dimension dim_stores_l1miss = {
1209 .header = HEADER_SPAN_LOW("L1Miss"),
1210 .name = "stores_l1miss",
1211 .cmp = st_l1miss_cmp,
1212 .entry = st_l1miss_entry,
1213 .width = 7,
1214};
1215
1216static struct c2c_dimension dim_cl_stores_l1hit = {
1217 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1218 .name = "cl_stores_l1hit",
1219 .cmp = st_l1hit_cmp,
1220 .entry = st_l1hit_entry,
1221 .width = 7,
1222};
1223
1224static struct c2c_dimension dim_cl_stores_l1miss = {
1225 .header = HEADER_SPAN_LOW("L1 Miss"),
1226 .name = "cl_stores_l1miss",
1227 .cmp = st_l1miss_cmp,
1228 .entry = st_l1miss_entry,
1229 .width = 7,
1230};
1231
Jiri Olsa1295f682016-05-04 10:18:24 +02001232static struct c2c_dimension dim_ld_fbhit = {
1233 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1234 .name = "ld_fbhit",
1235 .cmp = ld_fbhit_cmp,
1236 .entry = ld_fbhit_entry,
1237 .width = 7,
1238};
1239
1240static struct c2c_dimension dim_ld_l1hit = {
1241 .header = HEADER_SPAN_LOW("L1"),
1242 .name = "ld_l1hit",
1243 .cmp = ld_l1hit_cmp,
1244 .entry = ld_l1hit_entry,
1245 .width = 7,
1246};
1247
1248static struct c2c_dimension dim_ld_l2hit = {
1249 .header = HEADER_SPAN_LOW("L2"),
1250 .name = "ld_l2hit",
1251 .cmp = ld_l2hit_cmp,
1252 .entry = ld_l2hit_entry,
1253 .width = 7,
1254};
1255
Jiri Olsa4d089102016-05-04 10:27:51 +02001256static struct c2c_dimension dim_ld_llchit = {
1257 .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1258 .name = "ld_lclhit",
1259 .cmp = ld_llchit_cmp,
1260 .entry = ld_llchit_entry,
1261 .width = 8,
1262};
1263
1264static struct c2c_dimension dim_ld_rmthit = {
1265 .header = HEADER_SPAN_LOW("Rmt"),
1266 .name = "ld_rmthit",
1267 .cmp = rmt_hit_cmp,
1268 .entry = rmt_hit_entry,
1269 .width = 8,
1270};
1271
Jiri Olsa04402d22016-05-19 10:10:51 +02001272static struct c2c_dimension dim_ld_llcmiss = {
1273 .header = HEADER_BOTH("LLC", "Ld Miss"),
1274 .name = "ld_llcmiss",
1275 .cmp = ld_llcmiss_cmp,
1276 .entry = ld_llcmiss_entry,
1277 .width = 7,
1278};
1279
Jiri Olsa01b84d72016-05-04 10:35:29 +02001280static struct c2c_dimension dim_tot_recs = {
1281 .header = HEADER_BOTH("Total", "records"),
1282 .name = "tot_recs",
1283 .cmp = tot_recs_cmp,
1284 .entry = tot_recs_entry,
1285 .width = 7,
1286};
1287
Jiri Olsa55177c42016-05-19 09:52:37 +02001288static struct c2c_dimension dim_tot_loads = {
1289 .header = HEADER_BOTH("Total", "Loads"),
1290 .name = "tot_loads",
1291 .cmp = tot_loads_cmp,
1292 .entry = tot_loads_entry,
1293 .width = 7,
1294};
1295
Jiri Olsa55b95772016-05-29 10:21:45 +02001296static struct c2c_header percent_hitm_header[] = {
1297 [DISPLAY_LCL] = HEADER_BOTH("Lcl", "Hitm"),
1298 [DISPLAY_RMT] = HEADER_BOTH("Rmt", "Hitm"),
1299};
1300
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001301static struct c2c_dimension dim_percent_hitm = {
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001302 .name = "percent_hitm",
1303 .cmp = percent_hitm_cmp,
1304 .entry = percent_hitm_entry,
1305 .color = percent_hitm_color,
1306 .width = 7,
1307};
1308
Jiri Olsa9cb35002016-05-04 12:16:50 +02001309static struct c2c_dimension dim_percent_rmt_hitm = {
1310 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1311 .name = "percent_rmt_hitm",
1312 .cmp = percent_rmt_hitm_cmp,
1313 .entry = percent_rmt_hitm_entry,
1314 .color = percent_rmt_hitm_color,
1315 .width = 7,
1316};
1317
1318static struct c2c_dimension dim_percent_lcl_hitm = {
1319 .header = HEADER_SPAN_LOW("Lcl"),
1320 .name = "percent_lcl_hitm",
1321 .cmp = percent_lcl_hitm_cmp,
1322 .entry = percent_lcl_hitm_entry,
1323 .color = percent_lcl_hitm_color,
1324 .width = 7,
1325};
1326
1327static struct c2c_dimension dim_percent_stores_l1hit = {
1328 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1329 .name = "percent_stores_l1hit",
1330 .cmp = percent_stores_l1hit_cmp,
1331 .entry = percent_stores_l1hit_entry,
1332 .color = percent_stores_l1hit_color,
1333 .width = 7,
1334};
1335
1336static struct c2c_dimension dim_percent_stores_l1miss = {
1337 .header = HEADER_SPAN_LOW("L1 Miss"),
1338 .name = "percent_stores_l1miss",
1339 .cmp = percent_stores_l1miss_cmp,
1340 .entry = percent_stores_l1miss_entry,
1341 .color = percent_stores_l1miss_color,
1342 .width = 7,
1343};
1344
Jiri Olsa6c70f542016-05-28 12:30:13 +02001345static struct c2c_dimension dim_dram_lcl = {
1346 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1347 .name = "dram_lcl",
1348 .cmp = lcl_dram_cmp,
1349 .entry = lcl_dram_entry,
1350 .width = 8,
1351};
1352
1353static struct c2c_dimension dim_dram_rmt = {
1354 .header = HEADER_SPAN_LOW("Rmt"),
1355 .name = "dram_rmt",
1356 .cmp = rmt_dram_cmp,
1357 .entry = rmt_dram_entry,
1358 .width = 8,
1359};
1360
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001361static struct c2c_dimension dim_pid = {
1362 .header = HEADER_LOW("Pid"),
1363 .name = "pid",
1364 .cmp = pid_cmp,
1365 .entry = pid_entry,
1366 .width = 7,
1367};
1368
Jiri Olsae87019c2016-05-25 08:50:10 +02001369static struct c2c_dimension dim_tid = {
1370 .header = HEADER_LOW("Tid"),
1371 .name = "tid",
1372 .se = &sort_thread,
1373};
1374
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001375static struct c2c_dimension dim_symbol = {
1376 .name = "symbol",
1377 .se = &sort_sym,
1378};
1379
1380static struct c2c_dimension dim_dso = {
1381 .header = HEADER_BOTH("Shared", "Object"),
1382 .name = "dso",
1383 .se = &sort_dso,
1384};
1385
Jiri Olsa1e181b92016-06-03 15:40:28 +02001386static struct c2c_header header_node[3] = {
1387 HEADER_LOW("Node"),
1388 HEADER_LOW("Node{cpus %hitms %stores}"),
1389 HEADER_LOW("Node{cpu list}"),
1390};
1391
1392static struct c2c_dimension dim_node = {
1393 .name = "node",
1394 .cmp = empty_cmp,
1395 .entry = node_entry,
1396 .width = 4,
1397};
1398
Jiri Olsa92062d52016-06-05 13:40:53 +02001399static struct c2c_dimension dim_mean_rmt = {
1400 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1401 .name = "mean_rmt",
1402 .cmp = empty_cmp,
1403 .entry = mean_rmt_entry,
1404 .width = 8,
1405};
1406
1407static struct c2c_dimension dim_mean_lcl = {
1408 .header = HEADER_SPAN_LOW("lcl hitm"),
1409 .name = "mean_lcl",
1410 .cmp = empty_cmp,
1411 .entry = mean_lcl_entry,
1412 .width = 8,
1413};
1414
1415static struct c2c_dimension dim_mean_load = {
1416 .header = HEADER_SPAN_LOW("load"),
1417 .name = "mean_load",
1418 .cmp = empty_cmp,
1419 .entry = mean_load_entry,
1420 .width = 8,
1421};
1422
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001423static struct c2c_dimension dim_cpucnt = {
1424 .header = HEADER_BOTH("cpu", "cnt"),
1425 .name = "cpucnt",
1426 .cmp = empty_cmp,
1427 .entry = cpucnt_entry,
1428 .width = 8,
1429};
1430
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001431static struct c2c_dimension dim_srcline = {
1432 .name = "cl_srcline",
1433 .se = &sort_srcline,
1434};
1435
Jiri Olsac75540e2016-09-22 17:36:41 +02001436static struct c2c_dimension *dimensions[] = {
Jiri Olsacbb88502016-09-22 17:36:48 +02001437 &dim_dcacheline,
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001438 &dim_offset,
Jiri Olsa43575a92016-05-03 21:48:56 +02001439 &dim_iaddr,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001440 &dim_tot_hitm,
1441 &dim_lcl_hitm,
1442 &dim_rmt_hitm,
1443 &dim_cl_lcl_hitm,
1444 &dim_cl_rmt_hitm,
Jiri Olsa0f188962016-05-04 10:10:11 +02001445 &dim_stores,
1446 &dim_stores_l1hit,
1447 &dim_stores_l1miss,
1448 &dim_cl_stores_l1hit,
1449 &dim_cl_stores_l1miss,
Jiri Olsa1295f682016-05-04 10:18:24 +02001450 &dim_ld_fbhit,
1451 &dim_ld_l1hit,
1452 &dim_ld_l2hit,
Jiri Olsa4d089102016-05-04 10:27:51 +02001453 &dim_ld_llchit,
1454 &dim_ld_rmthit,
Jiri Olsa04402d22016-05-19 10:10:51 +02001455 &dim_ld_llcmiss,
Jiri Olsa01b84d72016-05-04 10:35:29 +02001456 &dim_tot_recs,
Jiri Olsa55177c42016-05-19 09:52:37 +02001457 &dim_tot_loads,
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001458 &dim_percent_hitm,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001459 &dim_percent_rmt_hitm,
1460 &dim_percent_lcl_hitm,
1461 &dim_percent_stores_l1hit,
1462 &dim_percent_stores_l1miss,
Jiri Olsa6c70f542016-05-28 12:30:13 +02001463 &dim_dram_lcl,
1464 &dim_dram_rmt,
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001465 &dim_pid,
Jiri Olsae87019c2016-05-25 08:50:10 +02001466 &dim_tid,
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001467 &dim_symbol,
1468 &dim_dso,
Jiri Olsa1e181b92016-06-03 15:40:28 +02001469 &dim_node,
Jiri Olsa92062d52016-06-05 13:40:53 +02001470 &dim_mean_rmt,
1471 &dim_mean_lcl,
1472 &dim_mean_load,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001473 &dim_cpucnt,
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001474 &dim_srcline,
Jiri Olsac75540e2016-09-22 17:36:41 +02001475 NULL,
1476};
1477
1478static void fmt_free(struct perf_hpp_fmt *fmt)
1479{
1480 struct c2c_fmt *c2c_fmt;
1481
1482 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1483 free(c2c_fmt);
1484}
1485
1486static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1487{
1488 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1489 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1490
1491 return c2c_a->dim == c2c_b->dim;
1492}
1493
1494static struct c2c_dimension *get_dimension(const char *name)
1495{
1496 unsigned int i;
1497
1498 for (i = 0; dimensions[i]; i++) {
1499 struct c2c_dimension *dim = dimensions[i];
1500
1501 if (!strcmp(dim->name, name))
1502 return dim;
1503 };
1504
1505 return NULL;
1506}
1507
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001508static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1509 struct hist_entry *he)
1510{
1511 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1512 struct c2c_dimension *dim = c2c_fmt->dim;
1513 size_t len = fmt->user_len;
1514
1515 if (!len)
1516 len = hists__col_len(he->hists, dim->se->se_width_idx);
1517
1518 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1519}
1520
1521static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1522 struct hist_entry *a, struct hist_entry *b)
1523{
1524 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1525 struct c2c_dimension *dim = c2c_fmt->dim;
1526
1527 return dim->se->se_cmp(a, b);
1528}
1529
1530static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1531 struct hist_entry *a, struct hist_entry *b)
1532{
1533 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1534 struct c2c_dimension *dim = c2c_fmt->dim;
1535 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1536
1537 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1538 return collapse_fn(a, b);
1539}
1540
Jiri Olsac75540e2016-09-22 17:36:41 +02001541static struct c2c_fmt *get_format(const char *name)
1542{
1543 struct c2c_dimension *dim = get_dimension(name);
1544 struct c2c_fmt *c2c_fmt;
1545 struct perf_hpp_fmt *fmt;
1546
1547 if (!dim)
1548 return NULL;
1549
1550 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1551 if (!c2c_fmt)
1552 return NULL;
1553
1554 c2c_fmt->dim = dim;
1555
1556 fmt = &c2c_fmt->fmt;
1557 INIT_LIST_HEAD(&fmt->list);
1558 INIT_LIST_HEAD(&fmt->sort_list);
1559
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001560 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1561 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
Jiri Olsa9cb35002016-05-04 12:16:50 +02001562 fmt->color = dim->se ? NULL : dim->color;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001563 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
Jiri Olsac75540e2016-09-22 17:36:41 +02001564 fmt->header = c2c_header;
1565 fmt->width = c2c_width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001566 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
Jiri Olsac75540e2016-09-22 17:36:41 +02001567 fmt->equal = fmt_equal;
1568 fmt->free = fmt_free;
1569
1570 return c2c_fmt;
1571}
1572
1573static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1574{
1575 struct c2c_fmt *c2c_fmt = get_format(name);
1576
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001577 if (!c2c_fmt) {
1578 reset_dimensions();
1579 return output_field_add(hpp_list, name);
1580 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001581
1582 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1583 return 0;
1584}
1585
1586static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1587{
1588 struct c2c_fmt *c2c_fmt = get_format(name);
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001589 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +02001590
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001591 if (!c2c_fmt) {
1592 reset_dimensions();
1593 return sort_dimension__add(hpp_list, name, NULL, 0);
1594 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001595
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001596 dim = c2c_fmt->dim;
1597 if (dim == &dim_dso)
1598 hpp_list->dso = 1;
1599
Jiri Olsac75540e2016-09-22 17:36:41 +02001600 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1601 return 0;
1602}
1603
1604#define PARSE_LIST(_list, _fn) \
1605 do { \
1606 char *tmp, *tok; \
1607 ret = 0; \
1608 \
1609 if (!_list) \
1610 break; \
1611 \
1612 for (tok = strtok_r((char *)_list, ", ", &tmp); \
1613 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
1614 ret = _fn(hpp_list, tok); \
1615 if (ret == -EINVAL) { \
1616 error("Invalid --fields key: `%s'", tok); \
1617 break; \
1618 } else if (ret == -ESRCH) { \
1619 error("Unknown --fields key: `%s'", tok); \
1620 break; \
1621 } \
1622 } \
1623 } while (0)
1624
1625static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1626 const char *output_,
1627 const char *sort_)
1628{
1629 char *output = output_ ? strdup(output_) : NULL;
1630 char *sort = sort_ ? strdup(sort_) : NULL;
1631 int ret;
1632
1633 PARSE_LIST(output, c2c_hists__init_output);
1634 PARSE_LIST(sort, c2c_hists__init_sort);
1635
1636 /* copy sort keys to output fields */
1637 perf_hpp__setup_output_field(hpp_list);
1638
1639 /*
1640 * We dont need other sorting keys other than those
1641 * we already specified. It also really slows down
1642 * the processing a lot with big number of output
1643 * fields, so switching this off for c2c.
1644 */
1645
1646#if 0
1647 /* and then copy output fields to sort keys */
1648 perf_hpp__append_sort_keys(&hists->list);
1649#endif
1650
1651 free(output);
1652 free(sort);
1653 return ret;
1654}
1655
1656static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001657 const char *sort,
1658 int nr_header_lines)
Jiri Olsac75540e2016-09-22 17:36:41 +02001659{
1660 __hists__init(&hists->hists, &hists->list);
1661
1662 /*
1663 * Initialize only with sort fields, we need to resort
1664 * later anyway, and that's where we add output fields
1665 * as well.
1666 */
1667 perf_hpp_list__init(&hists->list);
1668
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001669 /* Overload number of header lines.*/
1670 hists->list.nr_header_lines = nr_header_lines;
1671
Jiri Olsac75540e2016-09-22 17:36:41 +02001672 return hpp_list__parse(&hists->list, NULL, sort);
1673}
1674
1675__maybe_unused
1676static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1677 const char *output,
1678 const char *sort)
1679{
1680 perf_hpp__reset_output_field(&c2c_hists->list);
1681 return hpp_list__parse(&c2c_hists->list, output, sort);
1682}
1683
Jiri Olsa9857b712016-08-17 14:55:23 +02001684#define DISPLAY_LINE_LIMIT 0.0005
1685
1686static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
1687{
1688 struct c2c_hist_entry *c2c_he;
1689 double ld_dist;
1690
1691 /* XXX Disabled for now, till we get a command line switch to control this */
1692 return true;
1693
1694 c2c_he = container_of(he, struct c2c_hist_entry, he);
1695
Jiri Olsa55b95772016-05-29 10:21:45 +02001696#define FILTER_HITM(__h) \
1697 if (stats->__h) { \
1698 ld_dist = ((double)c2c_he->stats.__h / stats->__h); \
1699 if (ld_dist < DISPLAY_LINE_LIMIT) \
1700 he->filtered = HIST_FILTER__C2C; \
1701 } else { \
1702 he->filtered = HIST_FILTER__C2C; \
Jiri Olsa9857b712016-08-17 14:55:23 +02001703 }
1704
Jiri Olsa55b95772016-05-29 10:21:45 +02001705 switch (c2c.display) {
1706 case DISPLAY_LCL:
1707 FILTER_HITM(lcl_hitm);
1708 break;
1709 case DISPLAY_RMT:
1710 FILTER_HITM(rmt_hitm);
1711 default:
1712 break;
1713 };
1714
1715#undef FILTER_HITM
1716
Jiri Olsa9857b712016-08-17 14:55:23 +02001717 return he->filtered == 0;
1718}
1719
1720static inline int valid_hitm_or_store(struct hist_entry *he)
1721{
1722 struct c2c_hist_entry *c2c_he;
Jiri Olsa55b95772016-05-29 10:21:45 +02001723 bool has_hitm;
Jiri Olsa9857b712016-08-17 14:55:23 +02001724
1725 c2c_he = container_of(he, struct c2c_hist_entry, he);
Jiri Olsa55b95772016-05-29 10:21:45 +02001726 has_hitm = c2c.display == DISPLAY_LCL ?
1727 c2c_he->stats.lcl_hitm : c2c_he->stats.rmt_hitm;
1728 return has_hitm || c2c_he->stats.store;
Jiri Olsa9857b712016-08-17 14:55:23 +02001729}
1730
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001731static void calc_width(struct hist_entry *he)
1732{
1733 struct c2c_hists *c2c_hists;
1734
1735 c2c_hists = container_of(he->hists, struct c2c_hists, hists);
1736 hists__calc_col_len(&c2c_hists->hists, he);
1737}
1738
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001739static int filter_cb(struct hist_entry *he)
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001740{
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001741 if (c2c.show_src && !he->srcline)
1742 he->srcline = hist_entry__get_srcline(he);
1743
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001744 calc_width(he);
1745
Jiri Olsa9857b712016-08-17 14:55:23 +02001746 if (!valid_hitm_or_store(he))
1747 he->filtered = HIST_FILTER__C2C;
1748
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001749 return 0;
1750}
1751
1752static int resort_cl_cb(struct hist_entry *he)
1753{
1754 struct c2c_hist_entry *c2c_he;
1755 struct c2c_hists *c2c_hists;
Jiri Olsa9857b712016-08-17 14:55:23 +02001756 bool display = he__display(he, &c2c.hitm_stats);
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001757
1758 c2c_he = container_of(he, struct c2c_hist_entry, he);
1759 c2c_hists = c2c_he->hists;
1760
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001761 calc_width(he);
1762
Jiri Olsa9857b712016-08-17 14:55:23 +02001763 if (display && c2c_hists) {
Jiri Olsafc9c6302016-05-24 14:14:38 +02001764 c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort);
Jiri Olsa22dd59d2016-05-10 14:08:29 +02001765
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001766 hists__collapse_resort(&c2c_hists->hists, NULL);
1767 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
1768 }
1769
1770 return 0;
1771}
1772
Jiri Olsa1e181b92016-06-03 15:40:28 +02001773static void setup_nodes_header(void)
1774{
1775 dim_node.header = header_node[c2c.node_info];
1776}
1777
1778static int setup_nodes(struct perf_session *session)
1779{
1780 struct numa_node *n;
1781 unsigned long **nodes;
1782 int node, cpu;
1783 int *cpu2node;
1784
1785 if (c2c.node_info > 2)
1786 c2c.node_info = 2;
1787
1788 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1789 c2c.cpus_cnt = session->header.env.nr_cpus_online;
1790
1791 n = session->header.env.numa_nodes;
1792 if (!n)
1793 return -EINVAL;
1794
1795 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
1796 if (!nodes)
1797 return -ENOMEM;
1798
1799 c2c.nodes = nodes;
1800
1801 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
1802 if (!cpu2node)
1803 return -ENOMEM;
1804
1805 for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
1806 cpu2node[cpu] = -1;
1807
1808 c2c.cpu2node = cpu2node;
1809
1810 for (node = 0; node < c2c.nodes_cnt; node++) {
1811 struct cpu_map *map = n[node].map;
1812 unsigned long *set;
1813
1814 set = bitmap_alloc(c2c.cpus_cnt);
1815 if (!set)
1816 return -ENOMEM;
1817
1818 for (cpu = 0; cpu < map->nr; cpu++) {
1819 set_bit(map->map[cpu], set);
1820
1821 if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
1822 return -EINVAL;
1823
1824 cpu2node[map->map[cpu]] = node;
1825 }
1826
1827 nodes[node] = set;
1828 }
1829
1830 setup_nodes_header();
1831 return 0;
1832}
1833
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02001834#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
1835
1836static int resort_hitm_cb(struct hist_entry *he)
1837{
1838 struct c2c_hist_entry *c2c_he;
1839 c2c_he = container_of(he, struct c2c_hist_entry, he);
1840
1841 if (HAS_HITMS(c2c_he)) {
1842 c2c.shared_clines++;
1843 c2c_add_stats(&c2c.hitm_stats, &c2c_he->stats);
1844 }
1845
1846 return 0;
1847}
1848
1849static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
1850{
1851 struct rb_node *next = rb_first(&hists->entries);
1852 int ret = 0;
1853
1854 while (next) {
1855 struct hist_entry *he;
1856
1857 he = rb_entry(next, struct hist_entry, rb_node);
1858 ret = cb(he);
1859 if (ret)
1860 break;
1861 next = rb_next(&he->rb_node);
1862 }
1863
1864 return ret;
1865}
1866
Jiri Olsa74c63a22016-05-02 20:01:59 +02001867static void print_c2c__display_stats(FILE *out)
1868{
1869 int llc_misses;
1870 struct c2c_stats *stats = &c2c.hists.stats;
1871
1872 llc_misses = stats->lcl_dram +
1873 stats->rmt_dram +
1874 stats->rmt_hit +
1875 stats->rmt_hitm;
1876
1877 fprintf(out, "=================================================\n");
1878 fprintf(out, " Trace Event Information \n");
1879 fprintf(out, "=================================================\n");
1880 fprintf(out, " Total records : %10d\n", stats->nr_entries);
1881 fprintf(out, " Locked Load/Store Operations : %10d\n", stats->locks);
1882 fprintf(out, " Load Operations : %10d\n", stats->load);
1883 fprintf(out, " Loads - uncacheable : %10d\n", stats->ld_uncache);
1884 fprintf(out, " Loads - IO : %10d\n", stats->ld_io);
1885 fprintf(out, " Loads - Miss : %10d\n", stats->ld_miss);
1886 fprintf(out, " Loads - no mapping : %10d\n", stats->ld_noadrs);
1887 fprintf(out, " Load Fill Buffer Hit : %10d\n", stats->ld_fbhit);
1888 fprintf(out, " Load L1D hit : %10d\n", stats->ld_l1hit);
1889 fprintf(out, " Load L2D hit : %10d\n", stats->ld_l2hit);
1890 fprintf(out, " Load LLC hit : %10d\n", stats->ld_llchit + stats->lcl_hitm);
1891 fprintf(out, " Load Local HITM : %10d\n", stats->lcl_hitm);
1892 fprintf(out, " Load Remote HITM : %10d\n", stats->rmt_hitm);
1893 fprintf(out, " Load Remote HIT : %10d\n", stats->rmt_hit);
1894 fprintf(out, " Load Local DRAM : %10d\n", stats->lcl_dram);
1895 fprintf(out, " Load Remote DRAM : %10d\n", stats->rmt_dram);
1896 fprintf(out, " Load MESI State Exclusive : %10d\n", stats->ld_excl);
1897 fprintf(out, " Load MESI State Shared : %10d\n", stats->ld_shared);
1898 fprintf(out, " Load LLC Misses : %10d\n", llc_misses);
1899 fprintf(out, " LLC Misses to Local DRAM : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);
1900 fprintf(out, " LLC Misses to Remote DRAM : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);
1901 fprintf(out, " LLC Misses to Remote cache (HIT) : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.);
1902 fprintf(out, " LLC Misses to Remote cache (HITM) : %10.1f%%\n", ((double)stats->rmt_hitm/(double)llc_misses) * 100.);
1903 fprintf(out, " Store Operations : %10d\n", stats->store);
1904 fprintf(out, " Store - uncacheable : %10d\n", stats->st_uncache);
1905 fprintf(out, " Store - no mapping : %10d\n", stats->st_noadrs);
1906 fprintf(out, " Store L1D Hit : %10d\n", stats->st_l1hit);
1907 fprintf(out, " Store L1D Miss : %10d\n", stats->st_l1miss);
1908 fprintf(out, " No Page Map Rejects : %10d\n", stats->nomap);
1909 fprintf(out, " Unable to parse data source : %10d\n", stats->noparse);
1910}
1911
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02001912static void print_shared_cacheline_info(FILE *out)
1913{
1914 struct c2c_stats *stats = &c2c.hitm_stats;
1915 int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
1916
1917 fprintf(out, "=================================================\n");
1918 fprintf(out, " Global Shared Cache Line Event Information \n");
1919 fprintf(out, "=================================================\n");
1920 fprintf(out, " Total Shared Cache Lines : %10d\n", c2c.shared_clines);
1921 fprintf(out, " Load HITs on shared lines : %10d\n", stats->load);
1922 fprintf(out, " Fill Buffer Hits on shared lines : %10d\n", stats->ld_fbhit);
1923 fprintf(out, " L1D hits on shared lines : %10d\n", stats->ld_l1hit);
1924 fprintf(out, " L2D hits on shared lines : %10d\n", stats->ld_l2hit);
1925 fprintf(out, " LLC hits on shared lines : %10d\n", stats->ld_llchit + stats->lcl_hitm);
1926 fprintf(out, " Locked Access on shared lines : %10d\n", stats->locks);
1927 fprintf(out, " Store HITs on shared lines : %10d\n", stats->store);
1928 fprintf(out, " Store L1D hits on shared lines : %10d\n", stats->st_l1hit);
1929 fprintf(out, " Total Merged records : %10d\n", hitm_cnt + stats->store);
1930}
1931
Jiri Olsa2d388bd2016-05-03 14:32:56 +02001932static void print_cacheline(struct c2c_hists *c2c_hists,
1933 struct hist_entry *he_cl,
1934 struct perf_hpp_list *hpp_list,
1935 FILE *out)
1936{
1937 char bf[1000];
1938 struct perf_hpp hpp = {
1939 .buf = bf,
1940 .size = 1000,
1941 };
1942 static bool once;
1943
1944 if (!once) {
1945 hists__fprintf_headers(&c2c_hists->hists, out);
1946 once = true;
1947 } else {
1948 fprintf(out, "\n");
1949 }
1950
1951 fprintf(out, " ------------------------------------------------------\n");
1952 __hist_entry__snprintf(he_cl, &hpp, hpp_list);
1953 fprintf(out, "%s\n", bf);
1954 fprintf(out, " ------------------------------------------------------\n");
1955
1956 hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, true);
1957}
1958
1959static void print_pareto(FILE *out)
1960{
1961 struct perf_hpp_list hpp_list;
1962 struct rb_node *nd;
1963 int ret;
1964
1965 perf_hpp_list__init(&hpp_list);
1966 ret = hpp_list__parse(&hpp_list,
1967 "cl_rmt_hitm,"
1968 "cl_lcl_hitm,"
1969 "cl_stores_l1hit,"
1970 "cl_stores_l1miss,"
1971 "dcacheline",
1972 NULL);
1973
1974 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
1975 return;
1976
1977 nd = rb_first(&c2c.hists.hists.entries);
1978
1979 for (; nd; nd = rb_next(nd)) {
1980 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1981 struct c2c_hist_entry *c2c_he;
1982
1983 if (he->filtered)
1984 continue;
1985
1986 c2c_he = container_of(he, struct c2c_hist_entry, he);
1987 print_cacheline(c2c_he->hists, he, &hpp_list, out);
1988 }
1989}
1990
Jiri Olsa2709b972016-08-27 11:40:23 +02001991static void print_c2c_info(FILE *out, struct perf_session *session)
1992{
1993 struct perf_evlist *evlist = session->evlist;
1994 struct perf_evsel *evsel;
1995 bool first = true;
1996
1997 fprintf(out, "=================================================\n");
1998 fprintf(out, " c2c details \n");
1999 fprintf(out, "=================================================\n");
2000
2001 evlist__for_each_entry(evlist, evsel) {
2002 fprintf(out, "%-36s: %s\n", first ? " Events" : "",
2003 perf_evsel__name(evsel));
2004 first = false;
2005 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002006 fprintf(out, " Cachelines sort on : %s HITMs\n",
2007 c2c.display == DISPLAY_LCL ? "Local" : "Remote");
Jiri Olsafc9c6302016-05-24 14:14:38 +02002008 fprintf(out, " Cacheline data grouping : %s\n", c2c.cl_sort);
Jiri Olsa2709b972016-08-27 11:40:23 +02002009}
2010
2011static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002012{
2013 setup_pager();
2014
Jiri Olsa74c63a22016-05-02 20:01:59 +02002015 print_c2c__display_stats(out);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002016 fprintf(out, "\n");
2017 print_shared_cacheline_info(out);
Jiri Olsa2709b972016-08-27 11:40:23 +02002018 fprintf(out, "\n");
2019 print_c2c_info(out, session);
Jiri Olsa74c63a22016-05-02 20:01:59 +02002020
2021 if (c2c.stats_only)
2022 return;
2023
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002024 fprintf(out, "\n");
2025 fprintf(out, "=================================================\n");
2026 fprintf(out, " Shared Data Cache Line Table \n");
2027 fprintf(out, "=================================================\n");
2028 fprintf(out, "#\n");
2029
2030 hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, false);
2031
2032 fprintf(out, "\n");
2033 fprintf(out, "=================================================\n");
2034 fprintf(out, " Shared Cache Line Distribution Pareto \n");
2035 fprintf(out, "=================================================\n");
2036 fprintf(out, "#\n");
2037
2038 print_pareto(out);
2039}
Jiri Olsa1e181b92016-06-03 15:40:28 +02002040
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002041#ifdef HAVE_SLANG_SUPPORT
2042static void c2c_browser__update_nr_entries(struct hist_browser *hb)
2043{
2044 u64 nr_entries = 0;
2045 struct rb_node *nd = rb_first(&hb->hists->entries);
2046
2047 while (nd) {
2048 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2049
2050 if (!he->filtered)
2051 nr_entries++;
2052
2053 nd = rb_next(nd);
2054 }
2055
2056 hb->nr_non_filtered_entries = nr_entries;
2057}
2058
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002059struct c2c_cacheline_browser {
2060 struct hist_browser hb;
2061 struct hist_entry *he;
2062};
2063
2064static int
2065perf_c2c_cacheline_browser__title(struct hist_browser *browser,
2066 char *bf, size_t size)
2067{
2068 struct c2c_cacheline_browser *cl_browser;
2069 struct hist_entry *he;
2070 uint64_t addr = 0;
2071
2072 cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
2073 he = cl_browser->he;
2074
2075 if (he->mem_info)
2076 addr = cl_address(he->mem_info->daddr.addr);
2077
2078 scnprintf(bf, size, "Cacheline 0x%lx", addr);
2079 return 0;
2080}
2081
2082static struct c2c_cacheline_browser*
2083c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
2084{
2085 struct c2c_cacheline_browser *browser;
2086
2087 browser = zalloc(sizeof(*browser));
2088 if (browser) {
2089 hist_browser__init(&browser->hb, hists);
2090 browser->hb.c2c_filter = true;
2091 browser->hb.title = perf_c2c_cacheline_browser__title;
2092 browser->he = he;
2093 }
2094
2095 return browser;
2096}
2097
2098static int perf_c2c__browse_cacheline(struct hist_entry *he)
2099{
2100 struct c2c_hist_entry *c2c_he;
2101 struct c2c_hists *c2c_hists;
2102 struct c2c_cacheline_browser *cl_browser;
2103 struct hist_browser *browser;
2104 int key = -1;
2105
2106 c2c_he = container_of(he, struct c2c_hist_entry, he);
2107 c2c_hists = c2c_he->hists;
2108
2109 cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
2110 if (cl_browser == NULL)
2111 return -1;
2112
2113 browser = &cl_browser->hb;
2114
2115 /* reset abort key so that it can get Ctrl-C as a key */
2116 SLang_reset_tty();
2117 SLang_init_tty(0, 0, 0);
2118
2119 c2c_browser__update_nr_entries(browser);
2120
2121 while (1) {
2122 key = hist_browser__run(browser, "help");
2123
2124 switch (key) {
2125 case 'q':
2126 goto out;
2127 default:
2128 break;
2129 }
2130 }
2131
2132out:
2133 free(cl_browser);
2134 return 0;
2135}
2136
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002137static int perf_c2c_browser__title(struct hist_browser *browser,
2138 char *bf, size_t size)
2139{
2140 scnprintf(bf, size,
Jiri Olsa55b95772016-05-29 10:21:45 +02002141 "Shared Data Cache Line Table "
2142 "(%lu entries, sorted on %s HITMs)",
2143 browser->nr_non_filtered_entries,
2144 c2c.display == DISPLAY_LCL ? "local" : "remote");
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002145 return 0;
2146}
2147
2148static struct hist_browser*
2149perf_c2c_browser__new(struct hists *hists)
2150{
2151 struct hist_browser *browser = hist_browser__new(hists);
2152
2153 if (browser) {
2154 browser->title = perf_c2c_browser__title;
2155 browser->c2c_filter = true;
2156 }
2157
2158 return browser;
2159}
2160
2161static int perf_c2c__hists_browse(struct hists *hists)
2162{
2163 struct hist_browser *browser;
2164 int key = -1;
2165
2166 browser = perf_c2c_browser__new(hists);
2167 if (browser == NULL)
2168 return -1;
2169
2170 /* reset abort key so that it can get Ctrl-C as a key */
2171 SLang_reset_tty();
2172 SLang_init_tty(0, 0, 0);
2173
2174 c2c_browser__update_nr_entries(browser);
2175
2176 while (1) {
2177 key = hist_browser__run(browser, "help");
2178
2179 switch (key) {
2180 case 'q':
2181 goto out;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002182 case 'd':
2183 perf_c2c__browse_cacheline(browser->he_selection);
2184 break;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002185 default:
2186 break;
2187 }
2188 }
2189
2190out:
2191 hist_browser__delete(browser);
2192 return 0;
2193}
2194
Jiri Olsa2709b972016-08-27 11:40:23 +02002195static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002196{
2197 if (c2c.use_stdio)
Jiri Olsa2709b972016-08-27 11:40:23 +02002198 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002199 else
2200 perf_c2c__hists_browse(&c2c.hists.hists);
2201}
2202#else
Jiri Olsa2709b972016-08-27 11:40:23 +02002203static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002204{
2205 use_browser = 0;
Jiri Olsa2709b972016-08-27 11:40:23 +02002206 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002207}
2208#endif /* HAVE_SLANG_SUPPORT */
2209
2210static void ui_quirks(void)
2211{
2212 if (!c2c.use_stdio) {
2213 dim_offset.width = 5;
2214 dim_offset.header = header_offset_tui;
2215 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002216
2217 dim_percent_hitm.header = percent_hitm_header[c2c.display];
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002218}
2219
Jiri Olsadd805762016-05-11 18:23:48 +02002220#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
2221
2222const char callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
2223 CALLCHAIN_REPORT_HELP
2224 "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
2225
2226static int
2227parse_callchain_opt(const struct option *opt, const char *arg, int unset)
2228{
2229 struct callchain_param *callchain = opt->value;
2230
2231 callchain->enabled = !unset;
2232 /*
2233 * --no-call-graph
2234 */
2235 if (unset) {
2236 symbol_conf.use_callchain = false;
2237 callchain->mode = CHAIN_NONE;
2238 return 0;
2239 }
2240
2241 return parse_callchain_report_opt(arg);
2242}
2243
2244static int setup_callchain(struct perf_evlist *evlist)
2245{
2246 u64 sample_type = perf_evlist__combined_sample_type(evlist);
2247 enum perf_call_graph_mode mode = CALLCHAIN_NONE;
2248
2249 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
2250 (sample_type & PERF_SAMPLE_STACK_USER))
2251 mode = CALLCHAIN_DWARF;
2252 else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
2253 mode = CALLCHAIN_LBR;
2254 else if (sample_type & PERF_SAMPLE_CALLCHAIN)
2255 mode = CALLCHAIN_FP;
2256
2257 if (!callchain_param.enabled &&
2258 callchain_param.mode != CHAIN_NONE &&
2259 mode != CALLCHAIN_NONE) {
2260 symbol_conf.use_callchain = true;
2261 if (callchain_register_param(&callchain_param) < 0) {
2262 ui__error("Can't register callchain params.\n");
2263 return -EINVAL;
2264 }
2265 }
2266
2267 callchain_param.record_mode = mode;
2268 callchain_param.min_percent = 0;
2269 return 0;
2270}
2271
Jiri Olsa55b95772016-05-29 10:21:45 +02002272static int setup_display(const char *str)
2273{
2274 const char *display = str ?: "rmt";
2275
2276 if (!strcmp(display, "rmt"))
2277 c2c.display = DISPLAY_RMT;
2278 else if (!strcmp(display, "lcl"))
2279 c2c.display = DISPLAY_LCL;
2280 else {
2281 pr_err("failed: unknown display type: %s\n", str);
2282 return -1;
2283 }
2284
2285 return 0;
2286}
2287
Jiri Olsafc9c6302016-05-24 14:14:38 +02002288#define for_each_token(__tok, __buf, __sep, __tmp) \
2289 for (__tok = strtok_r(__buf, __sep, &__tmp); __tok; \
2290 __tok = strtok_r(NULL, __sep, &__tmp))
2291
2292static int build_cl_output(char *cl_sort)
2293{
2294 char *tok, *tmp, *buf = strdup(cl_sort);
2295 bool add_pid = false;
2296 bool add_tid = false;
2297 bool add_iaddr = false;
2298 bool add_sym = false;
2299 bool add_dso = false;
2300 bool add_src = false;
2301
2302 if (!buf)
2303 return -ENOMEM;
2304
2305 for_each_token(tok, buf, ",", tmp) {
2306 if (!strcmp(tok, "tid")) {
2307 add_tid = true;
2308 } else if (!strcmp(tok, "pid")) {
2309 add_pid = true;
2310 } else if (!strcmp(tok, "iaddr")) {
2311 add_iaddr = true;
2312 add_sym = true;
2313 add_dso = true;
2314 add_src = true;
2315 } else if (!strcmp(tok, "dso")) {
2316 add_dso = true;
2317 } else if (strcmp(tok, "offset")) {
2318 pr_err("unrecognized sort token: %s\n", tok);
2319 return -EINVAL;
2320 }
2321 }
2322
2323 if (asprintf(&c2c.cl_output,
2324 "%s%s%s%s%s%s%s%s%s",
2325 "percent_rmt_hitm,"
2326 "percent_lcl_hitm,"
2327 "percent_stores_l1hit,"
2328 "percent_stores_l1miss,"
2329 "offset,",
2330 add_pid ? "pid," : "",
2331 add_tid ? "tid," : "",
2332 add_iaddr ? "iaddr," : "",
2333 "mean_rmt,"
2334 "mean_lcl,"
2335 "mean_load,"
2336 "cpucnt,",
2337 add_sym ? "symbol," : "",
2338 add_dso ? "dso," : "",
2339 add_src ? "cl_srcline," : "",
2340 "node") < 0)
2341 return -ENOMEM;
2342
2343 c2c.show_src = add_src;
2344
2345 free(buf);
2346 return 0;
2347}
2348
2349static int setup_coalesce(const char *coalesce)
2350{
2351 const char *c = coalesce ?: coalesce_default;
2352
2353 if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)
2354 return -ENOMEM;
2355
2356 if (build_cl_output(c2c.cl_sort))
2357 return -1;
2358
2359 if (asprintf(&c2c.cl_resort, "offset,%s",
2360 c2c.display == DISPLAY_RMT ?
2361 "rmt_hitm,lcl_hitm" :
2362 "lcl_hitm,rmt_hitm") < 0)
2363 return -ENOMEM;
2364
2365 pr_debug("coalesce sort fields: %s\n", c2c.cl_sort);
2366 pr_debug("coalesce resort fields: %s\n", c2c.cl_resort);
2367 pr_debug("coalesce output fields: %s\n", c2c.cl_output);
2368 return 0;
2369}
2370
Jiri Olsa903a6f12016-09-22 17:36:40 +02002371static int perf_c2c__report(int argc, const char **argv)
2372{
2373 struct perf_session *session;
Jiri Olsa78b27542016-09-22 17:36:44 +02002374 struct ui_progress prog;
Jiri Olsa903a6f12016-09-22 17:36:40 +02002375 struct perf_data_file file = {
2376 .mode = PERF_DATA_MODE_READ,
2377 };
Jiri Olsadd805762016-05-11 18:23:48 +02002378 char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
Jiri Olsa55b95772016-05-29 10:21:45 +02002379 const char *display = NULL;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002380 const char *coalesce = NULL;
Jiri Olsa903a6f12016-09-22 17:36:40 +02002381 const struct option c2c_options[] = {
2382 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
2383 "file", "vmlinux pathname"),
2384 OPT_INCR('v', "verbose", &verbose,
2385 "be more verbose (show counter open errors, etc)"),
2386 OPT_STRING('i', "input", &input_name, "file",
2387 "the input file to process"),
Jiri Olsa1e181b92016-06-03 15:40:28 +02002388 OPT_INCR('N', "node-info", &c2c.node_info,
2389 "show extra node info in report (repeat for more info)"),
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002390#ifdef HAVE_SLANG_SUPPORT
2391 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2392#endif
Jiri Olsa74c63a22016-05-02 20:01:59 +02002393 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
2394 "Use the stdio interface"),
Jiri Olsadd805762016-05-11 18:23:48 +02002395 OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
2396 "print_type,threshold[,print_limit],order,sort_key[,branch],value",
2397 callchain_help, &parse_callchain_opt,
2398 callchain_default_opt),
Jiri Olsa55b95772016-05-29 10:21:45 +02002399 OPT_STRING('d', "display", &display, NULL, "lcl,rmt"),
Jiri Olsafc9c6302016-05-24 14:14:38 +02002400 OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
2401 "coalesce fields: pid,tid,iaddr,dso"),
Jiri Olsa903a6f12016-09-22 17:36:40 +02002402 OPT_END()
2403 };
2404 int err = 0;
2405
2406 argc = parse_options(argc, argv, c2c_options, report_c2c_usage,
2407 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa78b27542016-09-22 17:36:44 +02002408 if (argc)
Jiri Olsa903a6f12016-09-22 17:36:40 +02002409 usage_with_options(report_c2c_usage, c2c_options);
2410
Jiri Olsa74c63a22016-05-02 20:01:59 +02002411 if (c2c.stats_only)
2412 c2c.use_stdio = true;
2413
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002414 if (c2c.use_stdio)
2415 use_browser = 0;
2416 else
2417 use_browser = 1;
2418
2419 setup_browser(false);
2420
Jiri Olsa78b27542016-09-22 17:36:44 +02002421 if (!input_name || !strlen(input_name))
2422 input_name = "perf.data";
2423
Jiri Olsa903a6f12016-09-22 17:36:40 +02002424 file.path = input_name;
2425
Jiri Olsa55b95772016-05-29 10:21:45 +02002426 err = setup_display(display);
2427 if (err)
2428 goto out;
2429
Jiri Olsafc9c6302016-05-24 14:14:38 +02002430 err = setup_coalesce(coalesce);
2431 if (err) {
2432 pr_debug("Failed to initialize hists\n");
2433 goto out;
2434 }
2435
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02002436 err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
Jiri Olsac75540e2016-09-22 17:36:41 +02002437 if (err) {
2438 pr_debug("Failed to initialize hists\n");
2439 goto out;
2440 }
2441
Jiri Olsa903a6f12016-09-22 17:36:40 +02002442 session = perf_session__new(&file, 0, &c2c.tool);
2443 if (session == NULL) {
2444 pr_debug("No memory for session\n");
2445 goto out;
2446 }
Jiri Olsa1e181b92016-06-03 15:40:28 +02002447 err = setup_nodes(session);
2448 if (err) {
2449 pr_err("Failed setup nodes\n");
2450 goto out;
2451 }
Jiri Olsa903a6f12016-09-22 17:36:40 +02002452
Jiri Olsadd805762016-05-11 18:23:48 +02002453 err = setup_callchain(session->evlist);
2454 if (err)
2455 goto out_session;
2456
Jiri Olsa903a6f12016-09-22 17:36:40 +02002457 if (symbol__init(&session->header.env) < 0)
2458 goto out_session;
2459
2460 /* No pipe support at the moment. */
2461 if (perf_data_file__is_pipe(session->file)) {
2462 pr_debug("No pipe support at the moment.\n");
2463 goto out_session;
2464 }
2465
Jiri Olsa78b27542016-09-22 17:36:44 +02002466 err = perf_session__process_events(session);
2467 if (err) {
2468 pr_err("failed to process sample\n");
2469 goto out_session;
2470 }
2471
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002472 c2c_hists__reinit(&c2c.hists,
2473 "dcacheline,"
2474 "tot_recs,"
2475 "percent_hitm,"
2476 "tot_hitm,lcl_hitm,rmt_hitm,"
2477 "stores,stores_l1hit,stores_l1miss,"
2478 "dram_lcl,dram_rmt,"
2479 "ld_llcmiss,"
2480 "tot_loads,"
2481 "ld_fbhit,ld_l1hit,ld_l2hit,"
2482 "ld_lclhit,ld_rmthit",
Jiri Olsa55b95772016-05-29 10:21:45 +02002483 c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm"
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002484 );
2485
Jiri Olsa78b27542016-09-22 17:36:44 +02002486 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
2487
2488 hists__collapse_resort(&c2c.hists.hists, NULL);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002489 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_hitm_cb);
2490 hists__iterate_cb(&c2c.hists.hists, resort_cl_cb);
Jiri Olsa78b27542016-09-22 17:36:44 +02002491
2492 ui_progress__finish();
2493
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002494 ui_quirks();
2495
Jiri Olsa2709b972016-08-27 11:40:23 +02002496 perf_c2c_display(session);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002497
Jiri Olsa903a6f12016-09-22 17:36:40 +02002498out_session:
2499 perf_session__delete(session);
2500out:
2501 return err;
2502}
2503
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002504static int parse_record_events(const struct option *opt __maybe_unused,
2505 const char *str, int unset __maybe_unused)
2506{
2507 bool *event_set = (bool *) opt->value;
2508
2509 *event_set = true;
2510 return perf_mem_events__parse(str);
2511}
2512
2513
2514static const char * const __usage_record[] = {
2515 "perf c2c record [<options>] [<command>]",
2516 "perf c2c record [<options>] -- <command> [<options>]",
2517 NULL
2518};
2519
2520static const char * const *record_mem_usage = __usage_record;
2521
2522static int perf_c2c__record(int argc, const char **argv)
2523{
2524 int rec_argc, i = 0, j;
2525 const char **rec_argv;
2526 int ret;
2527 bool all_user = false, all_kernel = false;
2528 bool event_set = false;
2529 struct option options[] = {
2530 OPT_CALLBACK('e', "event", &event_set, "event",
2531 "event selector. Use 'perf mem record -e list' to list available events",
2532 parse_record_events),
2533 OPT_INCR('v', "verbose", &verbose,
2534 "be more verbose (show counter open errors, etc)"),
2535 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
2536 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
2537 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
2538 OPT_END()
2539 };
2540
2541 if (perf_mem_events__init()) {
2542 pr_err("failed: memory events not supported\n");
2543 return -1;
2544 }
2545
2546 argc = parse_options(argc, argv, options, record_mem_usage,
2547 PARSE_OPT_KEEP_UNKNOWN);
2548
2549 rec_argc = argc + 10; /* max number of arguments */
2550 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2551 if (!rec_argv)
2552 return -1;
2553
2554 rec_argv[i++] = "record";
2555
2556 if (!event_set) {
2557 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
2558 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
2559 }
2560
2561 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
2562 rec_argv[i++] = "-W";
2563
2564 rec_argv[i++] = "-d";
2565 rec_argv[i++] = "--sample-cpu";
2566
2567 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
2568 if (!perf_mem_events[j].record)
2569 continue;
2570
2571 if (!perf_mem_events[j].supported) {
2572 pr_err("failed: event '%s' not supported\n",
2573 perf_mem_events[j].name);
2574 return -1;
2575 }
2576
2577 rec_argv[i++] = "-e";
2578 rec_argv[i++] = perf_mem_events__name(j);
2579 };
2580
2581 if (all_user)
2582 rec_argv[i++] = "--all-user";
2583
2584 if (all_kernel)
2585 rec_argv[i++] = "--all-kernel";
2586
2587 for (j = 0; j < argc; j++, i++)
2588 rec_argv[i] = argv[j];
2589
2590 if (verbose > 0) {
2591 pr_debug("calling: ");
2592
2593 j = 0;
2594
2595 while (rec_argv[j]) {
2596 pr_debug("%s ", rec_argv[j]);
2597 j++;
2598 }
2599 pr_debug("\n");
2600 }
2601
2602 ret = cmd_record(i, rec_argv, NULL);
2603 free(rec_argv);
2604 return ret;
2605}
2606
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002607int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused)
2608{
2609 const struct option c2c_options[] = {
2610 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
2611 OPT_END()
2612 };
2613
2614 argc = parse_options(argc, argv, c2c_options, c2c_usage,
2615 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002616
2617 if (!argc)
2618 usage_with_options(c2c_usage, c2c_options);
2619
2620 if (!strncmp(argv[0], "rec", 3)) {
2621 return perf_c2c__record(argc, argv);
Jiri Olsa903a6f12016-09-22 17:36:40 +02002622 } else if (!strncmp(argv[0], "rep", 3)) {
2623 return perf_c2c__report(argc, argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002624 } else {
2625 usage_with_options(c2c_usage, c2c_options);
2626 }
2627
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002628 return 0;
2629}