blob: a90c1260f49ef59f2b2ff5a82af608bf477cf122 [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 */
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030012#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030013#include <inttypes.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020014#include <linux/compiler.h>
15#include <linux/kernel.h>
Jiri Olsacbb88502016-09-22 17:36:48 +020016#include <linux/stringify.h>
Jiri Olsa1e181b92016-06-03 15:40:28 +020017#include <asm/bug.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020018#include "util.h"
19#include "debug.h"
20#include "builtin.h"
21#include <subcmd/parse-options.h>
Jiri Olsa39bcd4a2016-09-22 17:36:39 +020022#include "mem-events.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020023#include "session.h"
24#include "hist.h"
Jiri Olsacbb88502016-09-22 17:36:48 +020025#include "sort.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020026#include "tool.h"
27#include "data.h"
Jiri Olsa8d3f9382016-09-22 17:36:42 +020028#include "sort.h"
Jiri Olsa2709b972016-08-27 11:40:23 +020029#include "evlist.h"
30#include "evsel.h"
Jiri Olsa2d388bd2016-05-03 14:32:56 +020031#include <asm/bug.h>
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010032#include "ui/browsers/hists.h"
Jiri Olsadd805762016-05-11 18:23:48 +020033#include "evlist.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020034
Jiri Olsac75540e2016-09-22 17:36:41 +020035struct c2c_hists {
36 struct hists hists;
37 struct perf_hpp_list list;
Jiri Olsab2252ae2016-09-22 17:36:46 +020038 struct c2c_stats stats;
Jiri Olsac75540e2016-09-22 17:36:41 +020039};
40
Jiri Olsa92062d52016-06-05 13:40:53 +020041struct compute_stats {
42 struct stats lcl_hitm;
43 struct stats rmt_hitm;
44 struct stats load;
45};
46
Jiri Olsa78b27542016-09-22 17:36:44 +020047struct c2c_hist_entry {
48 struct c2c_hists *hists;
Jiri Olsab2252ae2016-09-22 17:36:46 +020049 struct c2c_stats stats;
Jiri Olsa1e181b92016-06-03 15:40:28 +020050 unsigned long *cpuset;
51 struct c2c_stats *node_stats;
Jiri Olsabb342da2016-07-06 15:40:09 +020052 unsigned int cacheline_idx;
Jiri Olsa92062d52016-06-05 13:40:53 +020053
54 struct compute_stats cstats;
55
Jiri Olsa78b27542016-09-22 17:36:44 +020056 /*
57 * must be at the end,
58 * because of its callchain dynamic entry
59 */
60 struct hist_entry he;
61};
62
Jiri Olsa190bacc2017-01-20 10:20:32 +010063static char const *coalesce_default = "pid,iaddr";
Jiri Olsafc9c6302016-05-24 14:14:38 +020064
Jiri Olsa903a6f12016-09-22 17:36:40 +020065struct perf_c2c {
Jiri Olsac75540e2016-09-22 17:36:41 +020066 struct perf_tool tool;
67 struct c2c_hists hists;
Jiri Olsa1e181b92016-06-03 15:40:28 +020068
69 unsigned long **nodes;
70 int nodes_cnt;
71 int cpus_cnt;
72 int *cpu2node;
73 int node_info;
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +020074
75 bool show_src;
Jiri Olsaaf09b2d2016-10-11 13:52:05 +020076 bool show_all;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010077 bool use_stdio;
Jiri Olsa74c63a22016-05-02 20:01:59 +020078 bool stats_only;
Jiri Olsa590b6a32016-07-10 16:25:15 +020079 bool symbol_full;
Jiri Olsa7ef2efa2016-07-01 11:12:11 +020080
81 /* HITM shared clines stats */
82 struct c2c_stats hitm_stats;
83 int shared_clines;
Jiri Olsa55b95772016-05-29 10:21:45 +020084
85 int display;
Jiri Olsafc9c6302016-05-24 14:14:38 +020086
87 const char *coalesce;
88 char *cl_sort;
89 char *cl_resort;
90 char *cl_output;
Jiri Olsa55b95772016-05-29 10:21:45 +020091};
92
93enum {
94 DISPLAY_LCL,
95 DISPLAY_RMT,
Jiri Olsad940bac2016-11-21 22:33:30 +010096 DISPLAY_TOT,
97 DISPLAY_MAX,
98};
99
100static const char *display_str[DISPLAY_MAX] = {
101 [DISPLAY_LCL] = "Local",
102 [DISPLAY_RMT] = "Remote",
103 [DISPLAY_TOT] = "Total",
Jiri Olsa903a6f12016-09-22 17:36:40 +0200104};
105
Jiri Olsa3a5bfab2016-11-21 22:33:31 +0100106static const struct option c2c_options[] = {
107 OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),
108 OPT_END()
109};
110
Jiri Olsa903a6f12016-09-22 17:36:40 +0200111static struct perf_c2c c2c;
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200112
Jiri Olsa78b27542016-09-22 17:36:44 +0200113static void *c2c_he_zalloc(size_t size)
114{
115 struct c2c_hist_entry *c2c_he;
116
117 c2c_he = zalloc(size + sizeof(*c2c_he));
118 if (!c2c_he)
119 return NULL;
120
Jiri Olsa1e181b92016-06-03 15:40:28 +0200121 c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
122 if (!c2c_he->cpuset)
123 return NULL;
124
125 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
126 if (!c2c_he->node_stats)
127 return NULL;
128
Jiri Olsa92062d52016-06-05 13:40:53 +0200129 init_stats(&c2c_he->cstats.lcl_hitm);
130 init_stats(&c2c_he->cstats.rmt_hitm);
131 init_stats(&c2c_he->cstats.load);
132
Jiri Olsa78b27542016-09-22 17:36:44 +0200133 return &c2c_he->he;
134}
135
136static void c2c_he_free(void *he)
137{
138 struct c2c_hist_entry *c2c_he;
139
140 c2c_he = container_of(he, struct c2c_hist_entry, he);
141 if (c2c_he->hists) {
142 hists__delete_entries(&c2c_he->hists->hists);
143 free(c2c_he->hists);
144 }
145
Jiri Olsa1e181b92016-06-03 15:40:28 +0200146 free(c2c_he->cpuset);
147 free(c2c_he->node_stats);
Jiri Olsa78b27542016-09-22 17:36:44 +0200148 free(c2c_he);
149}
150
151static struct hist_entry_ops c2c_entry_ops = {
152 .new = c2c_he_zalloc,
153 .free = c2c_he_free,
154};
155
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200156static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200157 const char *sort,
158 int nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200159
Jiri Olsab2252ae2016-09-22 17:36:46 +0200160static struct c2c_hists*
161he__get_c2c_hists(struct hist_entry *he,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200162 const char *sort,
163 int nr_header_lines)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200164{
165 struct c2c_hist_entry *c2c_he;
166 struct c2c_hists *hists;
167 int ret;
168
169 c2c_he = container_of(he, struct c2c_hist_entry, he);
170 if (c2c_he->hists)
Jiri Olsab2252ae2016-09-22 17:36:46 +0200171 return c2c_he->hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200172
173 hists = c2c_he->hists = zalloc(sizeof(*hists));
174 if (!hists)
175 return NULL;
176
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200177 ret = c2c_hists__init(hists, sort, nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200178 if (ret) {
179 free(hists);
180 return NULL;
181 }
182
Jiri Olsab2252ae2016-09-22 17:36:46 +0200183 return hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200184}
185
Jiri Olsa1e181b92016-06-03 15:40:28 +0200186static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
187 struct perf_sample *sample)
188{
189 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
190 "WARNING: no sample cpu value"))
191 return;
192
193 set_bit(sample->cpu, c2c_he->cpuset);
194}
195
Jiri Olsa92062d52016-06-05 13:40:53 +0200196static void compute_stats(struct c2c_hist_entry *c2c_he,
197 struct c2c_stats *stats,
198 u64 weight)
199{
200 struct compute_stats *cstats = &c2c_he->cstats;
201
202 if (stats->rmt_hitm)
203 update_stats(&cstats->rmt_hitm, weight);
204 else if (stats->lcl_hitm)
205 update_stats(&cstats->lcl_hitm, weight);
206 else if (stats->load)
207 update_stats(&cstats->load, weight);
208}
209
Jiri Olsa78b27542016-09-22 17:36:44 +0200210static int process_sample_event(struct perf_tool *tool __maybe_unused,
211 union perf_event *event,
212 struct perf_sample *sample,
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -0300213 struct perf_evsel *evsel,
Jiri Olsa78b27542016-09-22 17:36:44 +0200214 struct machine *machine)
215{
Jiri Olsab2252ae2016-09-22 17:36:46 +0200216 struct c2c_hists *c2c_hists = &c2c.hists;
217 struct c2c_hist_entry *c2c_he;
218 struct c2c_stats stats = { .nr_entries = 0, };
Jiri Olsa78b27542016-09-22 17:36:44 +0200219 struct hist_entry *he;
220 struct addr_location al;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200221 struct mem_info *mi, *mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200222 int ret;
223
224 if (machine__resolve(machine, &al, sample) < 0) {
225 pr_debug("problem processing %d event, skipping it.\n",
226 event->header.type);
227 return -1;
228 }
229
Jiri Olsadd805762016-05-11 18:23:48 +0200230 ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
231 evsel, &al, sysctl_perf_event_max_stack);
232 if (ret)
233 goto out;
234
Jiri Olsa78b27542016-09-22 17:36:44 +0200235 mi = sample__resolve_mem(sample, &al);
236 if (mi == NULL)
237 return -ENOMEM;
238
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200239 mi_dup = memdup(mi, sizeof(*mi));
240 if (!mi_dup)
241 goto free_mi;
242
Jiri Olsab2252ae2016-09-22 17:36:46 +0200243 c2c_decode_stats(&stats, mi);
244
245 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsa78b27542016-09-22 17:36:44 +0200246 &al, NULL, NULL, mi,
247 sample, true);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200248 if (he == NULL)
249 goto free_mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200250
Jiri Olsab2252ae2016-09-22 17:36:46 +0200251 c2c_he = container_of(he, struct c2c_hist_entry, he);
252 c2c_add_stats(&c2c_he->stats, &stats);
253 c2c_add_stats(&c2c_hists->stats, &stats);
254
Jiri Olsa1e181b92016-06-03 15:40:28 +0200255 c2c_he__set_cpu(c2c_he, sample);
256
Jiri Olsab2252ae2016-09-22 17:36:46 +0200257 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsa78b27542016-09-22 17:36:44 +0200258 ret = hist_entry__append_callchain(he, sample);
259
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200260 if (!ret) {
Jiri Olsa1e181b92016-06-03 15:40:28 +0200261 /*
262 * There's already been warning about missing
263 * sample's cpu value. Let's account all to
264 * node 0 in this case, without any further
265 * warning.
266 *
267 * Doing node stats only for single callchain data.
268 */
269 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
270 int node = c2c.cpu2node[cpu];
271
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200272 mi = mi_dup;
273
274 mi_dup = memdup(mi, sizeof(*mi));
275 if (!mi_dup)
276 goto free_mi;
277
Jiri Olsafc9c6302016-05-24 14:14:38 +0200278 c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200279 if (!c2c_hists)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200280 goto free_mi_dup;
281
Jiri Olsab2252ae2016-09-22 17:36:46 +0200282 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200283 &al, NULL, NULL, mi,
284 sample, true);
285 if (he == NULL)
286 goto free_mi_dup;
287
Jiri Olsab2252ae2016-09-22 17:36:46 +0200288 c2c_he = container_of(he, struct c2c_hist_entry, he);
289 c2c_add_stats(&c2c_he->stats, &stats);
290 c2c_add_stats(&c2c_hists->stats, &stats);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200291 c2c_add_stats(&c2c_he->node_stats[node], &stats);
292
Jiri Olsa92062d52016-06-05 13:40:53 +0200293 compute_stats(c2c_he, &stats, sample->weight);
294
Jiri Olsa1e181b92016-06-03 15:40:28 +0200295 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200296
297 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200298 ret = hist_entry__append_callchain(he, sample);
299 }
300
301out:
Jiri Olsa78b27542016-09-22 17:36:44 +0200302 addr_location__put(&al);
303 return ret;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200304
305free_mi_dup:
306 free(mi_dup);
307free_mi:
308 free(mi);
309 ret = -ENOMEM;
310 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200311}
312
313static struct perf_c2c c2c = {
314 .tool = {
315 .sample = process_sample_event,
316 .mmap = perf_event__process_mmap,
317 .mmap2 = perf_event__process_mmap2,
318 .comm = perf_event__process_comm,
319 .exit = perf_event__process_exit,
320 .fork = perf_event__process_fork,
321 .lost = perf_event__process_lost,
322 .ordered_events = true,
323 .ordering_requires_timestamps = true,
324 },
325};
326
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200327static const char * const c2c_usage[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +0200328 "perf c2c {record|report}",
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200329 NULL
330};
331
Jiri Olsa903a6f12016-09-22 17:36:40 +0200332static const char * const __usage_report[] = {
333 "perf c2c report",
334 NULL
335};
336
337static const char * const *report_c2c_usage = __usage_report;
338
Jiri Olsac75540e2016-09-22 17:36:41 +0200339#define C2C_HEADER_MAX 2
340
341struct c2c_header {
342 struct {
343 const char *text;
344 int span;
345 } line[C2C_HEADER_MAX];
346};
347
348struct c2c_dimension {
349 struct c2c_header header;
350 const char *name;
351 int width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200352 struct sort_entry *se;
Jiri Olsac75540e2016-09-22 17:36:41 +0200353
354 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
355 struct hist_entry *, struct hist_entry *);
356 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
357 struct hist_entry *he);
358 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
359 struct hist_entry *he);
360};
361
362struct c2c_fmt {
363 struct perf_hpp_fmt fmt;
364 struct c2c_dimension *dim;
365};
366
Jiri Olsa590b6a32016-07-10 16:25:15 +0200367#define SYMBOL_WIDTH 30
368
369static struct c2c_dimension dim_symbol;
370static struct c2c_dimension dim_srcline;
371
372static int symbol_width(struct hists *hists, struct sort_entry *se)
373{
374 int width = hists__col_len(hists, se->se_width_idx);
375
376 if (!c2c.symbol_full)
377 width = MIN(width, SYMBOL_WIDTH);
378
379 return width;
380}
381
Jiri Olsac75540e2016-09-22 17:36:41 +0200382static int c2c_width(struct perf_hpp_fmt *fmt,
383 struct perf_hpp *hpp __maybe_unused,
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -0300384 struct hists *hists)
Jiri Olsac75540e2016-09-22 17:36:41 +0200385{
386 struct c2c_fmt *c2c_fmt;
Jiri Olsac75540e2016-09-22 17:36:41 +0200387 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +0200388
389 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
390 dim = c2c_fmt->dim;
391
Jiri Olsa590b6a32016-07-10 16:25:15 +0200392 if (dim == &dim_symbol || dim == &dim_srcline)
393 return symbol_width(hists, dim->se);
394
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200395 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
396 c2c_fmt->dim->width;
397}
398
399static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
400 struct hists *hists, int line, int *span)
401{
402 struct perf_hpp_list *hpp_list = hists->hpp_list;
403 struct c2c_fmt *c2c_fmt;
404 struct c2c_dimension *dim;
405 const char *text = NULL;
406 int width = c2c_width(fmt, hpp, hists);
407
408 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
409 dim = c2c_fmt->dim;
410
411 if (dim->se) {
412 text = dim->header.line[line].text;
413 /* Use the last line from sort_entry if not defined. */
414 if (!text && (line == hpp_list->nr_header_lines - 1))
415 text = dim->se->se_header;
416 } else {
417 text = dim->header.line[line].text;
418
419 if (*span) {
420 (*span)--;
421 return 0;
422 } else {
423 *span = dim->header.line[line].span;
424 }
425 }
426
Jiri Olsac75540e2016-09-22 17:36:41 +0200427 if (text == NULL)
428 text = "";
429
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200430 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
Jiri Olsac75540e2016-09-22 17:36:41 +0200431}
432
Jiri Olsacbb88502016-09-22 17:36:48 +0200433#define HEX_STR(__s, __v) \
434({ \
435 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
436 __s; \
437})
438
439static int64_t
440dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
441 struct hist_entry *left, struct hist_entry *right)
442{
443 return sort__dcacheline_cmp(left, right);
444}
445
446static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
447 struct hist_entry *he)
448{
449 uint64_t addr = 0;
450 int width = c2c_width(fmt, hpp, he->hists);
451 char buf[20];
452
453 if (he->mem_info)
454 addr = cl_address(he->mem_info->daddr.addr);
455
456 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
457}
458
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200459static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
460 struct hist_entry *he)
461{
462 uint64_t addr = 0;
463 int width = c2c_width(fmt, hpp, he->hists);
464 char buf[20];
465
466 if (he->mem_info)
467 addr = cl_offset(he->mem_info->daddr.al_addr);
468
469 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
470}
471
472static int64_t
473offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
474 struct hist_entry *left, struct hist_entry *right)
475{
476 uint64_t l = 0, r = 0;
477
478 if (left->mem_info)
479 l = cl_offset(left->mem_info->daddr.addr);
480 if (right->mem_info)
481 r = cl_offset(right->mem_info->daddr.addr);
482
483 return (int64_t)(r - l);
484}
485
Jiri Olsa43575a92016-05-03 21:48:56 +0200486static int
487iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
488 struct hist_entry *he)
489{
490 uint64_t addr = 0;
491 int width = c2c_width(fmt, hpp, he->hists);
492 char buf[20];
493
494 if (he->mem_info)
495 addr = he->mem_info->iaddr.addr;
496
497 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
498}
499
500static int64_t
501iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
502 struct hist_entry *left, struct hist_entry *right)
503{
504 return sort__iaddr_cmp(left, right);
505}
506
Jiri Olsa97cb4862016-05-23 16:20:14 +0200507static int
508tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
509 struct hist_entry *he)
510{
511 struct c2c_hist_entry *c2c_he;
512 int width = c2c_width(fmt, hpp, he->hists);
513 unsigned int tot_hitm;
514
515 c2c_he = container_of(he, struct c2c_hist_entry, he);
516 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
517
518 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
519}
520
521static int64_t
522tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
523 struct hist_entry *left, struct hist_entry *right)
524{
525 struct c2c_hist_entry *c2c_left;
526 struct c2c_hist_entry *c2c_right;
527 unsigned int tot_hitm_left;
528 unsigned int tot_hitm_right;
529
530 c2c_left = container_of(left, struct c2c_hist_entry, he);
531 c2c_right = container_of(right, struct c2c_hist_entry, he);
532
533 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
534 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
535
536 return tot_hitm_left - tot_hitm_right;
537}
538
539#define STAT_FN_ENTRY(__f) \
540static int \
541__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
542 struct hist_entry *he) \
543{ \
544 struct c2c_hist_entry *c2c_he; \
545 int width = c2c_width(fmt, hpp, he->hists); \
546 \
547 c2c_he = container_of(he, struct c2c_hist_entry, he); \
548 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
549 c2c_he->stats.__f); \
550}
551
552#define STAT_FN_CMP(__f) \
553static int64_t \
554__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
555 struct hist_entry *left, struct hist_entry *right) \
556{ \
557 struct c2c_hist_entry *c2c_left, *c2c_right; \
558 \
559 c2c_left = container_of(left, struct c2c_hist_entry, he); \
560 c2c_right = container_of(right, struct c2c_hist_entry, he); \
561 return c2c_left->stats.__f - c2c_right->stats.__f; \
562}
563
564#define STAT_FN(__f) \
565 STAT_FN_ENTRY(__f) \
566 STAT_FN_CMP(__f)
567
568STAT_FN(rmt_hitm)
569STAT_FN(lcl_hitm)
Jiri Olsa0f188962016-05-04 10:10:11 +0200570STAT_FN(store)
571STAT_FN(st_l1hit)
572STAT_FN(st_l1miss)
Jiri Olsa1295f682016-05-04 10:18:24 +0200573STAT_FN(ld_fbhit)
574STAT_FN(ld_l1hit)
575STAT_FN(ld_l2hit)
Jiri Olsa4d089102016-05-04 10:27:51 +0200576STAT_FN(ld_llchit)
577STAT_FN(rmt_hit)
Jiri Olsa97cb4862016-05-23 16:20:14 +0200578
Jiri Olsa04402d22016-05-19 10:10:51 +0200579static uint64_t llc_miss(struct c2c_stats *stats)
580{
581 uint64_t llcmiss;
582
583 llcmiss = stats->lcl_dram +
584 stats->rmt_dram +
585 stats->rmt_hitm +
586 stats->rmt_hit;
587
588 return llcmiss;
589}
590
591static int
592ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
593 struct hist_entry *he)
594{
595 struct c2c_hist_entry *c2c_he;
596 int width = c2c_width(fmt, hpp, he->hists);
597
598 c2c_he = container_of(he, struct c2c_hist_entry, he);
599
600 return scnprintf(hpp->buf, hpp->size, "%*lu", width,
601 llc_miss(&c2c_he->stats));
602}
603
604static int64_t
605ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
606 struct hist_entry *left, struct hist_entry *right)
607{
608 struct c2c_hist_entry *c2c_left;
609 struct c2c_hist_entry *c2c_right;
610
611 c2c_left = container_of(left, struct c2c_hist_entry, he);
612 c2c_right = container_of(right, struct c2c_hist_entry, he);
613
614 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
615}
616
Jiri Olsa01b84d72016-05-04 10:35:29 +0200617static uint64_t total_records(struct c2c_stats *stats)
618{
619 uint64_t lclmiss, ldcnt, total;
620
621 lclmiss = stats->lcl_dram +
622 stats->rmt_dram +
623 stats->rmt_hitm +
624 stats->rmt_hit;
625
626 ldcnt = lclmiss +
627 stats->ld_fbhit +
628 stats->ld_l1hit +
629 stats->ld_l2hit +
630 stats->ld_llchit +
631 stats->lcl_hitm;
632
633 total = ldcnt +
634 stats->st_l1hit +
635 stats->st_l1miss;
636
637 return total;
638}
639
640static int
641tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
642 struct hist_entry *he)
643{
644 struct c2c_hist_entry *c2c_he;
645 int width = c2c_width(fmt, hpp, he->hists);
646 uint64_t tot_recs;
647
648 c2c_he = container_of(he, struct c2c_hist_entry, he);
649 tot_recs = total_records(&c2c_he->stats);
650
651 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
652}
653
654static int64_t
655tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
656 struct hist_entry *left, struct hist_entry *right)
657{
658 struct c2c_hist_entry *c2c_left;
659 struct c2c_hist_entry *c2c_right;
660 uint64_t tot_recs_left;
661 uint64_t tot_recs_right;
662
663 c2c_left = container_of(left, struct c2c_hist_entry, he);
664 c2c_right = container_of(right, struct c2c_hist_entry, he);
665
666 tot_recs_left = total_records(&c2c_left->stats);
667 tot_recs_right = total_records(&c2c_right->stats);
668
669 return tot_recs_left - tot_recs_right;
670}
671
Jiri Olsa55177c42016-05-19 09:52:37 +0200672static uint64_t total_loads(struct c2c_stats *stats)
673{
674 uint64_t lclmiss, ldcnt;
675
676 lclmiss = stats->lcl_dram +
677 stats->rmt_dram +
678 stats->rmt_hitm +
679 stats->rmt_hit;
680
681 ldcnt = lclmiss +
682 stats->ld_fbhit +
683 stats->ld_l1hit +
684 stats->ld_l2hit +
685 stats->ld_llchit +
686 stats->lcl_hitm;
687
688 return ldcnt;
689}
690
691static int
692tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
693 struct hist_entry *he)
694{
695 struct c2c_hist_entry *c2c_he;
696 int width = c2c_width(fmt, hpp, he->hists);
697 uint64_t tot_recs;
698
699 c2c_he = container_of(he, struct c2c_hist_entry, he);
700 tot_recs = total_loads(&c2c_he->stats);
701
702 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
703}
704
705static int64_t
706tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
707 struct hist_entry *left, struct hist_entry *right)
708{
709 struct c2c_hist_entry *c2c_left;
710 struct c2c_hist_entry *c2c_right;
711 uint64_t tot_recs_left;
712 uint64_t tot_recs_right;
713
714 c2c_left = container_of(left, struct c2c_hist_entry, he);
715 c2c_right = container_of(right, struct c2c_hist_entry, he);
716
717 tot_recs_left = total_loads(&c2c_left->stats);
718 tot_recs_right = total_loads(&c2c_right->stats);
719
720 return tot_recs_left - tot_recs_right;
721}
722
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200723typedef double (get_percent_cb)(struct c2c_hist_entry *);
724
725static int
726percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
727 struct hist_entry *he, get_percent_cb get_percent)
728{
729 struct c2c_hist_entry *c2c_he;
730 int width = c2c_width(fmt, hpp, he->hists);
731 double per;
732
733 c2c_he = container_of(he, struct c2c_hist_entry, he);
734 per = get_percent(c2c_he);
735
Jiri Olsa5a1a99c2016-01-06 16:59:02 +0100736#ifdef HAVE_SLANG_SUPPORT
737 if (use_browser)
738 return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
739#endif
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200740 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
741}
742
743static double percent_hitm(struct c2c_hist_entry *c2c_he)
744{
745 struct c2c_hists *hists;
746 struct c2c_stats *stats;
747 struct c2c_stats *total;
Jiri Olsa55b95772016-05-29 10:21:45 +0200748 int tot = 0, st = 0;
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200749 double p;
750
751 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
752 stats = &c2c_he->stats;
753 total = &hists->stats;
754
Jiri Olsa55b95772016-05-29 10:21:45 +0200755 switch (c2c.display) {
756 case DISPLAY_RMT:
757 st = stats->rmt_hitm;
758 tot = total->rmt_hitm;
759 break;
760 case DISPLAY_LCL:
761 st = stats->lcl_hitm;
762 tot = total->lcl_hitm;
Jiri Olsad940bac2016-11-21 22:33:30 +0100763 break;
764 case DISPLAY_TOT:
765 st = stats->tot_hitm;
766 tot = total->tot_hitm;
Jiri Olsa55b95772016-05-29 10:21:45 +0200767 default:
768 break;
769 }
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200770
771 p = tot ? (double) st / tot : 0;
772
773 return 100 * p;
774}
775
776#define PERC_STR(__s, __v) \
777({ \
778 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
779 __s; \
780})
781
782static int
783percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
784 struct hist_entry *he)
785{
786 struct c2c_hist_entry *c2c_he;
787 int width = c2c_width(fmt, hpp, he->hists);
788 char buf[10];
789 double per;
790
791 c2c_he = container_of(he, struct c2c_hist_entry, he);
792 per = percent_hitm(c2c_he);
793 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
794}
795
796static int
797percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
798 struct hist_entry *he)
799{
800 return percent_color(fmt, hpp, he, percent_hitm);
801}
802
803static int64_t
804percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
805 struct hist_entry *left, struct hist_entry *right)
806{
807 struct c2c_hist_entry *c2c_left;
808 struct c2c_hist_entry *c2c_right;
809 double per_left;
810 double per_right;
811
812 c2c_left = container_of(left, struct c2c_hist_entry, he);
813 c2c_right = container_of(right, struct c2c_hist_entry, he);
814
815 per_left = percent_hitm(c2c_left);
816 per_right = percent_hitm(c2c_right);
817
818 return per_left - per_right;
819}
820
Jiri Olsa9cb35002016-05-04 12:16:50 +0200821static struct c2c_stats *he_stats(struct hist_entry *he)
822{
823 struct c2c_hist_entry *c2c_he;
824
825 c2c_he = container_of(he, struct c2c_hist_entry, he);
826 return &c2c_he->stats;
827}
828
829static struct c2c_stats *total_stats(struct hist_entry *he)
830{
831 struct c2c_hists *hists;
832
833 hists = container_of(he->hists, struct c2c_hists, hists);
834 return &hists->stats;
835}
836
837static double percent(int st, int tot)
838{
839 return tot ? 100. * (double) st / (double) tot : 0;
840}
841
842#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
843
844#define PERCENT_FN(__f) \
845static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
846{ \
847 struct c2c_hists *hists; \
848 \
849 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
850 return percent(c2c_he->stats.__f, hists->stats.__f); \
851}
852
853PERCENT_FN(rmt_hitm)
854PERCENT_FN(lcl_hitm)
855PERCENT_FN(st_l1hit)
856PERCENT_FN(st_l1miss)
857
858static int
859percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
860 struct hist_entry *he)
861{
862 int width = c2c_width(fmt, hpp, he->hists);
863 double per = PERCENT(he, rmt_hitm);
864 char buf[10];
865
866 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
867}
868
869static int
870percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
871 struct hist_entry *he)
872{
873 return percent_color(fmt, hpp, he, percent_rmt_hitm);
874}
875
876static int64_t
877percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
878 struct hist_entry *left, struct hist_entry *right)
879{
880 double per_left;
881 double per_right;
882
883 per_left = PERCENT(left, lcl_hitm);
884 per_right = PERCENT(right, lcl_hitm);
885
886 return per_left - per_right;
887}
888
889static int
890percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
891 struct hist_entry *he)
892{
893 int width = c2c_width(fmt, hpp, he->hists);
894 double per = PERCENT(he, lcl_hitm);
895 char buf[10];
896
897 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
898}
899
900static int
901percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
902 struct hist_entry *he)
903{
904 return percent_color(fmt, hpp, he, percent_lcl_hitm);
905}
906
907static int64_t
908percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
909 struct hist_entry *left, struct hist_entry *right)
910{
911 double per_left;
912 double per_right;
913
914 per_left = PERCENT(left, lcl_hitm);
915 per_right = PERCENT(right, lcl_hitm);
916
917 return per_left - per_right;
918}
919
920static int
921percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
922 struct hist_entry *he)
923{
924 int width = c2c_width(fmt, hpp, he->hists);
925 double per = PERCENT(he, st_l1hit);
926 char buf[10];
927
928 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
929}
930
931static int
932percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
933 struct hist_entry *he)
934{
935 return percent_color(fmt, hpp, he, percent_st_l1hit);
936}
937
938static int64_t
939percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
940 struct hist_entry *left, struct hist_entry *right)
941{
942 double per_left;
943 double per_right;
944
945 per_left = PERCENT(left, st_l1hit);
946 per_right = PERCENT(right, st_l1hit);
947
948 return per_left - per_right;
949}
950
951static int
952percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
953 struct hist_entry *he)
954{
955 int width = c2c_width(fmt, hpp, he->hists);
956 double per = PERCENT(he, st_l1miss);
957 char buf[10];
958
959 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
960}
961
962static int
963percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
964 struct hist_entry *he)
965{
966 return percent_color(fmt, hpp, he, percent_st_l1miss);
967}
968
969static int64_t
970percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
971 struct hist_entry *left, struct hist_entry *right)
972{
973 double per_left;
974 double per_right;
975
976 per_left = PERCENT(left, st_l1miss);
977 per_right = PERCENT(right, st_l1miss);
978
979 return per_left - per_right;
980}
981
Jiri Olsa6c70f542016-05-28 12:30:13 +0200982STAT_FN(lcl_dram)
983STAT_FN(rmt_dram)
984
Jiri Olsa36d3deb2016-05-24 13:09:47 +0200985static int
986pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
987 struct hist_entry *he)
988{
989 int width = c2c_width(fmt, hpp, he->hists);
990
991 return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
992}
993
994static int64_t
995pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
996 struct hist_entry *left, struct hist_entry *right)
997{
998 return left->thread->pid_ - right->thread->pid_;
999}
1000
Jiri Olsa1e181b92016-06-03 15:40:28 +02001001static int64_t
1002empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1003 struct hist_entry *left __maybe_unused,
1004 struct hist_entry *right __maybe_unused)
1005{
1006 return 0;
1007}
1008
1009static int
1010node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1011 struct hist_entry *he)
1012{
1013 struct c2c_hist_entry *c2c_he;
1014 bool first = true;
1015 int node;
1016 int ret = 0;
1017
1018 c2c_he = container_of(he, struct c2c_hist_entry, he);
1019
1020 for (node = 0; node < c2c.nodes_cnt; node++) {
1021 DECLARE_BITMAP(set, c2c.cpus_cnt);
1022
1023 bitmap_zero(set, c2c.cpus_cnt);
1024 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
1025
1026 if (!bitmap_weight(set, c2c.cpus_cnt)) {
1027 if (c2c.node_info == 1) {
1028 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
1029 advance_hpp(hpp, ret);
1030 }
1031 continue;
1032 }
1033
1034 if (!first) {
1035 ret = scnprintf(hpp->buf, hpp->size, " ");
1036 advance_hpp(hpp, ret);
1037 }
1038
1039 switch (c2c.node_info) {
1040 case 0:
1041 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
1042 advance_hpp(hpp, ret);
1043 break;
1044 case 1:
1045 {
1046 int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
1047 struct c2c_stats *stats = &c2c_he->node_stats[node];
1048
1049 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
1050 advance_hpp(hpp, ret);
1051
Jiri Olsa55b95772016-05-29 10:21:45 +02001052 #define DISPLAY_HITM(__h) \
1053 if (c2c_he->stats.__h> 0) { \
1054 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", \
1055 percent(stats->__h, c2c_he->stats.__h));\
1056 } else { \
1057 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); \
Jiri Olsa1e181b92016-06-03 15:40:28 +02001058 }
1059
Jiri Olsa55b95772016-05-29 10:21:45 +02001060 switch (c2c.display) {
1061 case DISPLAY_RMT:
1062 DISPLAY_HITM(rmt_hitm);
1063 break;
1064 case DISPLAY_LCL:
1065 DISPLAY_HITM(lcl_hitm);
Jiri Olsad940bac2016-11-21 22:33:30 +01001066 break;
1067 case DISPLAY_TOT:
1068 DISPLAY_HITM(tot_hitm);
Jiri Olsa55b95772016-05-29 10:21:45 +02001069 default:
1070 break;
1071 }
1072
1073 #undef DISPLAY_HITM
1074
Jiri Olsa1e181b92016-06-03 15:40:28 +02001075 advance_hpp(hpp, ret);
1076
1077 if (c2c_he->stats.store > 0) {
1078 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
1079 percent(stats->store, c2c_he->stats.store));
1080 } else {
1081 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
1082 }
1083
1084 advance_hpp(hpp, ret);
1085 break;
1086 }
1087 case 2:
1088 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
1089 advance_hpp(hpp, ret);
1090
1091 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
1092 advance_hpp(hpp, ret);
1093
1094 ret = scnprintf(hpp->buf, hpp->size, "}");
1095 advance_hpp(hpp, ret);
1096 break;
1097 default:
1098 break;
1099 }
1100
1101 first = false;
1102 }
1103
1104 return 0;
1105}
1106
Jiri Olsa92062d52016-06-05 13:40:53 +02001107static int
1108mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1109 struct hist_entry *he, double mean)
1110{
1111 int width = c2c_width(fmt, hpp, he->hists);
1112 char buf[10];
1113
1114 scnprintf(buf, 10, "%6.0f", mean);
1115 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1116}
1117
1118#define MEAN_ENTRY(__func, __val) \
1119static int \
1120__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1121{ \
1122 struct c2c_hist_entry *c2c_he; \
1123 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1124 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1125}
1126
1127MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1128MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1129MEAN_ENTRY(mean_load_entry, load);
1130
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001131static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001132cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001133 struct hist_entry *he)
1134{
1135 struct c2c_hist_entry *c2c_he;
1136 int width = c2c_width(fmt, hpp, he->hists);
1137 char buf[10];
1138
1139 c2c_he = container_of(he, struct c2c_hist_entry, he);
1140
1141 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1142 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1143}
1144
Jiri Olsabb342da2016-07-06 15:40:09 +02001145static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001146cl_idx_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsabb342da2016-07-06 15:40:09 +02001147 struct hist_entry *he)
1148{
1149 struct c2c_hist_entry *c2c_he;
1150 int width = c2c_width(fmt, hpp, he->hists);
1151 char buf[10];
1152
1153 c2c_he = container_of(he, struct c2c_hist_entry, he);
1154
1155 scnprintf(buf, 10, "%u", c2c_he->cacheline_idx);
1156 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1157}
1158
1159static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001160cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsabb342da2016-07-06 15:40:09 +02001161 struct hist_entry *he)
1162{
1163 int width = c2c_width(fmt, hpp, he->hists);
1164
1165 return scnprintf(hpp->buf, hpp->size, "%*s", width, "");
1166}
1167
Jiri Olsa600a8cf2016-09-22 17:36:47 +02001168#define HEADER_LOW(__h) \
1169 { \
1170 .line[1] = { \
1171 .text = __h, \
1172 }, \
1173 }
1174
1175#define HEADER_BOTH(__h0, __h1) \
1176 { \
1177 .line[0] = { \
1178 .text = __h0, \
1179 }, \
1180 .line[1] = { \
1181 .text = __h1, \
1182 }, \
1183 }
1184
1185#define HEADER_SPAN(__h0, __h1, __s) \
1186 { \
1187 .line[0] = { \
1188 .text = __h0, \
1189 .span = __s, \
1190 }, \
1191 .line[1] = { \
1192 .text = __h1, \
1193 }, \
1194 }
1195
1196#define HEADER_SPAN_LOW(__h) \
1197 { \
1198 .line[1] = { \
1199 .text = __h, \
1200 }, \
1201 }
1202
Jiri Olsacbb88502016-09-22 17:36:48 +02001203static struct c2c_dimension dim_dcacheline = {
1204 .header = HEADER_LOW("Cacheline"),
1205 .name = "dcacheline",
1206 .cmp = dcacheline_cmp,
1207 .entry = dcacheline_entry,
1208 .width = 18,
1209};
1210
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001211static struct c2c_header header_offset_tui = HEADER_LOW("Off");
1212
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001213static struct c2c_dimension dim_offset = {
1214 .header = HEADER_BOTH("Data address", "Offset"),
1215 .name = "offset",
1216 .cmp = offset_cmp,
1217 .entry = offset_entry,
1218 .width = 18,
1219};
1220
Jiri Olsa43575a92016-05-03 21:48:56 +02001221static struct c2c_dimension dim_iaddr = {
1222 .header = HEADER_LOW("Code address"),
1223 .name = "iaddr",
1224 .cmp = iaddr_cmp,
1225 .entry = iaddr_entry,
1226 .width = 18,
1227};
1228
Jiri Olsa97cb4862016-05-23 16:20:14 +02001229static struct c2c_dimension dim_tot_hitm = {
1230 .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1231 .name = "tot_hitm",
1232 .cmp = tot_hitm_cmp,
1233 .entry = tot_hitm_entry,
1234 .width = 7,
1235};
1236
1237static struct c2c_dimension dim_lcl_hitm = {
1238 .header = HEADER_SPAN_LOW("Lcl"),
1239 .name = "lcl_hitm",
1240 .cmp = lcl_hitm_cmp,
1241 .entry = lcl_hitm_entry,
1242 .width = 7,
1243};
1244
1245static struct c2c_dimension dim_rmt_hitm = {
1246 .header = HEADER_SPAN_LOW("Rmt"),
1247 .name = "rmt_hitm",
1248 .cmp = rmt_hitm_cmp,
1249 .entry = rmt_hitm_entry,
1250 .width = 7,
1251};
1252
1253static struct c2c_dimension dim_cl_rmt_hitm = {
1254 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1255 .name = "cl_rmt_hitm",
1256 .cmp = rmt_hitm_cmp,
1257 .entry = rmt_hitm_entry,
1258 .width = 7,
1259};
1260
1261static struct c2c_dimension dim_cl_lcl_hitm = {
1262 .header = HEADER_SPAN_LOW("Lcl"),
1263 .name = "cl_lcl_hitm",
1264 .cmp = lcl_hitm_cmp,
1265 .entry = lcl_hitm_entry,
1266 .width = 7,
1267};
1268
Jiri Olsa0f188962016-05-04 10:10:11 +02001269static struct c2c_dimension dim_stores = {
1270 .header = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1271 .name = "stores",
1272 .cmp = store_cmp,
1273 .entry = store_entry,
1274 .width = 7,
1275};
1276
1277static struct c2c_dimension dim_stores_l1hit = {
1278 .header = HEADER_SPAN_LOW("L1Hit"),
1279 .name = "stores_l1hit",
1280 .cmp = st_l1hit_cmp,
1281 .entry = st_l1hit_entry,
1282 .width = 7,
1283};
1284
1285static struct c2c_dimension dim_stores_l1miss = {
1286 .header = HEADER_SPAN_LOW("L1Miss"),
1287 .name = "stores_l1miss",
1288 .cmp = st_l1miss_cmp,
1289 .entry = st_l1miss_entry,
1290 .width = 7,
1291};
1292
1293static struct c2c_dimension dim_cl_stores_l1hit = {
1294 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1295 .name = "cl_stores_l1hit",
1296 .cmp = st_l1hit_cmp,
1297 .entry = st_l1hit_entry,
1298 .width = 7,
1299};
1300
1301static struct c2c_dimension dim_cl_stores_l1miss = {
1302 .header = HEADER_SPAN_LOW("L1 Miss"),
1303 .name = "cl_stores_l1miss",
1304 .cmp = st_l1miss_cmp,
1305 .entry = st_l1miss_entry,
1306 .width = 7,
1307};
1308
Jiri Olsa1295f682016-05-04 10:18:24 +02001309static struct c2c_dimension dim_ld_fbhit = {
1310 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1311 .name = "ld_fbhit",
1312 .cmp = ld_fbhit_cmp,
1313 .entry = ld_fbhit_entry,
1314 .width = 7,
1315};
1316
1317static struct c2c_dimension dim_ld_l1hit = {
1318 .header = HEADER_SPAN_LOW("L1"),
1319 .name = "ld_l1hit",
1320 .cmp = ld_l1hit_cmp,
1321 .entry = ld_l1hit_entry,
1322 .width = 7,
1323};
1324
1325static struct c2c_dimension dim_ld_l2hit = {
1326 .header = HEADER_SPAN_LOW("L2"),
1327 .name = "ld_l2hit",
1328 .cmp = ld_l2hit_cmp,
1329 .entry = ld_l2hit_entry,
1330 .width = 7,
1331};
1332
Jiri Olsa4d089102016-05-04 10:27:51 +02001333static struct c2c_dimension dim_ld_llchit = {
1334 .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1335 .name = "ld_lclhit",
1336 .cmp = ld_llchit_cmp,
1337 .entry = ld_llchit_entry,
1338 .width = 8,
1339};
1340
1341static struct c2c_dimension dim_ld_rmthit = {
1342 .header = HEADER_SPAN_LOW("Rmt"),
1343 .name = "ld_rmthit",
1344 .cmp = rmt_hit_cmp,
1345 .entry = rmt_hit_entry,
1346 .width = 8,
1347};
1348
Jiri Olsa04402d22016-05-19 10:10:51 +02001349static struct c2c_dimension dim_ld_llcmiss = {
1350 .header = HEADER_BOTH("LLC", "Ld Miss"),
1351 .name = "ld_llcmiss",
1352 .cmp = ld_llcmiss_cmp,
1353 .entry = ld_llcmiss_entry,
1354 .width = 7,
1355};
1356
Jiri Olsa01b84d72016-05-04 10:35:29 +02001357static struct c2c_dimension dim_tot_recs = {
1358 .header = HEADER_BOTH("Total", "records"),
1359 .name = "tot_recs",
1360 .cmp = tot_recs_cmp,
1361 .entry = tot_recs_entry,
1362 .width = 7,
1363};
1364
Jiri Olsa55177c42016-05-19 09:52:37 +02001365static struct c2c_dimension dim_tot_loads = {
1366 .header = HEADER_BOTH("Total", "Loads"),
1367 .name = "tot_loads",
1368 .cmp = tot_loads_cmp,
1369 .entry = tot_loads_entry,
1370 .width = 7,
1371};
1372
Jiri Olsa55b95772016-05-29 10:21:45 +02001373static struct c2c_header percent_hitm_header[] = {
1374 [DISPLAY_LCL] = HEADER_BOTH("Lcl", "Hitm"),
1375 [DISPLAY_RMT] = HEADER_BOTH("Rmt", "Hitm"),
Jiri Olsad940bac2016-11-21 22:33:30 +01001376 [DISPLAY_TOT] = HEADER_BOTH("Tot", "Hitm"),
Jiri Olsa55b95772016-05-29 10:21:45 +02001377};
1378
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001379static struct c2c_dimension dim_percent_hitm = {
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001380 .name = "percent_hitm",
1381 .cmp = percent_hitm_cmp,
1382 .entry = percent_hitm_entry,
1383 .color = percent_hitm_color,
1384 .width = 7,
1385};
1386
Jiri Olsa9cb35002016-05-04 12:16:50 +02001387static struct c2c_dimension dim_percent_rmt_hitm = {
1388 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1389 .name = "percent_rmt_hitm",
1390 .cmp = percent_rmt_hitm_cmp,
1391 .entry = percent_rmt_hitm_entry,
1392 .color = percent_rmt_hitm_color,
1393 .width = 7,
1394};
1395
1396static struct c2c_dimension dim_percent_lcl_hitm = {
1397 .header = HEADER_SPAN_LOW("Lcl"),
1398 .name = "percent_lcl_hitm",
1399 .cmp = percent_lcl_hitm_cmp,
1400 .entry = percent_lcl_hitm_entry,
1401 .color = percent_lcl_hitm_color,
1402 .width = 7,
1403};
1404
1405static struct c2c_dimension dim_percent_stores_l1hit = {
1406 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1407 .name = "percent_stores_l1hit",
1408 .cmp = percent_stores_l1hit_cmp,
1409 .entry = percent_stores_l1hit_entry,
1410 .color = percent_stores_l1hit_color,
1411 .width = 7,
1412};
1413
1414static struct c2c_dimension dim_percent_stores_l1miss = {
1415 .header = HEADER_SPAN_LOW("L1 Miss"),
1416 .name = "percent_stores_l1miss",
1417 .cmp = percent_stores_l1miss_cmp,
1418 .entry = percent_stores_l1miss_entry,
1419 .color = percent_stores_l1miss_color,
1420 .width = 7,
1421};
1422
Jiri Olsa6c70f542016-05-28 12:30:13 +02001423static struct c2c_dimension dim_dram_lcl = {
1424 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1425 .name = "dram_lcl",
1426 .cmp = lcl_dram_cmp,
1427 .entry = lcl_dram_entry,
1428 .width = 8,
1429};
1430
1431static struct c2c_dimension dim_dram_rmt = {
1432 .header = HEADER_SPAN_LOW("Rmt"),
1433 .name = "dram_rmt",
1434 .cmp = rmt_dram_cmp,
1435 .entry = rmt_dram_entry,
1436 .width = 8,
1437};
1438
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001439static struct c2c_dimension dim_pid = {
1440 .header = HEADER_LOW("Pid"),
1441 .name = "pid",
1442 .cmp = pid_cmp,
1443 .entry = pid_entry,
1444 .width = 7,
1445};
1446
Jiri Olsae87019c2016-05-25 08:50:10 +02001447static struct c2c_dimension dim_tid = {
1448 .header = HEADER_LOW("Tid"),
1449 .name = "tid",
1450 .se = &sort_thread,
1451};
1452
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001453static struct c2c_dimension dim_symbol = {
1454 .name = "symbol",
1455 .se = &sort_sym,
1456};
1457
1458static struct c2c_dimension dim_dso = {
1459 .header = HEADER_BOTH("Shared", "Object"),
1460 .name = "dso",
1461 .se = &sort_dso,
1462};
1463
Jiri Olsa1e181b92016-06-03 15:40:28 +02001464static struct c2c_header header_node[3] = {
1465 HEADER_LOW("Node"),
1466 HEADER_LOW("Node{cpus %hitms %stores}"),
1467 HEADER_LOW("Node{cpu list}"),
1468};
1469
1470static struct c2c_dimension dim_node = {
1471 .name = "node",
1472 .cmp = empty_cmp,
1473 .entry = node_entry,
1474 .width = 4,
1475};
1476
Jiri Olsa92062d52016-06-05 13:40:53 +02001477static struct c2c_dimension dim_mean_rmt = {
1478 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1479 .name = "mean_rmt",
1480 .cmp = empty_cmp,
1481 .entry = mean_rmt_entry,
1482 .width = 8,
1483};
1484
1485static struct c2c_dimension dim_mean_lcl = {
1486 .header = HEADER_SPAN_LOW("lcl hitm"),
1487 .name = "mean_lcl",
1488 .cmp = empty_cmp,
1489 .entry = mean_lcl_entry,
1490 .width = 8,
1491};
1492
1493static struct c2c_dimension dim_mean_load = {
1494 .header = HEADER_SPAN_LOW("load"),
1495 .name = "mean_load",
1496 .cmp = empty_cmp,
1497 .entry = mean_load_entry,
1498 .width = 8,
1499};
1500
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001501static struct c2c_dimension dim_cpucnt = {
1502 .header = HEADER_BOTH("cpu", "cnt"),
1503 .name = "cpucnt",
1504 .cmp = empty_cmp,
1505 .entry = cpucnt_entry,
1506 .width = 8,
1507};
1508
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001509static struct c2c_dimension dim_srcline = {
1510 .name = "cl_srcline",
1511 .se = &sort_srcline,
1512};
1513
Jiri Olsabb342da2016-07-06 15:40:09 +02001514static struct c2c_dimension dim_dcacheline_idx = {
1515 .header = HEADER_LOW("Index"),
1516 .name = "cl_idx",
1517 .cmp = empty_cmp,
1518 .entry = cl_idx_entry,
1519 .width = 5,
1520};
1521
1522static struct c2c_dimension dim_dcacheline_num = {
1523 .header = HEADER_LOW("Num"),
1524 .name = "cl_num",
1525 .cmp = empty_cmp,
1526 .entry = cl_idx_entry,
1527 .width = 5,
1528};
1529
1530static struct c2c_dimension dim_dcacheline_num_empty = {
1531 .header = HEADER_LOW("Num"),
1532 .name = "cl_num_empty",
1533 .cmp = empty_cmp,
1534 .entry = cl_idx_empty_entry,
1535 .width = 5,
1536};
1537
Jiri Olsac75540e2016-09-22 17:36:41 +02001538static struct c2c_dimension *dimensions[] = {
Jiri Olsacbb88502016-09-22 17:36:48 +02001539 &dim_dcacheline,
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001540 &dim_offset,
Jiri Olsa43575a92016-05-03 21:48:56 +02001541 &dim_iaddr,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001542 &dim_tot_hitm,
1543 &dim_lcl_hitm,
1544 &dim_rmt_hitm,
1545 &dim_cl_lcl_hitm,
1546 &dim_cl_rmt_hitm,
Jiri Olsa0f188962016-05-04 10:10:11 +02001547 &dim_stores,
1548 &dim_stores_l1hit,
1549 &dim_stores_l1miss,
1550 &dim_cl_stores_l1hit,
1551 &dim_cl_stores_l1miss,
Jiri Olsa1295f682016-05-04 10:18:24 +02001552 &dim_ld_fbhit,
1553 &dim_ld_l1hit,
1554 &dim_ld_l2hit,
Jiri Olsa4d089102016-05-04 10:27:51 +02001555 &dim_ld_llchit,
1556 &dim_ld_rmthit,
Jiri Olsa04402d22016-05-19 10:10:51 +02001557 &dim_ld_llcmiss,
Jiri Olsa01b84d72016-05-04 10:35:29 +02001558 &dim_tot_recs,
Jiri Olsa55177c42016-05-19 09:52:37 +02001559 &dim_tot_loads,
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001560 &dim_percent_hitm,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001561 &dim_percent_rmt_hitm,
1562 &dim_percent_lcl_hitm,
1563 &dim_percent_stores_l1hit,
1564 &dim_percent_stores_l1miss,
Jiri Olsa6c70f542016-05-28 12:30:13 +02001565 &dim_dram_lcl,
1566 &dim_dram_rmt,
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001567 &dim_pid,
Jiri Olsae87019c2016-05-25 08:50:10 +02001568 &dim_tid,
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001569 &dim_symbol,
1570 &dim_dso,
Jiri Olsa1e181b92016-06-03 15:40:28 +02001571 &dim_node,
Jiri Olsa92062d52016-06-05 13:40:53 +02001572 &dim_mean_rmt,
1573 &dim_mean_lcl,
1574 &dim_mean_load,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001575 &dim_cpucnt,
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001576 &dim_srcline,
Jiri Olsabb342da2016-07-06 15:40:09 +02001577 &dim_dcacheline_idx,
1578 &dim_dcacheline_num,
1579 &dim_dcacheline_num_empty,
Jiri Olsac75540e2016-09-22 17:36:41 +02001580 NULL,
1581};
1582
1583static void fmt_free(struct perf_hpp_fmt *fmt)
1584{
1585 struct c2c_fmt *c2c_fmt;
1586
1587 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1588 free(c2c_fmt);
1589}
1590
1591static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1592{
1593 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1594 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1595
1596 return c2c_a->dim == c2c_b->dim;
1597}
1598
1599static struct c2c_dimension *get_dimension(const char *name)
1600{
1601 unsigned int i;
1602
1603 for (i = 0; dimensions[i]; i++) {
1604 struct c2c_dimension *dim = dimensions[i];
1605
1606 if (!strcmp(dim->name, name))
1607 return dim;
1608 };
1609
1610 return NULL;
1611}
1612
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001613static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1614 struct hist_entry *he)
1615{
1616 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1617 struct c2c_dimension *dim = c2c_fmt->dim;
1618 size_t len = fmt->user_len;
1619
Jiri Olsa590b6a32016-07-10 16:25:15 +02001620 if (!len) {
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001621 len = hists__col_len(he->hists, dim->se->se_width_idx);
1622
Jiri Olsa590b6a32016-07-10 16:25:15 +02001623 if (dim == &dim_symbol || dim == &dim_srcline)
1624 len = symbol_width(he->hists, dim->se);
1625 }
1626
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001627 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1628}
1629
1630static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1631 struct hist_entry *a, struct hist_entry *b)
1632{
1633 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1634 struct c2c_dimension *dim = c2c_fmt->dim;
1635
1636 return dim->se->se_cmp(a, b);
1637}
1638
1639static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1640 struct hist_entry *a, struct hist_entry *b)
1641{
1642 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1643 struct c2c_dimension *dim = c2c_fmt->dim;
1644 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1645
1646 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1647 return collapse_fn(a, b);
1648}
1649
Jiri Olsac75540e2016-09-22 17:36:41 +02001650static struct c2c_fmt *get_format(const char *name)
1651{
1652 struct c2c_dimension *dim = get_dimension(name);
1653 struct c2c_fmt *c2c_fmt;
1654 struct perf_hpp_fmt *fmt;
1655
1656 if (!dim)
1657 return NULL;
1658
1659 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1660 if (!c2c_fmt)
1661 return NULL;
1662
1663 c2c_fmt->dim = dim;
1664
1665 fmt = &c2c_fmt->fmt;
1666 INIT_LIST_HEAD(&fmt->list);
1667 INIT_LIST_HEAD(&fmt->sort_list);
1668
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001669 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1670 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
Jiri Olsa9cb35002016-05-04 12:16:50 +02001671 fmt->color = dim->se ? NULL : dim->color;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001672 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
Jiri Olsac75540e2016-09-22 17:36:41 +02001673 fmt->header = c2c_header;
1674 fmt->width = c2c_width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001675 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
Jiri Olsac75540e2016-09-22 17:36:41 +02001676 fmt->equal = fmt_equal;
1677 fmt->free = fmt_free;
1678
1679 return c2c_fmt;
1680}
1681
1682static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1683{
1684 struct c2c_fmt *c2c_fmt = get_format(name);
1685
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001686 if (!c2c_fmt) {
1687 reset_dimensions();
1688 return output_field_add(hpp_list, name);
1689 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001690
1691 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1692 return 0;
1693}
1694
1695static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1696{
1697 struct c2c_fmt *c2c_fmt = get_format(name);
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001698 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +02001699
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001700 if (!c2c_fmt) {
1701 reset_dimensions();
1702 return sort_dimension__add(hpp_list, name, NULL, 0);
1703 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001704
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001705 dim = c2c_fmt->dim;
1706 if (dim == &dim_dso)
1707 hpp_list->dso = 1;
1708
Jiri Olsac75540e2016-09-22 17:36:41 +02001709 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1710 return 0;
1711}
1712
1713#define PARSE_LIST(_list, _fn) \
1714 do { \
1715 char *tmp, *tok; \
1716 ret = 0; \
1717 \
1718 if (!_list) \
1719 break; \
1720 \
1721 for (tok = strtok_r((char *)_list, ", ", &tmp); \
1722 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
1723 ret = _fn(hpp_list, tok); \
1724 if (ret == -EINVAL) { \
1725 error("Invalid --fields key: `%s'", tok); \
1726 break; \
1727 } else if (ret == -ESRCH) { \
1728 error("Unknown --fields key: `%s'", tok); \
1729 break; \
1730 } \
1731 } \
1732 } while (0)
1733
1734static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1735 const char *output_,
1736 const char *sort_)
1737{
1738 char *output = output_ ? strdup(output_) : NULL;
1739 char *sort = sort_ ? strdup(sort_) : NULL;
1740 int ret;
1741
1742 PARSE_LIST(output, c2c_hists__init_output);
1743 PARSE_LIST(sort, c2c_hists__init_sort);
1744
1745 /* copy sort keys to output fields */
1746 perf_hpp__setup_output_field(hpp_list);
1747
1748 /*
1749 * We dont need other sorting keys other than those
1750 * we already specified. It also really slows down
1751 * the processing a lot with big number of output
1752 * fields, so switching this off for c2c.
1753 */
1754
1755#if 0
1756 /* and then copy output fields to sort keys */
1757 perf_hpp__append_sort_keys(&hists->list);
1758#endif
1759
1760 free(output);
1761 free(sort);
1762 return ret;
1763}
1764
1765static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001766 const char *sort,
1767 int nr_header_lines)
Jiri Olsac75540e2016-09-22 17:36:41 +02001768{
1769 __hists__init(&hists->hists, &hists->list);
1770
1771 /*
1772 * Initialize only with sort fields, we need to resort
1773 * later anyway, and that's where we add output fields
1774 * as well.
1775 */
1776 perf_hpp_list__init(&hists->list);
1777
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001778 /* Overload number of header lines.*/
1779 hists->list.nr_header_lines = nr_header_lines;
1780
Jiri Olsac75540e2016-09-22 17:36:41 +02001781 return hpp_list__parse(&hists->list, NULL, sort);
1782}
1783
Jiri Olsac75540e2016-09-22 17:36:41 +02001784static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1785 const char *output,
1786 const char *sort)
1787{
1788 perf_hpp__reset_output_field(&c2c_hists->list);
1789 return hpp_list__parse(&c2c_hists->list, output, sort);
1790}
1791
Jiri Olsa9857b712016-08-17 14:55:23 +02001792#define DISPLAY_LINE_LIMIT 0.0005
1793
1794static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
1795{
1796 struct c2c_hist_entry *c2c_he;
1797 double ld_dist;
1798
Jiri Olsaaf09b2d2016-10-11 13:52:05 +02001799 if (c2c.show_all)
1800 return true;
Jiri Olsa9857b712016-08-17 14:55:23 +02001801
1802 c2c_he = container_of(he, struct c2c_hist_entry, he);
1803
Jiri Olsa55b95772016-05-29 10:21:45 +02001804#define FILTER_HITM(__h) \
1805 if (stats->__h) { \
1806 ld_dist = ((double)c2c_he->stats.__h / stats->__h); \
1807 if (ld_dist < DISPLAY_LINE_LIMIT) \
1808 he->filtered = HIST_FILTER__C2C; \
1809 } else { \
1810 he->filtered = HIST_FILTER__C2C; \
Jiri Olsa9857b712016-08-17 14:55:23 +02001811 }
1812
Jiri Olsa55b95772016-05-29 10:21:45 +02001813 switch (c2c.display) {
1814 case DISPLAY_LCL:
1815 FILTER_HITM(lcl_hitm);
1816 break;
1817 case DISPLAY_RMT:
1818 FILTER_HITM(rmt_hitm);
Jiri Olsad940bac2016-11-21 22:33:30 +01001819 break;
1820 case DISPLAY_TOT:
1821 FILTER_HITM(tot_hitm);
Jiri Olsa55b95772016-05-29 10:21:45 +02001822 default:
1823 break;
1824 };
1825
1826#undef FILTER_HITM
1827
Jiri Olsa9857b712016-08-17 14:55:23 +02001828 return he->filtered == 0;
1829}
1830
1831static inline int valid_hitm_or_store(struct hist_entry *he)
1832{
1833 struct c2c_hist_entry *c2c_he;
Jiri Olsa55b95772016-05-29 10:21:45 +02001834 bool has_hitm;
Jiri Olsa9857b712016-08-17 14:55:23 +02001835
1836 c2c_he = container_of(he, struct c2c_hist_entry, he);
Jiri Olsad940bac2016-11-21 22:33:30 +01001837 has_hitm = c2c.display == DISPLAY_TOT ? c2c_he->stats.tot_hitm :
1838 c2c.display == DISPLAY_LCL ? c2c_he->stats.lcl_hitm :
1839 c2c_he->stats.rmt_hitm;
Jiri Olsa55b95772016-05-29 10:21:45 +02001840 return has_hitm || c2c_he->stats.store;
Jiri Olsa9857b712016-08-17 14:55:23 +02001841}
1842
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001843static void calc_width(struct hist_entry *he)
1844{
1845 struct c2c_hists *c2c_hists;
1846
1847 c2c_hists = container_of(he->hists, struct c2c_hists, hists);
1848 hists__calc_col_len(&c2c_hists->hists, he);
1849}
1850
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001851static int filter_cb(struct hist_entry *he)
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001852{
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001853 if (c2c.show_src && !he->srcline)
1854 he->srcline = hist_entry__get_srcline(he);
1855
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001856 calc_width(he);
1857
Jiri Olsa9857b712016-08-17 14:55:23 +02001858 if (!valid_hitm_or_store(he))
1859 he->filtered = HIST_FILTER__C2C;
1860
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001861 return 0;
1862}
1863
1864static int resort_cl_cb(struct hist_entry *he)
1865{
1866 struct c2c_hist_entry *c2c_he;
1867 struct c2c_hists *c2c_hists;
Jiri Olsa9857b712016-08-17 14:55:23 +02001868 bool display = he__display(he, &c2c.hitm_stats);
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001869
1870 c2c_he = container_of(he, struct c2c_hist_entry, he);
1871 c2c_hists = c2c_he->hists;
1872
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001873 calc_width(he);
1874
Jiri Olsa9857b712016-08-17 14:55:23 +02001875 if (display && c2c_hists) {
Jiri Olsabb342da2016-07-06 15:40:09 +02001876 static unsigned int idx;
1877
1878 c2c_he->cacheline_idx = idx++;
1879
Jiri Olsafc9c6302016-05-24 14:14:38 +02001880 c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort);
Jiri Olsa22dd59d2016-05-10 14:08:29 +02001881
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001882 hists__collapse_resort(&c2c_hists->hists, NULL);
1883 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
1884 }
1885
1886 return 0;
1887}
1888
Jiri Olsa1e181b92016-06-03 15:40:28 +02001889static void setup_nodes_header(void)
1890{
1891 dim_node.header = header_node[c2c.node_info];
1892}
1893
1894static int setup_nodes(struct perf_session *session)
1895{
1896 struct numa_node *n;
1897 unsigned long **nodes;
1898 int node, cpu;
1899 int *cpu2node;
1900
1901 if (c2c.node_info > 2)
1902 c2c.node_info = 2;
1903
1904 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1905 c2c.cpus_cnt = session->header.env.nr_cpus_online;
1906
1907 n = session->header.env.numa_nodes;
1908 if (!n)
1909 return -EINVAL;
1910
1911 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
1912 if (!nodes)
1913 return -ENOMEM;
1914
1915 c2c.nodes = nodes;
1916
1917 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
1918 if (!cpu2node)
1919 return -ENOMEM;
1920
1921 for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
1922 cpu2node[cpu] = -1;
1923
1924 c2c.cpu2node = cpu2node;
1925
1926 for (node = 0; node < c2c.nodes_cnt; node++) {
1927 struct cpu_map *map = n[node].map;
1928 unsigned long *set;
1929
1930 set = bitmap_alloc(c2c.cpus_cnt);
1931 if (!set)
1932 return -ENOMEM;
1933
1934 for (cpu = 0; cpu < map->nr; cpu++) {
1935 set_bit(map->map[cpu], set);
1936
1937 if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
1938 return -EINVAL;
1939
1940 cpu2node[map->map[cpu]] = node;
1941 }
1942
1943 nodes[node] = set;
1944 }
1945
1946 setup_nodes_header();
1947 return 0;
1948}
1949
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02001950#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
1951
1952static int resort_hitm_cb(struct hist_entry *he)
1953{
1954 struct c2c_hist_entry *c2c_he;
1955 c2c_he = container_of(he, struct c2c_hist_entry, he);
1956
1957 if (HAS_HITMS(c2c_he)) {
1958 c2c.shared_clines++;
1959 c2c_add_stats(&c2c.hitm_stats, &c2c_he->stats);
1960 }
1961
1962 return 0;
1963}
1964
1965static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
1966{
1967 struct rb_node *next = rb_first(&hists->entries);
1968 int ret = 0;
1969
1970 while (next) {
1971 struct hist_entry *he;
1972
1973 he = rb_entry(next, struct hist_entry, rb_node);
1974 ret = cb(he);
1975 if (ret)
1976 break;
1977 next = rb_next(&he->rb_node);
1978 }
1979
1980 return ret;
1981}
1982
Jiri Olsa74c63a22016-05-02 20:01:59 +02001983static void print_c2c__display_stats(FILE *out)
1984{
1985 int llc_misses;
1986 struct c2c_stats *stats = &c2c.hists.stats;
1987
1988 llc_misses = stats->lcl_dram +
1989 stats->rmt_dram +
1990 stats->rmt_hit +
1991 stats->rmt_hitm;
1992
1993 fprintf(out, "=================================================\n");
1994 fprintf(out, " Trace Event Information \n");
1995 fprintf(out, "=================================================\n");
1996 fprintf(out, " Total records : %10d\n", stats->nr_entries);
1997 fprintf(out, " Locked Load/Store Operations : %10d\n", stats->locks);
1998 fprintf(out, " Load Operations : %10d\n", stats->load);
1999 fprintf(out, " Loads - uncacheable : %10d\n", stats->ld_uncache);
2000 fprintf(out, " Loads - IO : %10d\n", stats->ld_io);
2001 fprintf(out, " Loads - Miss : %10d\n", stats->ld_miss);
2002 fprintf(out, " Loads - no mapping : %10d\n", stats->ld_noadrs);
2003 fprintf(out, " Load Fill Buffer Hit : %10d\n", stats->ld_fbhit);
2004 fprintf(out, " Load L1D hit : %10d\n", stats->ld_l1hit);
2005 fprintf(out, " Load L2D hit : %10d\n", stats->ld_l2hit);
2006 fprintf(out, " Load LLC hit : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2007 fprintf(out, " Load Local HITM : %10d\n", stats->lcl_hitm);
2008 fprintf(out, " Load Remote HITM : %10d\n", stats->rmt_hitm);
2009 fprintf(out, " Load Remote HIT : %10d\n", stats->rmt_hit);
2010 fprintf(out, " Load Local DRAM : %10d\n", stats->lcl_dram);
2011 fprintf(out, " Load Remote DRAM : %10d\n", stats->rmt_dram);
2012 fprintf(out, " Load MESI State Exclusive : %10d\n", stats->ld_excl);
2013 fprintf(out, " Load MESI State Shared : %10d\n", stats->ld_shared);
2014 fprintf(out, " Load LLC Misses : %10d\n", llc_misses);
2015 fprintf(out, " LLC Misses to Local DRAM : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);
2016 fprintf(out, " LLC Misses to Remote DRAM : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);
2017 fprintf(out, " LLC Misses to Remote cache (HIT) : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.);
2018 fprintf(out, " LLC Misses to Remote cache (HITM) : %10.1f%%\n", ((double)stats->rmt_hitm/(double)llc_misses) * 100.);
2019 fprintf(out, " Store Operations : %10d\n", stats->store);
2020 fprintf(out, " Store - uncacheable : %10d\n", stats->st_uncache);
2021 fprintf(out, " Store - no mapping : %10d\n", stats->st_noadrs);
2022 fprintf(out, " Store L1D Hit : %10d\n", stats->st_l1hit);
2023 fprintf(out, " Store L1D Miss : %10d\n", stats->st_l1miss);
2024 fprintf(out, " No Page Map Rejects : %10d\n", stats->nomap);
2025 fprintf(out, " Unable to parse data source : %10d\n", stats->noparse);
2026}
2027
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002028static void print_shared_cacheline_info(FILE *out)
2029{
2030 struct c2c_stats *stats = &c2c.hitm_stats;
2031 int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
2032
2033 fprintf(out, "=================================================\n");
2034 fprintf(out, " Global Shared Cache Line Event Information \n");
2035 fprintf(out, "=================================================\n");
2036 fprintf(out, " Total Shared Cache Lines : %10d\n", c2c.shared_clines);
2037 fprintf(out, " Load HITs on shared lines : %10d\n", stats->load);
2038 fprintf(out, " Fill Buffer Hits on shared lines : %10d\n", stats->ld_fbhit);
2039 fprintf(out, " L1D hits on shared lines : %10d\n", stats->ld_l1hit);
2040 fprintf(out, " L2D hits on shared lines : %10d\n", stats->ld_l2hit);
2041 fprintf(out, " LLC hits on shared lines : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2042 fprintf(out, " Locked Access on shared lines : %10d\n", stats->locks);
2043 fprintf(out, " Store HITs on shared lines : %10d\n", stats->store);
2044 fprintf(out, " Store L1D hits on shared lines : %10d\n", stats->st_l1hit);
2045 fprintf(out, " Total Merged records : %10d\n", hitm_cnt + stats->store);
2046}
2047
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002048static void print_cacheline(struct c2c_hists *c2c_hists,
2049 struct hist_entry *he_cl,
2050 struct perf_hpp_list *hpp_list,
2051 FILE *out)
2052{
2053 char bf[1000];
2054 struct perf_hpp hpp = {
2055 .buf = bf,
2056 .size = 1000,
2057 };
2058 static bool once;
2059
2060 if (!once) {
2061 hists__fprintf_headers(&c2c_hists->hists, out);
2062 once = true;
2063 } else {
2064 fprintf(out, "\n");
2065 }
2066
Jiri Olsabb342da2016-07-06 15:40:09 +02002067 fprintf(out, " -------------------------------------------------------------\n");
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002068 __hist_entry__snprintf(he_cl, &hpp, hpp_list);
2069 fprintf(out, "%s\n", bf);
Jiri Olsabb342da2016-07-06 15:40:09 +02002070 fprintf(out, " -------------------------------------------------------------\n");
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002071
2072 hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, true);
2073}
2074
2075static void print_pareto(FILE *out)
2076{
2077 struct perf_hpp_list hpp_list;
2078 struct rb_node *nd;
2079 int ret;
2080
2081 perf_hpp_list__init(&hpp_list);
2082 ret = hpp_list__parse(&hpp_list,
Jiri Olsabb342da2016-07-06 15:40:09 +02002083 "cl_num,"
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002084 "cl_rmt_hitm,"
2085 "cl_lcl_hitm,"
2086 "cl_stores_l1hit,"
2087 "cl_stores_l1miss,"
2088 "dcacheline",
2089 NULL);
2090
2091 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
2092 return;
2093
2094 nd = rb_first(&c2c.hists.hists.entries);
2095
2096 for (; nd; nd = rb_next(nd)) {
2097 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2098 struct c2c_hist_entry *c2c_he;
2099
2100 if (he->filtered)
2101 continue;
2102
2103 c2c_he = container_of(he, struct c2c_hist_entry, he);
2104 print_cacheline(c2c_he->hists, he, &hpp_list, out);
2105 }
2106}
2107
Jiri Olsa2709b972016-08-27 11:40:23 +02002108static void print_c2c_info(FILE *out, struct perf_session *session)
2109{
2110 struct perf_evlist *evlist = session->evlist;
2111 struct perf_evsel *evsel;
2112 bool first = true;
2113
2114 fprintf(out, "=================================================\n");
2115 fprintf(out, " c2c details \n");
2116 fprintf(out, "=================================================\n");
2117
2118 evlist__for_each_entry(evlist, evsel) {
2119 fprintf(out, "%-36s: %s\n", first ? " Events" : "",
2120 perf_evsel__name(evsel));
2121 first = false;
2122 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002123 fprintf(out, " Cachelines sort on : %s HITMs\n",
Jiri Olsad940bac2016-11-21 22:33:30 +01002124 display_str[c2c.display]);
Jiri Olsafc9c6302016-05-24 14:14:38 +02002125 fprintf(out, " Cacheline data grouping : %s\n", c2c.cl_sort);
Jiri Olsa2709b972016-08-27 11:40:23 +02002126}
2127
2128static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002129{
2130 setup_pager();
2131
Jiri Olsa74c63a22016-05-02 20:01:59 +02002132 print_c2c__display_stats(out);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002133 fprintf(out, "\n");
2134 print_shared_cacheline_info(out);
Jiri Olsa2709b972016-08-27 11:40:23 +02002135 fprintf(out, "\n");
2136 print_c2c_info(out, session);
Jiri Olsa74c63a22016-05-02 20:01:59 +02002137
2138 if (c2c.stats_only)
2139 return;
2140
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002141 fprintf(out, "\n");
2142 fprintf(out, "=================================================\n");
2143 fprintf(out, " Shared Data Cache Line Table \n");
2144 fprintf(out, "=================================================\n");
2145 fprintf(out, "#\n");
2146
2147 hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, false);
2148
2149 fprintf(out, "\n");
2150 fprintf(out, "=================================================\n");
2151 fprintf(out, " Shared Cache Line Distribution Pareto \n");
2152 fprintf(out, "=================================================\n");
2153 fprintf(out, "#\n");
2154
2155 print_pareto(out);
2156}
Jiri Olsa1e181b92016-06-03 15:40:28 +02002157
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002158#ifdef HAVE_SLANG_SUPPORT
2159static void c2c_browser__update_nr_entries(struct hist_browser *hb)
2160{
2161 u64 nr_entries = 0;
2162 struct rb_node *nd = rb_first(&hb->hists->entries);
2163
2164 while (nd) {
2165 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2166
2167 if (!he->filtered)
2168 nr_entries++;
2169
2170 nd = rb_next(nd);
2171 }
2172
2173 hb->nr_non_filtered_entries = nr_entries;
2174}
2175
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002176struct c2c_cacheline_browser {
2177 struct hist_browser hb;
2178 struct hist_entry *he;
2179};
2180
2181static int
2182perf_c2c_cacheline_browser__title(struct hist_browser *browser,
2183 char *bf, size_t size)
2184{
2185 struct c2c_cacheline_browser *cl_browser;
2186 struct hist_entry *he;
2187 uint64_t addr = 0;
2188
2189 cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
2190 he = cl_browser->he;
2191
2192 if (he->mem_info)
2193 addr = cl_address(he->mem_info->daddr.addr);
2194
2195 scnprintf(bf, size, "Cacheline 0x%lx", addr);
2196 return 0;
2197}
2198
2199static struct c2c_cacheline_browser*
2200c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
2201{
2202 struct c2c_cacheline_browser *browser;
2203
2204 browser = zalloc(sizeof(*browser));
2205 if (browser) {
2206 hist_browser__init(&browser->hb, hists);
2207 browser->hb.c2c_filter = true;
2208 browser->hb.title = perf_c2c_cacheline_browser__title;
2209 browser->he = he;
2210 }
2211
2212 return browser;
2213}
2214
2215static int perf_c2c__browse_cacheline(struct hist_entry *he)
2216{
2217 struct c2c_hist_entry *c2c_he;
2218 struct c2c_hists *c2c_hists;
2219 struct c2c_cacheline_browser *cl_browser;
2220 struct hist_browser *browser;
2221 int key = -1;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002222 const char help[] =
2223 " ENTER Togle callchains (if present) \n"
2224 " n Togle Node details info \n"
2225 " s Togle full lenght of symbol and source line columns \n"
2226 " q Return back to cacheline list \n";
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002227
Jiri Olsa590b6a32016-07-10 16:25:15 +02002228 /* Display compact version first. */
2229 c2c.symbol_full = false;
2230
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002231 c2c_he = container_of(he, struct c2c_hist_entry, he);
2232 c2c_hists = c2c_he->hists;
2233
2234 cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
2235 if (cl_browser == NULL)
2236 return -1;
2237
2238 browser = &cl_browser->hb;
2239
2240 /* reset abort key so that it can get Ctrl-C as a key */
2241 SLang_reset_tty();
2242 SLang_init_tty(0, 0, 0);
2243
2244 c2c_browser__update_nr_entries(browser);
2245
2246 while (1) {
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002247 key = hist_browser__run(browser, "? - help");
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002248
2249 switch (key) {
Jiri Olsa590b6a32016-07-10 16:25:15 +02002250 case 's':
2251 c2c.symbol_full = !c2c.symbol_full;
2252 break;
Jiri Olsa1a56a422016-07-10 16:30:27 +02002253 case 'n':
2254 c2c.node_info = (c2c.node_info + 1) % 3;
2255 setup_nodes_header();
2256 break;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002257 case 'q':
2258 goto out;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002259 case '?':
2260 ui_browser__help_window(&browser->b, help);
2261 break;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002262 default:
2263 break;
2264 }
2265 }
2266
2267out:
2268 free(cl_browser);
2269 return 0;
2270}
2271
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002272static int perf_c2c_browser__title(struct hist_browser *browser,
2273 char *bf, size_t size)
2274{
2275 scnprintf(bf, size,
Jiri Olsa55b95772016-05-29 10:21:45 +02002276 "Shared Data Cache Line Table "
2277 "(%lu entries, sorted on %s HITMs)",
2278 browser->nr_non_filtered_entries,
Jiri Olsad940bac2016-11-21 22:33:30 +01002279 display_str[c2c.display]);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002280 return 0;
2281}
2282
2283static struct hist_browser*
2284perf_c2c_browser__new(struct hists *hists)
2285{
2286 struct hist_browser *browser = hist_browser__new(hists);
2287
2288 if (browser) {
2289 browser->title = perf_c2c_browser__title;
2290 browser->c2c_filter = true;
2291 }
2292
2293 return browser;
2294}
2295
2296static int perf_c2c__hists_browse(struct hists *hists)
2297{
2298 struct hist_browser *browser;
2299 int key = -1;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002300 const char help[] =
2301 " d Display cacheline details \n"
2302 " ENTER Togle callchains (if present) \n"
2303 " q Quit \n";
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002304
2305 browser = perf_c2c_browser__new(hists);
2306 if (browser == NULL)
2307 return -1;
2308
2309 /* reset abort key so that it can get Ctrl-C as a key */
2310 SLang_reset_tty();
2311 SLang_init_tty(0, 0, 0);
2312
2313 c2c_browser__update_nr_entries(browser);
2314
2315 while (1) {
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002316 key = hist_browser__run(browser, "? - help");
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002317
2318 switch (key) {
2319 case 'q':
2320 goto out;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002321 case 'd':
2322 perf_c2c__browse_cacheline(browser->he_selection);
2323 break;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002324 case '?':
2325 ui_browser__help_window(&browser->b, help);
2326 break;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002327 default:
2328 break;
2329 }
2330 }
2331
2332out:
2333 hist_browser__delete(browser);
2334 return 0;
2335}
2336
Jiri Olsa2709b972016-08-27 11:40:23 +02002337static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002338{
Namhyung Kim1936fea2017-03-08 00:08:33 +09002339 if (use_browser == 0)
Jiri Olsa2709b972016-08-27 11:40:23 +02002340 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002341 else
2342 perf_c2c__hists_browse(&c2c.hists.hists);
2343}
2344#else
Jiri Olsa2709b972016-08-27 11:40:23 +02002345static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002346{
2347 use_browser = 0;
Jiri Olsa2709b972016-08-27 11:40:23 +02002348 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002349}
2350#endif /* HAVE_SLANG_SUPPORT */
2351
2352static void ui_quirks(void)
2353{
2354 if (!c2c.use_stdio) {
2355 dim_offset.width = 5;
2356 dim_offset.header = header_offset_tui;
2357 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002358
2359 dim_percent_hitm.header = percent_hitm_header[c2c.display];
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002360}
2361
Jiri Olsadd805762016-05-11 18:23:48 +02002362#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
2363
2364const char callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
2365 CALLCHAIN_REPORT_HELP
2366 "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
2367
2368static int
2369parse_callchain_opt(const struct option *opt, const char *arg, int unset)
2370{
2371 struct callchain_param *callchain = opt->value;
2372
2373 callchain->enabled = !unset;
2374 /*
2375 * --no-call-graph
2376 */
2377 if (unset) {
2378 symbol_conf.use_callchain = false;
2379 callchain->mode = CHAIN_NONE;
2380 return 0;
2381 }
2382
2383 return parse_callchain_report_opt(arg);
2384}
2385
2386static int setup_callchain(struct perf_evlist *evlist)
2387{
2388 u64 sample_type = perf_evlist__combined_sample_type(evlist);
2389 enum perf_call_graph_mode mode = CALLCHAIN_NONE;
2390
2391 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
2392 (sample_type & PERF_SAMPLE_STACK_USER))
2393 mode = CALLCHAIN_DWARF;
2394 else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
2395 mode = CALLCHAIN_LBR;
2396 else if (sample_type & PERF_SAMPLE_CALLCHAIN)
2397 mode = CALLCHAIN_FP;
2398
2399 if (!callchain_param.enabled &&
2400 callchain_param.mode != CHAIN_NONE &&
2401 mode != CALLCHAIN_NONE) {
2402 symbol_conf.use_callchain = true;
2403 if (callchain_register_param(&callchain_param) < 0) {
2404 ui__error("Can't register callchain params.\n");
2405 return -EINVAL;
2406 }
2407 }
2408
2409 callchain_param.record_mode = mode;
2410 callchain_param.min_percent = 0;
2411 return 0;
2412}
2413
Jiri Olsa55b95772016-05-29 10:21:45 +02002414static int setup_display(const char *str)
2415{
Jiri Olsad940bac2016-11-21 22:33:30 +01002416 const char *display = str ?: "tot";
Jiri Olsa55b95772016-05-29 10:21:45 +02002417
Jiri Olsad940bac2016-11-21 22:33:30 +01002418 if (!strcmp(display, "tot"))
2419 c2c.display = DISPLAY_TOT;
2420 else if (!strcmp(display, "rmt"))
Jiri Olsa55b95772016-05-29 10:21:45 +02002421 c2c.display = DISPLAY_RMT;
2422 else if (!strcmp(display, "lcl"))
2423 c2c.display = DISPLAY_LCL;
2424 else {
2425 pr_err("failed: unknown display type: %s\n", str);
2426 return -1;
2427 }
2428
2429 return 0;
2430}
2431
Jiri Olsafc9c6302016-05-24 14:14:38 +02002432#define for_each_token(__tok, __buf, __sep, __tmp) \
2433 for (__tok = strtok_r(__buf, __sep, &__tmp); __tok; \
2434 __tok = strtok_r(NULL, __sep, &__tmp))
2435
Jiri Olsa18f278d2016-10-11 13:39:47 +02002436static int build_cl_output(char *cl_sort, bool no_source)
Jiri Olsafc9c6302016-05-24 14:14:38 +02002437{
2438 char *tok, *tmp, *buf = strdup(cl_sort);
2439 bool add_pid = false;
2440 bool add_tid = false;
2441 bool add_iaddr = false;
2442 bool add_sym = false;
2443 bool add_dso = false;
2444 bool add_src = false;
2445
2446 if (!buf)
2447 return -ENOMEM;
2448
2449 for_each_token(tok, buf, ",", tmp) {
2450 if (!strcmp(tok, "tid")) {
2451 add_tid = true;
2452 } else if (!strcmp(tok, "pid")) {
2453 add_pid = true;
2454 } else if (!strcmp(tok, "iaddr")) {
2455 add_iaddr = true;
2456 add_sym = true;
2457 add_dso = true;
Jiri Olsa18f278d2016-10-11 13:39:47 +02002458 add_src = no_source ? false : true;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002459 } else if (!strcmp(tok, "dso")) {
2460 add_dso = true;
2461 } else if (strcmp(tok, "offset")) {
2462 pr_err("unrecognized sort token: %s\n", tok);
2463 return -EINVAL;
2464 }
2465 }
2466
2467 if (asprintf(&c2c.cl_output,
Jiri Olsabb342da2016-07-06 15:40:09 +02002468 "%s%s%s%s%s%s%s%s%s%s",
2469 c2c.use_stdio ? "cl_num_empty," : "",
Jiri Olsafc9c6302016-05-24 14:14:38 +02002470 "percent_rmt_hitm,"
2471 "percent_lcl_hitm,"
2472 "percent_stores_l1hit,"
2473 "percent_stores_l1miss,"
2474 "offset,",
2475 add_pid ? "pid," : "",
2476 add_tid ? "tid," : "",
2477 add_iaddr ? "iaddr," : "",
2478 "mean_rmt,"
2479 "mean_lcl,"
2480 "mean_load,"
Jiri Olsa8763e6a2017-01-20 10:20:31 +01002481 "tot_recs,"
Jiri Olsafc9c6302016-05-24 14:14:38 +02002482 "cpucnt,",
2483 add_sym ? "symbol," : "",
2484 add_dso ? "dso," : "",
2485 add_src ? "cl_srcline," : "",
2486 "node") < 0)
2487 return -ENOMEM;
2488
2489 c2c.show_src = add_src;
2490
2491 free(buf);
2492 return 0;
2493}
2494
Jiri Olsa18f278d2016-10-11 13:39:47 +02002495static int setup_coalesce(const char *coalesce, bool no_source)
Jiri Olsafc9c6302016-05-24 14:14:38 +02002496{
2497 const char *c = coalesce ?: coalesce_default;
2498
2499 if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)
2500 return -ENOMEM;
2501
Jiri Olsa18f278d2016-10-11 13:39:47 +02002502 if (build_cl_output(c2c.cl_sort, no_source))
Jiri Olsafc9c6302016-05-24 14:14:38 +02002503 return -1;
2504
2505 if (asprintf(&c2c.cl_resort, "offset,%s",
Jiri Olsad940bac2016-11-21 22:33:30 +01002506 c2c.display == DISPLAY_TOT ?
2507 "tot_hitm" :
Jiri Olsafc9c6302016-05-24 14:14:38 +02002508 c2c.display == DISPLAY_RMT ?
2509 "rmt_hitm,lcl_hitm" :
2510 "lcl_hitm,rmt_hitm") < 0)
2511 return -ENOMEM;
2512
2513 pr_debug("coalesce sort fields: %s\n", c2c.cl_sort);
2514 pr_debug("coalesce resort fields: %s\n", c2c.cl_resort);
2515 pr_debug("coalesce output fields: %s\n", c2c.cl_output);
2516 return 0;
2517}
2518
Jiri Olsa903a6f12016-09-22 17:36:40 +02002519static int perf_c2c__report(int argc, const char **argv)
2520{
2521 struct perf_session *session;
Jiri Olsa78b27542016-09-22 17:36:44 +02002522 struct ui_progress prog;
Jiri Olsa903a6f12016-09-22 17:36:40 +02002523 struct perf_data_file file = {
2524 .mode = PERF_DATA_MODE_READ,
2525 };
Jiri Olsadd805762016-05-11 18:23:48 +02002526 char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
Jiri Olsa55b95772016-05-29 10:21:45 +02002527 const char *display = NULL;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002528 const char *coalesce = NULL;
Jiri Olsa18f278d2016-10-11 13:39:47 +02002529 bool no_source = false;
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002530 const struct option options[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +02002531 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
2532 "file", "vmlinux pathname"),
Jiri Olsa903a6f12016-09-22 17:36:40 +02002533 OPT_STRING('i', "input", &input_name, "file",
2534 "the input file to process"),
Jiri Olsa1e181b92016-06-03 15:40:28 +02002535 OPT_INCR('N', "node-info", &c2c.node_info,
2536 "show extra node info in report (repeat for more info)"),
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002537#ifdef HAVE_SLANG_SUPPORT
2538 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2539#endif
Jiri Olsa74c63a22016-05-02 20:01:59 +02002540 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
Namhyung Kimf75d2892017-03-08 00:08:32 +09002541 "Display only statistic tables (implies --stdio)"),
Jiri Olsa590b6a32016-07-10 16:25:15 +02002542 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
2543 "Display full length of symbols"),
Jiri Olsa18f278d2016-10-11 13:39:47 +02002544 OPT_BOOLEAN(0, "no-source", &no_source,
2545 "Do not display Source Line column"),
Jiri Olsaaf09b2d2016-10-11 13:52:05 +02002546 OPT_BOOLEAN(0, "show-all", &c2c.show_all,
2547 "Show all captured HITM lines."),
Jiri Olsadd805762016-05-11 18:23:48 +02002548 OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
2549 "print_type,threshold[,print_limit],order,sort_key[,branch],value",
2550 callchain_help, &parse_callchain_opt,
2551 callchain_default_opt),
Jiri Olsad940bac2016-11-21 22:33:30 +01002552 OPT_STRING('d', "display", &display, "Switch HITM output type", "lcl,rmt"),
Jiri Olsafc9c6302016-05-24 14:14:38 +02002553 OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
2554 "coalesce fields: pid,tid,iaddr,dso"),
Jiri Olsab7ac4f92016-11-21 22:33:28 +01002555 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002556 OPT_PARENT(c2c_options),
Jiri Olsa903a6f12016-09-22 17:36:40 +02002557 OPT_END()
2558 };
2559 int err = 0;
2560
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002561 argc = parse_options(argc, argv, options, report_c2c_usage,
Jiri Olsa903a6f12016-09-22 17:36:40 +02002562 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa78b27542016-09-22 17:36:44 +02002563 if (argc)
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002564 usage_with_options(report_c2c_usage, options);
Jiri Olsa903a6f12016-09-22 17:36:40 +02002565
Jiri Olsa74c63a22016-05-02 20:01:59 +02002566 if (c2c.stats_only)
2567 c2c.use_stdio = true;
2568
Jiri Olsa78b27542016-09-22 17:36:44 +02002569 if (!input_name || !strlen(input_name))
2570 input_name = "perf.data";
2571
Jiri Olsab7ac4f92016-11-21 22:33:28 +01002572 file.path = input_name;
2573 file.force = symbol_conf.force;
Jiri Olsa903a6f12016-09-22 17:36:40 +02002574
Jiri Olsa55b95772016-05-29 10:21:45 +02002575 err = setup_display(display);
2576 if (err)
2577 goto out;
2578
Jiri Olsa18f278d2016-10-11 13:39:47 +02002579 err = setup_coalesce(coalesce, no_source);
Jiri Olsafc9c6302016-05-24 14:14:38 +02002580 if (err) {
2581 pr_debug("Failed to initialize hists\n");
2582 goto out;
2583 }
2584
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02002585 err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
Jiri Olsac75540e2016-09-22 17:36:41 +02002586 if (err) {
2587 pr_debug("Failed to initialize hists\n");
2588 goto out;
2589 }
2590
Jiri Olsa903a6f12016-09-22 17:36:40 +02002591 session = perf_session__new(&file, 0, &c2c.tool);
2592 if (session == NULL) {
2593 pr_debug("No memory for session\n");
2594 goto out;
2595 }
Jiri Olsae8c5fe12016-11-21 22:33:27 +01002596
Jiri Olsa1e181b92016-06-03 15:40:28 +02002597 err = setup_nodes(session);
2598 if (err) {
2599 pr_err("Failed setup nodes\n");
2600 goto out;
2601 }
Jiri Olsa903a6f12016-09-22 17:36:40 +02002602
Jiri Olsadd805762016-05-11 18:23:48 +02002603 err = setup_callchain(session->evlist);
2604 if (err)
2605 goto out_session;
2606
Jiri Olsa903a6f12016-09-22 17:36:40 +02002607 if (symbol__init(&session->header.env) < 0)
2608 goto out_session;
2609
2610 /* No pipe support at the moment. */
2611 if (perf_data_file__is_pipe(session->file)) {
2612 pr_debug("No pipe support at the moment.\n");
2613 goto out_session;
2614 }
2615
Jiri Olsae8c5fe12016-11-21 22:33:27 +01002616 if (c2c.use_stdio)
2617 use_browser = 0;
2618 else
2619 use_browser = 1;
2620
2621 setup_browser(false);
2622
Jiri Olsa78b27542016-09-22 17:36:44 +02002623 err = perf_session__process_events(session);
2624 if (err) {
2625 pr_err("failed to process sample\n");
2626 goto out_session;
2627 }
2628
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002629 c2c_hists__reinit(&c2c.hists,
Jiri Olsabb342da2016-07-06 15:40:09 +02002630 "cl_idx,"
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002631 "dcacheline,"
2632 "tot_recs,"
2633 "percent_hitm,"
2634 "tot_hitm,lcl_hitm,rmt_hitm,"
2635 "stores,stores_l1hit,stores_l1miss,"
2636 "dram_lcl,dram_rmt,"
2637 "ld_llcmiss,"
2638 "tot_loads,"
2639 "ld_fbhit,ld_l1hit,ld_l2hit,"
2640 "ld_lclhit,ld_rmthit",
Jiri Olsad940bac2016-11-21 22:33:30 +01002641 c2c.display == DISPLAY_TOT ? "tot_hitm" :
Jiri Olsa55b95772016-05-29 10:21:45 +02002642 c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm"
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002643 );
2644
Jiri Olsa78b27542016-09-22 17:36:44 +02002645 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
2646
2647 hists__collapse_resort(&c2c.hists.hists, NULL);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002648 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_hitm_cb);
2649 hists__iterate_cb(&c2c.hists.hists, resort_cl_cb);
Jiri Olsa78b27542016-09-22 17:36:44 +02002650
2651 ui_progress__finish();
2652
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002653 ui_quirks();
2654
Jiri Olsa2709b972016-08-27 11:40:23 +02002655 perf_c2c_display(session);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002656
Jiri Olsa903a6f12016-09-22 17:36:40 +02002657out_session:
2658 perf_session__delete(session);
2659out:
2660 return err;
2661}
2662
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03002663static int parse_record_events(const struct option *opt,
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002664 const char *str, int unset __maybe_unused)
2665{
2666 bool *event_set = (bool *) opt->value;
2667
2668 *event_set = true;
2669 return perf_mem_events__parse(str);
2670}
2671
2672
2673static const char * const __usage_record[] = {
2674 "perf c2c record [<options>] [<command>]",
2675 "perf c2c record [<options>] -- <command> [<options>]",
2676 NULL
2677};
2678
2679static const char * const *record_mem_usage = __usage_record;
2680
2681static int perf_c2c__record(int argc, const char **argv)
2682{
2683 int rec_argc, i = 0, j;
2684 const char **rec_argv;
2685 int ret;
2686 bool all_user = false, all_kernel = false;
2687 bool event_set = false;
2688 struct option options[] = {
2689 OPT_CALLBACK('e', "event", &event_set, "event",
2690 "event selector. Use 'perf mem record -e list' to list available events",
2691 parse_record_events),
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002692 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
2693 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
2694 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002695 OPT_PARENT(c2c_options),
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002696 OPT_END()
2697 };
2698
2699 if (perf_mem_events__init()) {
2700 pr_err("failed: memory events not supported\n");
2701 return -1;
2702 }
2703
2704 argc = parse_options(argc, argv, options, record_mem_usage,
2705 PARSE_OPT_KEEP_UNKNOWN);
2706
2707 rec_argc = argc + 10; /* max number of arguments */
2708 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2709 if (!rec_argv)
2710 return -1;
2711
2712 rec_argv[i++] = "record";
2713
2714 if (!event_set) {
2715 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
2716 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
2717 }
2718
2719 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
2720 rec_argv[i++] = "-W";
2721
2722 rec_argv[i++] = "-d";
2723 rec_argv[i++] = "--sample-cpu";
2724
2725 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
2726 if (!perf_mem_events[j].record)
2727 continue;
2728
2729 if (!perf_mem_events[j].supported) {
2730 pr_err("failed: event '%s' not supported\n",
2731 perf_mem_events[j].name);
2732 return -1;
2733 }
2734
2735 rec_argv[i++] = "-e";
2736 rec_argv[i++] = perf_mem_events__name(j);
2737 };
2738
2739 if (all_user)
2740 rec_argv[i++] = "--all-user";
2741
2742 if (all_kernel)
2743 rec_argv[i++] = "--all-kernel";
2744
2745 for (j = 0; j < argc; j++, i++)
2746 rec_argv[i] = argv[j];
2747
2748 if (verbose > 0) {
2749 pr_debug("calling: ");
2750
2751 j = 0;
2752
2753 while (rec_argv[j]) {
2754 pr_debug("%s ", rec_argv[j]);
2755 j++;
2756 }
2757 pr_debug("\n");
2758 }
2759
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002760 ret = cmd_record(i, rec_argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002761 free(rec_argv);
2762 return ret;
2763}
2764
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002765int cmd_c2c(int argc, const char **argv)
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002766{
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002767 argc = parse_options(argc, argv, c2c_options, c2c_usage,
2768 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002769
2770 if (!argc)
2771 usage_with_options(c2c_usage, c2c_options);
2772
2773 if (!strncmp(argv[0], "rec", 3)) {
2774 return perf_c2c__record(argc, argv);
Jiri Olsa903a6f12016-09-22 17:36:40 +02002775 } else if (!strncmp(argv[0], "rep", 3)) {
2776 return perf_c2c__report(argc, argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002777 } else {
2778 usage_with_options(c2c_usage, c2c_options);
2779 }
2780
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002781 return 0;
2782}