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