blob: a14be1cd3d70f0fe42c20c0b083cdab455ae7459 [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>
Arnaldo Carvalho de Melo391e4202017-04-19 18:51:14 -030018#include <sys/param.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020019#include "util.h"
20#include "debug.h"
21#include "builtin.h"
22#include <subcmd/parse-options.h>
Jiri Olsa39bcd4a2016-09-22 17:36:39 +020023#include "mem-events.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020024#include "session.h"
25#include "hist.h"
Jiri Olsacbb88502016-09-22 17:36:48 +020026#include "sort.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020027#include "tool.h"
28#include "data.h"
Jiri Olsa8d3f9382016-09-22 17:36:42 +020029#include "sort.h"
Jiri Olsa2709b972016-08-27 11:40:23 +020030#include "evlist.h"
31#include "evsel.h"
Jiri Olsa2d388bd2016-05-03 14:32:56 +020032#include <asm/bug.h>
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010033#include "ui/browsers/hists.h"
Jiri Olsadd805762016-05-11 18:23:48 +020034#include "evlist.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020035
Jiri Olsac75540e2016-09-22 17:36:41 +020036struct c2c_hists {
37 struct hists hists;
38 struct perf_hpp_list list;
Jiri Olsab2252ae2016-09-22 17:36:46 +020039 struct c2c_stats stats;
Jiri Olsac75540e2016-09-22 17:36:41 +020040};
41
Jiri Olsa92062d52016-06-05 13:40:53 +020042struct compute_stats {
43 struct stats lcl_hitm;
44 struct stats rmt_hitm;
45 struct stats load;
46};
47
Jiri Olsa78b27542016-09-22 17:36:44 +020048struct c2c_hist_entry {
49 struct c2c_hists *hists;
Jiri Olsab2252ae2016-09-22 17:36:46 +020050 struct c2c_stats stats;
Jiri Olsa1e181b92016-06-03 15:40:28 +020051 unsigned long *cpuset;
52 struct c2c_stats *node_stats;
Jiri Olsabb342da2016-07-06 15:40:09 +020053 unsigned int cacheline_idx;
Jiri Olsa92062d52016-06-05 13:40:53 +020054
55 struct compute_stats cstats;
56
Jiri Olsa78b27542016-09-22 17:36:44 +020057 /*
58 * must be at the end,
59 * because of its callchain dynamic entry
60 */
61 struct hist_entry he;
62};
63
Jiri Olsa190bacc2017-01-20 10:20:32 +010064static char const *coalesce_default = "pid,iaddr";
Jiri Olsafc9c6302016-05-24 14:14:38 +020065
Jiri Olsa903a6f12016-09-22 17:36:40 +020066struct perf_c2c {
Jiri Olsac75540e2016-09-22 17:36:41 +020067 struct perf_tool tool;
68 struct c2c_hists hists;
Jiri Olsa1e181b92016-06-03 15:40:28 +020069
70 unsigned long **nodes;
71 int nodes_cnt;
72 int cpus_cnt;
73 int *cpu2node;
74 int node_info;
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +020075
76 bool show_src;
Jiri Olsaaf09b2d2016-10-11 13:52:05 +020077 bool show_all;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010078 bool use_stdio;
Jiri Olsa74c63a22016-05-02 20:01:59 +020079 bool stats_only;
Jiri Olsa590b6a32016-07-10 16:25:15 +020080 bool symbol_full;
Jiri Olsa7ef2efa2016-07-01 11:12:11 +020081
82 /* HITM shared clines stats */
83 struct c2c_stats hitm_stats;
84 int shared_clines;
Jiri Olsa55b95772016-05-29 10:21:45 +020085
86 int display;
Jiri Olsafc9c6302016-05-24 14:14:38 +020087
88 const char *coalesce;
89 char *cl_sort;
90 char *cl_resort;
91 char *cl_output;
Jiri Olsa55b95772016-05-29 10:21:45 +020092};
93
94enum {
95 DISPLAY_LCL,
96 DISPLAY_RMT,
Jiri Olsad940bac2016-11-21 22:33:30 +010097 DISPLAY_TOT,
98 DISPLAY_MAX,
99};
100
101static const char *display_str[DISPLAY_MAX] = {
102 [DISPLAY_LCL] = "Local",
103 [DISPLAY_RMT] = "Remote",
104 [DISPLAY_TOT] = "Total",
Jiri Olsa903a6f12016-09-22 17:36:40 +0200105};
106
Jiri Olsa3a5bfab2016-11-21 22:33:31 +0100107static const struct option c2c_options[] = {
108 OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),
109 OPT_END()
110};
111
Jiri Olsa903a6f12016-09-22 17:36:40 +0200112static struct perf_c2c c2c;
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200113
Jiri Olsa78b27542016-09-22 17:36:44 +0200114static void *c2c_he_zalloc(size_t size)
115{
116 struct c2c_hist_entry *c2c_he;
117
118 c2c_he = zalloc(size + sizeof(*c2c_he));
119 if (!c2c_he)
120 return NULL;
121
Jiri Olsa1e181b92016-06-03 15:40:28 +0200122 c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
123 if (!c2c_he->cpuset)
124 return NULL;
125
126 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
127 if (!c2c_he->node_stats)
128 return NULL;
129
Jiri Olsa92062d52016-06-05 13:40:53 +0200130 init_stats(&c2c_he->cstats.lcl_hitm);
131 init_stats(&c2c_he->cstats.rmt_hitm);
132 init_stats(&c2c_he->cstats.load);
133
Jiri Olsa78b27542016-09-22 17:36:44 +0200134 return &c2c_he->he;
135}
136
137static void c2c_he_free(void *he)
138{
139 struct c2c_hist_entry *c2c_he;
140
141 c2c_he = container_of(he, struct c2c_hist_entry, he);
142 if (c2c_he->hists) {
143 hists__delete_entries(&c2c_he->hists->hists);
144 free(c2c_he->hists);
145 }
146
Jiri Olsa1e181b92016-06-03 15:40:28 +0200147 free(c2c_he->cpuset);
148 free(c2c_he->node_stats);
Jiri Olsa78b27542016-09-22 17:36:44 +0200149 free(c2c_he);
150}
151
152static struct hist_entry_ops c2c_entry_ops = {
153 .new = c2c_he_zalloc,
154 .free = c2c_he_free,
155};
156
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200157static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200158 const char *sort,
159 int nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200160
Jiri Olsab2252ae2016-09-22 17:36:46 +0200161static struct c2c_hists*
162he__get_c2c_hists(struct hist_entry *he,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200163 const char *sort,
164 int nr_header_lines)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200165{
166 struct c2c_hist_entry *c2c_he;
167 struct c2c_hists *hists;
168 int ret;
169
170 c2c_he = container_of(he, struct c2c_hist_entry, he);
171 if (c2c_he->hists)
Jiri Olsab2252ae2016-09-22 17:36:46 +0200172 return c2c_he->hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200173
174 hists = c2c_he->hists = zalloc(sizeof(*hists));
175 if (!hists)
176 return NULL;
177
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200178 ret = c2c_hists__init(hists, sort, nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200179 if (ret) {
180 free(hists);
181 return NULL;
182 }
183
Jiri Olsab2252ae2016-09-22 17:36:46 +0200184 return hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200185}
186
Jiri Olsa1e181b92016-06-03 15:40:28 +0200187static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
188 struct perf_sample *sample)
189{
190 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
191 "WARNING: no sample cpu value"))
192 return;
193
194 set_bit(sample->cpu, c2c_he->cpuset);
195}
196
Jiri Olsa92062d52016-06-05 13:40:53 +0200197static void compute_stats(struct c2c_hist_entry *c2c_he,
198 struct c2c_stats *stats,
199 u64 weight)
200{
201 struct compute_stats *cstats = &c2c_he->cstats;
202
203 if (stats->rmt_hitm)
204 update_stats(&cstats->rmt_hitm, weight);
205 else if (stats->lcl_hitm)
206 update_stats(&cstats->lcl_hitm, weight);
207 else if (stats->load)
208 update_stats(&cstats->load, weight);
209}
210
Jiri Olsa78b27542016-09-22 17:36:44 +0200211static int process_sample_event(struct perf_tool *tool __maybe_unused,
212 union perf_event *event,
213 struct perf_sample *sample,
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -0300214 struct perf_evsel *evsel,
Jiri Olsa78b27542016-09-22 17:36:44 +0200215 struct machine *machine)
216{
Jiri Olsab2252ae2016-09-22 17:36:46 +0200217 struct c2c_hists *c2c_hists = &c2c.hists;
218 struct c2c_hist_entry *c2c_he;
219 struct c2c_stats stats = { .nr_entries = 0, };
Jiri Olsa78b27542016-09-22 17:36:44 +0200220 struct hist_entry *he;
221 struct addr_location al;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200222 struct mem_info *mi, *mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200223 int ret;
224
225 if (machine__resolve(machine, &al, sample) < 0) {
226 pr_debug("problem processing %d event, skipping it.\n",
227 event->header.type);
228 return -1;
229 }
230
Jiri Olsadd805762016-05-11 18:23:48 +0200231 ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
232 evsel, &al, sysctl_perf_event_max_stack);
233 if (ret)
234 goto out;
235
Jiri Olsa78b27542016-09-22 17:36:44 +0200236 mi = sample__resolve_mem(sample, &al);
237 if (mi == NULL)
238 return -ENOMEM;
239
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200240 mi_dup = memdup(mi, sizeof(*mi));
241 if (!mi_dup)
242 goto free_mi;
243
Jiri Olsab2252ae2016-09-22 17:36:46 +0200244 c2c_decode_stats(&stats, mi);
245
246 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsa78b27542016-09-22 17:36:44 +0200247 &al, NULL, NULL, mi,
248 sample, true);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200249 if (he == NULL)
250 goto free_mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200251
Jiri Olsab2252ae2016-09-22 17:36:46 +0200252 c2c_he = container_of(he, struct c2c_hist_entry, he);
253 c2c_add_stats(&c2c_he->stats, &stats);
254 c2c_add_stats(&c2c_hists->stats, &stats);
255
Jiri Olsa1e181b92016-06-03 15:40:28 +0200256 c2c_he__set_cpu(c2c_he, sample);
257
Jiri Olsab2252ae2016-09-22 17:36:46 +0200258 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsa78b27542016-09-22 17:36:44 +0200259 ret = hist_entry__append_callchain(he, sample);
260
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200261 if (!ret) {
Jiri Olsa1e181b92016-06-03 15:40:28 +0200262 /*
263 * There's already been warning about missing
264 * sample's cpu value. Let's account all to
265 * node 0 in this case, without any further
266 * warning.
267 *
268 * Doing node stats only for single callchain data.
269 */
270 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
271 int node = c2c.cpu2node[cpu];
272
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200273 mi = mi_dup;
274
275 mi_dup = memdup(mi, sizeof(*mi));
276 if (!mi_dup)
277 goto free_mi;
278
Jiri Olsafc9c6302016-05-24 14:14:38 +0200279 c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200280 if (!c2c_hists)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200281 goto free_mi_dup;
282
Jiri Olsab2252ae2016-09-22 17:36:46 +0200283 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200284 &al, NULL, NULL, mi,
285 sample, true);
286 if (he == NULL)
287 goto free_mi_dup;
288
Jiri Olsab2252ae2016-09-22 17:36:46 +0200289 c2c_he = container_of(he, struct c2c_hist_entry, he);
290 c2c_add_stats(&c2c_he->stats, &stats);
291 c2c_add_stats(&c2c_hists->stats, &stats);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200292 c2c_add_stats(&c2c_he->node_stats[node], &stats);
293
Jiri Olsa92062d52016-06-05 13:40:53 +0200294 compute_stats(c2c_he, &stats, sample->weight);
295
Jiri Olsa1e181b92016-06-03 15:40:28 +0200296 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200297
298 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200299 ret = hist_entry__append_callchain(he, sample);
300 }
301
302out:
Jiri Olsa78b27542016-09-22 17:36:44 +0200303 addr_location__put(&al);
304 return ret;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200305
306free_mi_dup:
307 free(mi_dup);
308free_mi:
309 free(mi);
310 ret = -ENOMEM;
311 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200312}
313
314static struct perf_c2c c2c = {
315 .tool = {
316 .sample = process_sample_event,
317 .mmap = perf_event__process_mmap,
318 .mmap2 = perf_event__process_mmap2,
319 .comm = perf_event__process_comm,
320 .exit = perf_event__process_exit,
321 .fork = perf_event__process_fork,
322 .lost = perf_event__process_lost,
323 .ordered_events = true,
324 .ordering_requires_timestamps = true,
325 },
326};
327
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200328static const char * const c2c_usage[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +0200329 "perf c2c {record|report}",
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200330 NULL
331};
332
Jiri Olsa903a6f12016-09-22 17:36:40 +0200333static const char * const __usage_report[] = {
334 "perf c2c report",
335 NULL
336};
337
338static const char * const *report_c2c_usage = __usage_report;
339
Jiri Olsac75540e2016-09-22 17:36:41 +0200340#define C2C_HEADER_MAX 2
341
342struct c2c_header {
343 struct {
344 const char *text;
345 int span;
346 } line[C2C_HEADER_MAX];
347};
348
349struct c2c_dimension {
350 struct c2c_header header;
351 const char *name;
352 int width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200353 struct sort_entry *se;
Jiri Olsac75540e2016-09-22 17:36:41 +0200354
355 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
356 struct hist_entry *, struct hist_entry *);
357 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
358 struct hist_entry *he);
359 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
360 struct hist_entry *he);
361};
362
363struct c2c_fmt {
364 struct perf_hpp_fmt fmt;
365 struct c2c_dimension *dim;
366};
367
Jiri Olsa590b6a32016-07-10 16:25:15 +0200368#define SYMBOL_WIDTH 30
369
370static struct c2c_dimension dim_symbol;
371static struct c2c_dimension dim_srcline;
372
373static int symbol_width(struct hists *hists, struct sort_entry *se)
374{
375 int width = hists__col_len(hists, se->se_width_idx);
376
377 if (!c2c.symbol_full)
378 width = MIN(width, SYMBOL_WIDTH);
379
380 return width;
381}
382
Jiri Olsac75540e2016-09-22 17:36:41 +0200383static int c2c_width(struct perf_hpp_fmt *fmt,
384 struct perf_hpp *hpp __maybe_unused,
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -0300385 struct hists *hists)
Jiri Olsac75540e2016-09-22 17:36:41 +0200386{
387 struct c2c_fmt *c2c_fmt;
Jiri Olsac75540e2016-09-22 17:36:41 +0200388 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +0200389
390 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
391 dim = c2c_fmt->dim;
392
Jiri Olsa590b6a32016-07-10 16:25:15 +0200393 if (dim == &dim_symbol || dim == &dim_srcline)
394 return symbol_width(hists, dim->se);
395
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200396 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
397 c2c_fmt->dim->width;
398}
399
400static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
401 struct hists *hists, int line, int *span)
402{
403 struct perf_hpp_list *hpp_list = hists->hpp_list;
404 struct c2c_fmt *c2c_fmt;
405 struct c2c_dimension *dim;
406 const char *text = NULL;
407 int width = c2c_width(fmt, hpp, hists);
408
409 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
410 dim = c2c_fmt->dim;
411
412 if (dim->se) {
413 text = dim->header.line[line].text;
414 /* Use the last line from sort_entry if not defined. */
415 if (!text && (line == hpp_list->nr_header_lines - 1))
416 text = dim->se->se_header;
417 } else {
418 text = dim->header.line[line].text;
419
420 if (*span) {
421 (*span)--;
422 return 0;
423 } else {
424 *span = dim->header.line[line].span;
425 }
426 }
427
Jiri Olsac75540e2016-09-22 17:36:41 +0200428 if (text == NULL)
429 text = "";
430
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200431 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
Jiri Olsac75540e2016-09-22 17:36:41 +0200432}
433
Jiri Olsacbb88502016-09-22 17:36:48 +0200434#define HEX_STR(__s, __v) \
435({ \
436 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
437 __s; \
438})
439
440static int64_t
441dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
442 struct hist_entry *left, struct hist_entry *right)
443{
444 return sort__dcacheline_cmp(left, right);
445}
446
447static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
448 struct hist_entry *he)
449{
450 uint64_t addr = 0;
451 int width = c2c_width(fmt, hpp, he->hists);
452 char buf[20];
453
454 if (he->mem_info)
455 addr = cl_address(he->mem_info->daddr.addr);
456
457 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
458}
459
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200460static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
461 struct hist_entry *he)
462{
463 uint64_t addr = 0;
464 int width = c2c_width(fmt, hpp, he->hists);
465 char buf[20];
466
467 if (he->mem_info)
468 addr = cl_offset(he->mem_info->daddr.al_addr);
469
470 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
471}
472
473static int64_t
474offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
475 struct hist_entry *left, struct hist_entry *right)
476{
477 uint64_t l = 0, r = 0;
478
479 if (left->mem_info)
480 l = cl_offset(left->mem_info->daddr.addr);
481 if (right->mem_info)
482 r = cl_offset(right->mem_info->daddr.addr);
483
484 return (int64_t)(r - l);
485}
486
Jiri Olsa43575a92016-05-03 21:48:56 +0200487static int
488iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
489 struct hist_entry *he)
490{
491 uint64_t addr = 0;
492 int width = c2c_width(fmt, hpp, he->hists);
493 char buf[20];
494
495 if (he->mem_info)
496 addr = he->mem_info->iaddr.addr;
497
498 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
499}
500
501static int64_t
502iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
503 struct hist_entry *left, struct hist_entry *right)
504{
505 return sort__iaddr_cmp(left, right);
506}
507
Jiri Olsa97cb4862016-05-23 16:20:14 +0200508static int
509tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
510 struct hist_entry *he)
511{
512 struct c2c_hist_entry *c2c_he;
513 int width = c2c_width(fmt, hpp, he->hists);
514 unsigned int tot_hitm;
515
516 c2c_he = container_of(he, struct c2c_hist_entry, he);
517 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
518
519 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
520}
521
522static int64_t
523tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
524 struct hist_entry *left, struct hist_entry *right)
525{
526 struct c2c_hist_entry *c2c_left;
527 struct c2c_hist_entry *c2c_right;
528 unsigned int tot_hitm_left;
529 unsigned int tot_hitm_right;
530
531 c2c_left = container_of(left, struct c2c_hist_entry, he);
532 c2c_right = container_of(right, struct c2c_hist_entry, he);
533
534 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
535 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
536
537 return tot_hitm_left - tot_hitm_right;
538}
539
540#define STAT_FN_ENTRY(__f) \
541static int \
542__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
543 struct hist_entry *he) \
544{ \
545 struct c2c_hist_entry *c2c_he; \
546 int width = c2c_width(fmt, hpp, he->hists); \
547 \
548 c2c_he = container_of(he, struct c2c_hist_entry, he); \
549 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
550 c2c_he->stats.__f); \
551}
552
553#define STAT_FN_CMP(__f) \
554static int64_t \
555__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
556 struct hist_entry *left, struct hist_entry *right) \
557{ \
558 struct c2c_hist_entry *c2c_left, *c2c_right; \
559 \
560 c2c_left = container_of(left, struct c2c_hist_entry, he); \
561 c2c_right = container_of(right, struct c2c_hist_entry, he); \
562 return c2c_left->stats.__f - c2c_right->stats.__f; \
563}
564
565#define STAT_FN(__f) \
566 STAT_FN_ENTRY(__f) \
567 STAT_FN_CMP(__f)
568
569STAT_FN(rmt_hitm)
570STAT_FN(lcl_hitm)
Jiri Olsa0f188962016-05-04 10:10:11 +0200571STAT_FN(store)
572STAT_FN(st_l1hit)
573STAT_FN(st_l1miss)
Jiri Olsa1295f682016-05-04 10:18:24 +0200574STAT_FN(ld_fbhit)
575STAT_FN(ld_l1hit)
576STAT_FN(ld_l2hit)
Jiri Olsa4d089102016-05-04 10:27:51 +0200577STAT_FN(ld_llchit)
578STAT_FN(rmt_hit)
Jiri Olsa97cb4862016-05-23 16:20:14 +0200579
Jiri Olsa04402d22016-05-19 10:10:51 +0200580static uint64_t llc_miss(struct c2c_stats *stats)
581{
582 uint64_t llcmiss;
583
584 llcmiss = stats->lcl_dram +
585 stats->rmt_dram +
586 stats->rmt_hitm +
587 stats->rmt_hit;
588
589 return llcmiss;
590}
591
592static int
593ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
594 struct hist_entry *he)
595{
596 struct c2c_hist_entry *c2c_he;
597 int width = c2c_width(fmt, hpp, he->hists);
598
599 c2c_he = container_of(he, struct c2c_hist_entry, he);
600
601 return scnprintf(hpp->buf, hpp->size, "%*lu", width,
602 llc_miss(&c2c_he->stats));
603}
604
605static int64_t
606ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
607 struct hist_entry *left, struct hist_entry *right)
608{
609 struct c2c_hist_entry *c2c_left;
610 struct c2c_hist_entry *c2c_right;
611
612 c2c_left = container_of(left, struct c2c_hist_entry, he);
613 c2c_right = container_of(right, struct c2c_hist_entry, he);
614
615 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
616}
617
Jiri Olsa01b84d72016-05-04 10:35:29 +0200618static uint64_t total_records(struct c2c_stats *stats)
619{
620 uint64_t lclmiss, ldcnt, total;
621
622 lclmiss = stats->lcl_dram +
623 stats->rmt_dram +
624 stats->rmt_hitm +
625 stats->rmt_hit;
626
627 ldcnt = lclmiss +
628 stats->ld_fbhit +
629 stats->ld_l1hit +
630 stats->ld_l2hit +
631 stats->ld_llchit +
632 stats->lcl_hitm;
633
634 total = ldcnt +
635 stats->st_l1hit +
636 stats->st_l1miss;
637
638 return total;
639}
640
641static int
642tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
643 struct hist_entry *he)
644{
645 struct c2c_hist_entry *c2c_he;
646 int width = c2c_width(fmt, hpp, he->hists);
647 uint64_t tot_recs;
648
649 c2c_he = container_of(he, struct c2c_hist_entry, he);
650 tot_recs = total_records(&c2c_he->stats);
651
652 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
653}
654
655static int64_t
656tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
657 struct hist_entry *left, struct hist_entry *right)
658{
659 struct c2c_hist_entry *c2c_left;
660 struct c2c_hist_entry *c2c_right;
661 uint64_t tot_recs_left;
662 uint64_t tot_recs_right;
663
664 c2c_left = container_of(left, struct c2c_hist_entry, he);
665 c2c_right = container_of(right, struct c2c_hist_entry, he);
666
667 tot_recs_left = total_records(&c2c_left->stats);
668 tot_recs_right = total_records(&c2c_right->stats);
669
670 return tot_recs_left - tot_recs_right;
671}
672
Jiri Olsa55177c42016-05-19 09:52:37 +0200673static uint64_t total_loads(struct c2c_stats *stats)
674{
675 uint64_t lclmiss, ldcnt;
676
677 lclmiss = stats->lcl_dram +
678 stats->rmt_dram +
679 stats->rmt_hitm +
680 stats->rmt_hit;
681
682 ldcnt = lclmiss +
683 stats->ld_fbhit +
684 stats->ld_l1hit +
685 stats->ld_l2hit +
686 stats->ld_llchit +
687 stats->lcl_hitm;
688
689 return ldcnt;
690}
691
692static int
693tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
694 struct hist_entry *he)
695{
696 struct c2c_hist_entry *c2c_he;
697 int width = c2c_width(fmt, hpp, he->hists);
698 uint64_t tot_recs;
699
700 c2c_he = container_of(he, struct c2c_hist_entry, he);
701 tot_recs = total_loads(&c2c_he->stats);
702
703 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
704}
705
706static int64_t
707tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
708 struct hist_entry *left, struct hist_entry *right)
709{
710 struct c2c_hist_entry *c2c_left;
711 struct c2c_hist_entry *c2c_right;
712 uint64_t tot_recs_left;
713 uint64_t tot_recs_right;
714
715 c2c_left = container_of(left, struct c2c_hist_entry, he);
716 c2c_right = container_of(right, struct c2c_hist_entry, he);
717
718 tot_recs_left = total_loads(&c2c_left->stats);
719 tot_recs_right = total_loads(&c2c_right->stats);
720
721 return tot_recs_left - tot_recs_right;
722}
723
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200724typedef double (get_percent_cb)(struct c2c_hist_entry *);
725
726static int
727percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
728 struct hist_entry *he, get_percent_cb get_percent)
729{
730 struct c2c_hist_entry *c2c_he;
731 int width = c2c_width(fmt, hpp, he->hists);
732 double per;
733
734 c2c_he = container_of(he, struct c2c_hist_entry, he);
735 per = get_percent(c2c_he);
736
Jiri Olsa5a1a99c2016-01-06 16:59:02 +0100737#ifdef HAVE_SLANG_SUPPORT
738 if (use_browser)
739 return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
740#endif
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200741 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
742}
743
744static double percent_hitm(struct c2c_hist_entry *c2c_he)
745{
746 struct c2c_hists *hists;
747 struct c2c_stats *stats;
748 struct c2c_stats *total;
Jiri Olsa55b95772016-05-29 10:21:45 +0200749 int tot = 0, st = 0;
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200750 double p;
751
752 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
753 stats = &c2c_he->stats;
754 total = &hists->stats;
755
Jiri Olsa55b95772016-05-29 10:21:45 +0200756 switch (c2c.display) {
757 case DISPLAY_RMT:
758 st = stats->rmt_hitm;
759 tot = total->rmt_hitm;
760 break;
761 case DISPLAY_LCL:
762 st = stats->lcl_hitm;
763 tot = total->lcl_hitm;
Jiri Olsad940bac2016-11-21 22:33:30 +0100764 break;
765 case DISPLAY_TOT:
766 st = stats->tot_hitm;
767 tot = total->tot_hitm;
Jiri Olsa55b95772016-05-29 10:21:45 +0200768 default:
769 break;
770 }
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200771
772 p = tot ? (double) st / tot : 0;
773
774 return 100 * p;
775}
776
777#define PERC_STR(__s, __v) \
778({ \
779 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
780 __s; \
781})
782
783static int
784percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
785 struct hist_entry *he)
786{
787 struct c2c_hist_entry *c2c_he;
788 int width = c2c_width(fmt, hpp, he->hists);
789 char buf[10];
790 double per;
791
792 c2c_he = container_of(he, struct c2c_hist_entry, he);
793 per = percent_hitm(c2c_he);
794 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
795}
796
797static int
798percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
799 struct hist_entry *he)
800{
801 return percent_color(fmt, hpp, he, percent_hitm);
802}
803
804static int64_t
805percent_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
806 struct hist_entry *left, struct hist_entry *right)
807{
808 struct c2c_hist_entry *c2c_left;
809 struct c2c_hist_entry *c2c_right;
810 double per_left;
811 double per_right;
812
813 c2c_left = container_of(left, struct c2c_hist_entry, he);
814 c2c_right = container_of(right, struct c2c_hist_entry, he);
815
816 per_left = percent_hitm(c2c_left);
817 per_right = percent_hitm(c2c_right);
818
819 return per_left - per_right;
820}
821
Jiri Olsa9cb35002016-05-04 12:16:50 +0200822static struct c2c_stats *he_stats(struct hist_entry *he)
823{
824 struct c2c_hist_entry *c2c_he;
825
826 c2c_he = container_of(he, struct c2c_hist_entry, he);
827 return &c2c_he->stats;
828}
829
830static struct c2c_stats *total_stats(struct hist_entry *he)
831{
832 struct c2c_hists *hists;
833
834 hists = container_of(he->hists, struct c2c_hists, hists);
835 return &hists->stats;
836}
837
838static double percent(int st, int tot)
839{
840 return tot ? 100. * (double) st / (double) tot : 0;
841}
842
843#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
844
845#define PERCENT_FN(__f) \
846static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
847{ \
848 struct c2c_hists *hists; \
849 \
850 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
851 return percent(c2c_he->stats.__f, hists->stats.__f); \
852}
853
854PERCENT_FN(rmt_hitm)
855PERCENT_FN(lcl_hitm)
856PERCENT_FN(st_l1hit)
857PERCENT_FN(st_l1miss)
858
859static int
860percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
861 struct hist_entry *he)
862{
863 int width = c2c_width(fmt, hpp, he->hists);
864 double per = PERCENT(he, rmt_hitm);
865 char buf[10];
866
867 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
868}
869
870static int
871percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
872 struct hist_entry *he)
873{
874 return percent_color(fmt, hpp, he, percent_rmt_hitm);
875}
876
877static int64_t
878percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
879 struct hist_entry *left, struct hist_entry *right)
880{
881 double per_left;
882 double per_right;
883
884 per_left = PERCENT(left, lcl_hitm);
885 per_right = PERCENT(right, lcl_hitm);
886
887 return per_left - per_right;
888}
889
890static int
891percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
892 struct hist_entry *he)
893{
894 int width = c2c_width(fmt, hpp, he->hists);
895 double per = PERCENT(he, lcl_hitm);
896 char buf[10];
897
898 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
899}
900
901static int
902percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
903 struct hist_entry *he)
904{
905 return percent_color(fmt, hpp, he, percent_lcl_hitm);
906}
907
908static int64_t
909percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
910 struct hist_entry *left, struct hist_entry *right)
911{
912 double per_left;
913 double per_right;
914
915 per_left = PERCENT(left, lcl_hitm);
916 per_right = PERCENT(right, lcl_hitm);
917
918 return per_left - per_right;
919}
920
921static int
922percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
923 struct hist_entry *he)
924{
925 int width = c2c_width(fmt, hpp, he->hists);
926 double per = PERCENT(he, st_l1hit);
927 char buf[10];
928
929 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
930}
931
932static int
933percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
934 struct hist_entry *he)
935{
936 return percent_color(fmt, hpp, he, percent_st_l1hit);
937}
938
939static int64_t
940percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
941 struct hist_entry *left, struct hist_entry *right)
942{
943 double per_left;
944 double per_right;
945
946 per_left = PERCENT(left, st_l1hit);
947 per_right = PERCENT(right, st_l1hit);
948
949 return per_left - per_right;
950}
951
952static int
953percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
954 struct hist_entry *he)
955{
956 int width = c2c_width(fmt, hpp, he->hists);
957 double per = PERCENT(he, st_l1miss);
958 char buf[10];
959
960 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
961}
962
963static int
964percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
965 struct hist_entry *he)
966{
967 return percent_color(fmt, hpp, he, percent_st_l1miss);
968}
969
970static int64_t
971percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
972 struct hist_entry *left, struct hist_entry *right)
973{
974 double per_left;
975 double per_right;
976
977 per_left = PERCENT(left, st_l1miss);
978 per_right = PERCENT(right, st_l1miss);
979
980 return per_left - per_right;
981}
982
Jiri Olsa6c70f542016-05-28 12:30:13 +0200983STAT_FN(lcl_dram)
984STAT_FN(rmt_dram)
985
Jiri Olsa36d3deb2016-05-24 13:09:47 +0200986static int
987pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
988 struct hist_entry *he)
989{
990 int width = c2c_width(fmt, hpp, he->hists);
991
992 return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
993}
994
995static int64_t
996pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
997 struct hist_entry *left, struct hist_entry *right)
998{
999 return left->thread->pid_ - right->thread->pid_;
1000}
1001
Jiri Olsa1e181b92016-06-03 15:40:28 +02001002static int64_t
1003empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1004 struct hist_entry *left __maybe_unused,
1005 struct hist_entry *right __maybe_unused)
1006{
1007 return 0;
1008}
1009
1010static int
1011node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1012 struct hist_entry *he)
1013{
1014 struct c2c_hist_entry *c2c_he;
1015 bool first = true;
1016 int node;
1017 int ret = 0;
1018
1019 c2c_he = container_of(he, struct c2c_hist_entry, he);
1020
1021 for (node = 0; node < c2c.nodes_cnt; node++) {
1022 DECLARE_BITMAP(set, c2c.cpus_cnt);
1023
1024 bitmap_zero(set, c2c.cpus_cnt);
1025 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
1026
1027 if (!bitmap_weight(set, c2c.cpus_cnt)) {
1028 if (c2c.node_info == 1) {
1029 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
1030 advance_hpp(hpp, ret);
1031 }
1032 continue;
1033 }
1034
1035 if (!first) {
1036 ret = scnprintf(hpp->buf, hpp->size, " ");
1037 advance_hpp(hpp, ret);
1038 }
1039
1040 switch (c2c.node_info) {
1041 case 0:
1042 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
1043 advance_hpp(hpp, ret);
1044 break;
1045 case 1:
1046 {
1047 int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
1048 struct c2c_stats *stats = &c2c_he->node_stats[node];
1049
1050 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
1051 advance_hpp(hpp, ret);
1052
Jiri Olsa55b95772016-05-29 10:21:45 +02001053 #define DISPLAY_HITM(__h) \
1054 if (c2c_he->stats.__h> 0) { \
1055 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", \
1056 percent(stats->__h, c2c_he->stats.__h));\
1057 } else { \
1058 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); \
Jiri Olsa1e181b92016-06-03 15:40:28 +02001059 }
1060
Jiri Olsa55b95772016-05-29 10:21:45 +02001061 switch (c2c.display) {
1062 case DISPLAY_RMT:
1063 DISPLAY_HITM(rmt_hitm);
1064 break;
1065 case DISPLAY_LCL:
1066 DISPLAY_HITM(lcl_hitm);
Jiri Olsad940bac2016-11-21 22:33:30 +01001067 break;
1068 case DISPLAY_TOT:
1069 DISPLAY_HITM(tot_hitm);
Jiri Olsa55b95772016-05-29 10:21:45 +02001070 default:
1071 break;
1072 }
1073
1074 #undef DISPLAY_HITM
1075
Jiri Olsa1e181b92016-06-03 15:40:28 +02001076 advance_hpp(hpp, ret);
1077
1078 if (c2c_he->stats.store > 0) {
1079 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
1080 percent(stats->store, c2c_he->stats.store));
1081 } else {
1082 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
1083 }
1084
1085 advance_hpp(hpp, ret);
1086 break;
1087 }
1088 case 2:
1089 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
1090 advance_hpp(hpp, ret);
1091
1092 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
1093 advance_hpp(hpp, ret);
1094
1095 ret = scnprintf(hpp->buf, hpp->size, "}");
1096 advance_hpp(hpp, ret);
1097 break;
1098 default:
1099 break;
1100 }
1101
1102 first = false;
1103 }
1104
1105 return 0;
1106}
1107
Jiri Olsa92062d52016-06-05 13:40:53 +02001108static int
1109mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1110 struct hist_entry *he, double mean)
1111{
1112 int width = c2c_width(fmt, hpp, he->hists);
1113 char buf[10];
1114
1115 scnprintf(buf, 10, "%6.0f", mean);
1116 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1117}
1118
1119#define MEAN_ENTRY(__func, __val) \
1120static int \
1121__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1122{ \
1123 struct c2c_hist_entry *c2c_he; \
1124 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1125 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1126}
1127
1128MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1129MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1130MEAN_ENTRY(mean_load_entry, load);
1131
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001132static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001133cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001134 struct hist_entry *he)
1135{
1136 struct c2c_hist_entry *c2c_he;
1137 int width = c2c_width(fmt, hpp, he->hists);
1138 char buf[10];
1139
1140 c2c_he = container_of(he, struct c2c_hist_entry, he);
1141
1142 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1143 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1144}
1145
Jiri Olsabb342da2016-07-06 15:40:09 +02001146static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001147cl_idx_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsabb342da2016-07-06 15:40:09 +02001148 struct hist_entry *he)
1149{
1150 struct c2c_hist_entry *c2c_he;
1151 int width = c2c_width(fmt, hpp, he->hists);
1152 char buf[10];
1153
1154 c2c_he = container_of(he, struct c2c_hist_entry, he);
1155
1156 scnprintf(buf, 10, "%u", c2c_he->cacheline_idx);
1157 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1158}
1159
1160static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001161cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsabb342da2016-07-06 15:40:09 +02001162 struct hist_entry *he)
1163{
1164 int width = c2c_width(fmt, hpp, he->hists);
1165
1166 return scnprintf(hpp->buf, hpp->size, "%*s", width, "");
1167}
1168
Jiri Olsa600a8cf2016-09-22 17:36:47 +02001169#define HEADER_LOW(__h) \
1170 { \
1171 .line[1] = { \
1172 .text = __h, \
1173 }, \
1174 }
1175
1176#define HEADER_BOTH(__h0, __h1) \
1177 { \
1178 .line[0] = { \
1179 .text = __h0, \
1180 }, \
1181 .line[1] = { \
1182 .text = __h1, \
1183 }, \
1184 }
1185
1186#define HEADER_SPAN(__h0, __h1, __s) \
1187 { \
1188 .line[0] = { \
1189 .text = __h0, \
1190 .span = __s, \
1191 }, \
1192 .line[1] = { \
1193 .text = __h1, \
1194 }, \
1195 }
1196
1197#define HEADER_SPAN_LOW(__h) \
1198 { \
1199 .line[1] = { \
1200 .text = __h, \
1201 }, \
1202 }
1203
Jiri Olsacbb88502016-09-22 17:36:48 +02001204static struct c2c_dimension dim_dcacheline = {
1205 .header = HEADER_LOW("Cacheline"),
1206 .name = "dcacheline",
1207 .cmp = dcacheline_cmp,
1208 .entry = dcacheline_entry,
1209 .width = 18,
1210};
1211
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001212static struct c2c_header header_offset_tui = HEADER_LOW("Off");
1213
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001214static struct c2c_dimension dim_offset = {
1215 .header = HEADER_BOTH("Data address", "Offset"),
1216 .name = "offset",
1217 .cmp = offset_cmp,
1218 .entry = offset_entry,
1219 .width = 18,
1220};
1221
Jiri Olsa43575a92016-05-03 21:48:56 +02001222static struct c2c_dimension dim_iaddr = {
1223 .header = HEADER_LOW("Code address"),
1224 .name = "iaddr",
1225 .cmp = iaddr_cmp,
1226 .entry = iaddr_entry,
1227 .width = 18,
1228};
1229
Jiri Olsa97cb4862016-05-23 16:20:14 +02001230static struct c2c_dimension dim_tot_hitm = {
1231 .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1232 .name = "tot_hitm",
1233 .cmp = tot_hitm_cmp,
1234 .entry = tot_hitm_entry,
1235 .width = 7,
1236};
1237
1238static struct c2c_dimension dim_lcl_hitm = {
1239 .header = HEADER_SPAN_LOW("Lcl"),
1240 .name = "lcl_hitm",
1241 .cmp = lcl_hitm_cmp,
1242 .entry = lcl_hitm_entry,
1243 .width = 7,
1244};
1245
1246static struct c2c_dimension dim_rmt_hitm = {
1247 .header = HEADER_SPAN_LOW("Rmt"),
1248 .name = "rmt_hitm",
1249 .cmp = rmt_hitm_cmp,
1250 .entry = rmt_hitm_entry,
1251 .width = 7,
1252};
1253
1254static struct c2c_dimension dim_cl_rmt_hitm = {
1255 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1256 .name = "cl_rmt_hitm",
1257 .cmp = rmt_hitm_cmp,
1258 .entry = rmt_hitm_entry,
1259 .width = 7,
1260};
1261
1262static struct c2c_dimension dim_cl_lcl_hitm = {
1263 .header = HEADER_SPAN_LOW("Lcl"),
1264 .name = "cl_lcl_hitm",
1265 .cmp = lcl_hitm_cmp,
1266 .entry = lcl_hitm_entry,
1267 .width = 7,
1268};
1269
Jiri Olsa0f188962016-05-04 10:10:11 +02001270static struct c2c_dimension dim_stores = {
1271 .header = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1272 .name = "stores",
1273 .cmp = store_cmp,
1274 .entry = store_entry,
1275 .width = 7,
1276};
1277
1278static struct c2c_dimension dim_stores_l1hit = {
1279 .header = HEADER_SPAN_LOW("L1Hit"),
1280 .name = "stores_l1hit",
1281 .cmp = st_l1hit_cmp,
1282 .entry = st_l1hit_entry,
1283 .width = 7,
1284};
1285
1286static struct c2c_dimension dim_stores_l1miss = {
1287 .header = HEADER_SPAN_LOW("L1Miss"),
1288 .name = "stores_l1miss",
1289 .cmp = st_l1miss_cmp,
1290 .entry = st_l1miss_entry,
1291 .width = 7,
1292};
1293
1294static struct c2c_dimension dim_cl_stores_l1hit = {
1295 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1296 .name = "cl_stores_l1hit",
1297 .cmp = st_l1hit_cmp,
1298 .entry = st_l1hit_entry,
1299 .width = 7,
1300};
1301
1302static struct c2c_dimension dim_cl_stores_l1miss = {
1303 .header = HEADER_SPAN_LOW("L1 Miss"),
1304 .name = "cl_stores_l1miss",
1305 .cmp = st_l1miss_cmp,
1306 .entry = st_l1miss_entry,
1307 .width = 7,
1308};
1309
Jiri Olsa1295f682016-05-04 10:18:24 +02001310static struct c2c_dimension dim_ld_fbhit = {
1311 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1312 .name = "ld_fbhit",
1313 .cmp = ld_fbhit_cmp,
1314 .entry = ld_fbhit_entry,
1315 .width = 7,
1316};
1317
1318static struct c2c_dimension dim_ld_l1hit = {
1319 .header = HEADER_SPAN_LOW("L1"),
1320 .name = "ld_l1hit",
1321 .cmp = ld_l1hit_cmp,
1322 .entry = ld_l1hit_entry,
1323 .width = 7,
1324};
1325
1326static struct c2c_dimension dim_ld_l2hit = {
1327 .header = HEADER_SPAN_LOW("L2"),
1328 .name = "ld_l2hit",
1329 .cmp = ld_l2hit_cmp,
1330 .entry = ld_l2hit_entry,
1331 .width = 7,
1332};
1333
Jiri Olsa4d089102016-05-04 10:27:51 +02001334static struct c2c_dimension dim_ld_llchit = {
1335 .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1336 .name = "ld_lclhit",
1337 .cmp = ld_llchit_cmp,
1338 .entry = ld_llchit_entry,
1339 .width = 8,
1340};
1341
1342static struct c2c_dimension dim_ld_rmthit = {
1343 .header = HEADER_SPAN_LOW("Rmt"),
1344 .name = "ld_rmthit",
1345 .cmp = rmt_hit_cmp,
1346 .entry = rmt_hit_entry,
1347 .width = 8,
1348};
1349
Jiri Olsa04402d22016-05-19 10:10:51 +02001350static struct c2c_dimension dim_ld_llcmiss = {
1351 .header = HEADER_BOTH("LLC", "Ld Miss"),
1352 .name = "ld_llcmiss",
1353 .cmp = ld_llcmiss_cmp,
1354 .entry = ld_llcmiss_entry,
1355 .width = 7,
1356};
1357
Jiri Olsa01b84d72016-05-04 10:35:29 +02001358static struct c2c_dimension dim_tot_recs = {
1359 .header = HEADER_BOTH("Total", "records"),
1360 .name = "tot_recs",
1361 .cmp = tot_recs_cmp,
1362 .entry = tot_recs_entry,
1363 .width = 7,
1364};
1365
Jiri Olsa55177c42016-05-19 09:52:37 +02001366static struct c2c_dimension dim_tot_loads = {
1367 .header = HEADER_BOTH("Total", "Loads"),
1368 .name = "tot_loads",
1369 .cmp = tot_loads_cmp,
1370 .entry = tot_loads_entry,
1371 .width = 7,
1372};
1373
Jiri Olsa55b95772016-05-29 10:21:45 +02001374static struct c2c_header percent_hitm_header[] = {
1375 [DISPLAY_LCL] = HEADER_BOTH("Lcl", "Hitm"),
1376 [DISPLAY_RMT] = HEADER_BOTH("Rmt", "Hitm"),
Jiri Olsad940bac2016-11-21 22:33:30 +01001377 [DISPLAY_TOT] = HEADER_BOTH("Tot", "Hitm"),
Jiri Olsa55b95772016-05-29 10:21:45 +02001378};
1379
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001380static struct c2c_dimension dim_percent_hitm = {
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001381 .name = "percent_hitm",
1382 .cmp = percent_hitm_cmp,
1383 .entry = percent_hitm_entry,
1384 .color = percent_hitm_color,
1385 .width = 7,
1386};
1387
Jiri Olsa9cb35002016-05-04 12:16:50 +02001388static struct c2c_dimension dim_percent_rmt_hitm = {
1389 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1390 .name = "percent_rmt_hitm",
1391 .cmp = percent_rmt_hitm_cmp,
1392 .entry = percent_rmt_hitm_entry,
1393 .color = percent_rmt_hitm_color,
1394 .width = 7,
1395};
1396
1397static struct c2c_dimension dim_percent_lcl_hitm = {
1398 .header = HEADER_SPAN_LOW("Lcl"),
1399 .name = "percent_lcl_hitm",
1400 .cmp = percent_lcl_hitm_cmp,
1401 .entry = percent_lcl_hitm_entry,
1402 .color = percent_lcl_hitm_color,
1403 .width = 7,
1404};
1405
1406static struct c2c_dimension dim_percent_stores_l1hit = {
1407 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1408 .name = "percent_stores_l1hit",
1409 .cmp = percent_stores_l1hit_cmp,
1410 .entry = percent_stores_l1hit_entry,
1411 .color = percent_stores_l1hit_color,
1412 .width = 7,
1413};
1414
1415static struct c2c_dimension dim_percent_stores_l1miss = {
1416 .header = HEADER_SPAN_LOW("L1 Miss"),
1417 .name = "percent_stores_l1miss",
1418 .cmp = percent_stores_l1miss_cmp,
1419 .entry = percent_stores_l1miss_entry,
1420 .color = percent_stores_l1miss_color,
1421 .width = 7,
1422};
1423
Jiri Olsa6c70f542016-05-28 12:30:13 +02001424static struct c2c_dimension dim_dram_lcl = {
1425 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1426 .name = "dram_lcl",
1427 .cmp = lcl_dram_cmp,
1428 .entry = lcl_dram_entry,
1429 .width = 8,
1430};
1431
1432static struct c2c_dimension dim_dram_rmt = {
1433 .header = HEADER_SPAN_LOW("Rmt"),
1434 .name = "dram_rmt",
1435 .cmp = rmt_dram_cmp,
1436 .entry = rmt_dram_entry,
1437 .width = 8,
1438};
1439
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001440static struct c2c_dimension dim_pid = {
1441 .header = HEADER_LOW("Pid"),
1442 .name = "pid",
1443 .cmp = pid_cmp,
1444 .entry = pid_entry,
1445 .width = 7,
1446};
1447
Jiri Olsae87019c2016-05-25 08:50:10 +02001448static struct c2c_dimension dim_tid = {
1449 .header = HEADER_LOW("Tid"),
1450 .name = "tid",
1451 .se = &sort_thread,
1452};
1453
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001454static struct c2c_dimension dim_symbol = {
1455 .name = "symbol",
1456 .se = &sort_sym,
1457};
1458
1459static struct c2c_dimension dim_dso = {
1460 .header = HEADER_BOTH("Shared", "Object"),
1461 .name = "dso",
1462 .se = &sort_dso,
1463};
1464
Jiri Olsa1e181b92016-06-03 15:40:28 +02001465static struct c2c_header header_node[3] = {
1466 HEADER_LOW("Node"),
1467 HEADER_LOW("Node{cpus %hitms %stores}"),
1468 HEADER_LOW("Node{cpu list}"),
1469};
1470
1471static struct c2c_dimension dim_node = {
1472 .name = "node",
1473 .cmp = empty_cmp,
1474 .entry = node_entry,
1475 .width = 4,
1476};
1477
Jiri Olsa92062d52016-06-05 13:40:53 +02001478static struct c2c_dimension dim_mean_rmt = {
1479 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1480 .name = "mean_rmt",
1481 .cmp = empty_cmp,
1482 .entry = mean_rmt_entry,
1483 .width = 8,
1484};
1485
1486static struct c2c_dimension dim_mean_lcl = {
1487 .header = HEADER_SPAN_LOW("lcl hitm"),
1488 .name = "mean_lcl",
1489 .cmp = empty_cmp,
1490 .entry = mean_lcl_entry,
1491 .width = 8,
1492};
1493
1494static struct c2c_dimension dim_mean_load = {
1495 .header = HEADER_SPAN_LOW("load"),
1496 .name = "mean_load",
1497 .cmp = empty_cmp,
1498 .entry = mean_load_entry,
1499 .width = 8,
1500};
1501
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001502static struct c2c_dimension dim_cpucnt = {
1503 .header = HEADER_BOTH("cpu", "cnt"),
1504 .name = "cpucnt",
1505 .cmp = empty_cmp,
1506 .entry = cpucnt_entry,
1507 .width = 8,
1508};
1509
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001510static struct c2c_dimension dim_srcline = {
1511 .name = "cl_srcline",
1512 .se = &sort_srcline,
1513};
1514
Jiri Olsabb342da2016-07-06 15:40:09 +02001515static struct c2c_dimension dim_dcacheline_idx = {
1516 .header = HEADER_LOW("Index"),
1517 .name = "cl_idx",
1518 .cmp = empty_cmp,
1519 .entry = cl_idx_entry,
1520 .width = 5,
1521};
1522
1523static struct c2c_dimension dim_dcacheline_num = {
1524 .header = HEADER_LOW("Num"),
1525 .name = "cl_num",
1526 .cmp = empty_cmp,
1527 .entry = cl_idx_entry,
1528 .width = 5,
1529};
1530
1531static struct c2c_dimension dim_dcacheline_num_empty = {
1532 .header = HEADER_LOW("Num"),
1533 .name = "cl_num_empty",
1534 .cmp = empty_cmp,
1535 .entry = cl_idx_empty_entry,
1536 .width = 5,
1537};
1538
Jiri Olsac75540e2016-09-22 17:36:41 +02001539static struct c2c_dimension *dimensions[] = {
Jiri Olsacbb88502016-09-22 17:36:48 +02001540 &dim_dcacheline,
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001541 &dim_offset,
Jiri Olsa43575a92016-05-03 21:48:56 +02001542 &dim_iaddr,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001543 &dim_tot_hitm,
1544 &dim_lcl_hitm,
1545 &dim_rmt_hitm,
1546 &dim_cl_lcl_hitm,
1547 &dim_cl_rmt_hitm,
Jiri Olsa0f188962016-05-04 10:10:11 +02001548 &dim_stores,
1549 &dim_stores_l1hit,
1550 &dim_stores_l1miss,
1551 &dim_cl_stores_l1hit,
1552 &dim_cl_stores_l1miss,
Jiri Olsa1295f682016-05-04 10:18:24 +02001553 &dim_ld_fbhit,
1554 &dim_ld_l1hit,
1555 &dim_ld_l2hit,
Jiri Olsa4d089102016-05-04 10:27:51 +02001556 &dim_ld_llchit,
1557 &dim_ld_rmthit,
Jiri Olsa04402d22016-05-19 10:10:51 +02001558 &dim_ld_llcmiss,
Jiri Olsa01b84d72016-05-04 10:35:29 +02001559 &dim_tot_recs,
Jiri Olsa55177c42016-05-19 09:52:37 +02001560 &dim_tot_loads,
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001561 &dim_percent_hitm,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001562 &dim_percent_rmt_hitm,
1563 &dim_percent_lcl_hitm,
1564 &dim_percent_stores_l1hit,
1565 &dim_percent_stores_l1miss,
Jiri Olsa6c70f542016-05-28 12:30:13 +02001566 &dim_dram_lcl,
1567 &dim_dram_rmt,
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001568 &dim_pid,
Jiri Olsae87019c2016-05-25 08:50:10 +02001569 &dim_tid,
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001570 &dim_symbol,
1571 &dim_dso,
Jiri Olsa1e181b92016-06-03 15:40:28 +02001572 &dim_node,
Jiri Olsa92062d52016-06-05 13:40:53 +02001573 &dim_mean_rmt,
1574 &dim_mean_lcl,
1575 &dim_mean_load,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001576 &dim_cpucnt,
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001577 &dim_srcline,
Jiri Olsabb342da2016-07-06 15:40:09 +02001578 &dim_dcacheline_idx,
1579 &dim_dcacheline_num,
1580 &dim_dcacheline_num_empty,
Jiri Olsac75540e2016-09-22 17:36:41 +02001581 NULL,
1582};
1583
1584static void fmt_free(struct perf_hpp_fmt *fmt)
1585{
1586 struct c2c_fmt *c2c_fmt;
1587
1588 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1589 free(c2c_fmt);
1590}
1591
1592static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1593{
1594 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1595 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1596
1597 return c2c_a->dim == c2c_b->dim;
1598}
1599
1600static struct c2c_dimension *get_dimension(const char *name)
1601{
1602 unsigned int i;
1603
1604 for (i = 0; dimensions[i]; i++) {
1605 struct c2c_dimension *dim = dimensions[i];
1606
1607 if (!strcmp(dim->name, name))
1608 return dim;
1609 };
1610
1611 return NULL;
1612}
1613
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001614static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1615 struct hist_entry *he)
1616{
1617 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1618 struct c2c_dimension *dim = c2c_fmt->dim;
1619 size_t len = fmt->user_len;
1620
Jiri Olsa590b6a32016-07-10 16:25:15 +02001621 if (!len) {
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001622 len = hists__col_len(he->hists, dim->se->se_width_idx);
1623
Jiri Olsa590b6a32016-07-10 16:25:15 +02001624 if (dim == &dim_symbol || dim == &dim_srcline)
1625 len = symbol_width(he->hists, dim->se);
1626 }
1627
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001628 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1629}
1630
1631static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1632 struct hist_entry *a, struct hist_entry *b)
1633{
1634 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1635 struct c2c_dimension *dim = c2c_fmt->dim;
1636
1637 return dim->se->se_cmp(a, b);
1638}
1639
1640static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1641 struct hist_entry *a, struct hist_entry *b)
1642{
1643 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1644 struct c2c_dimension *dim = c2c_fmt->dim;
1645 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1646
1647 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1648 return collapse_fn(a, b);
1649}
1650
Jiri Olsac75540e2016-09-22 17:36:41 +02001651static struct c2c_fmt *get_format(const char *name)
1652{
1653 struct c2c_dimension *dim = get_dimension(name);
1654 struct c2c_fmt *c2c_fmt;
1655 struct perf_hpp_fmt *fmt;
1656
1657 if (!dim)
1658 return NULL;
1659
1660 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1661 if (!c2c_fmt)
1662 return NULL;
1663
1664 c2c_fmt->dim = dim;
1665
1666 fmt = &c2c_fmt->fmt;
1667 INIT_LIST_HEAD(&fmt->list);
1668 INIT_LIST_HEAD(&fmt->sort_list);
1669
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001670 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1671 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
Jiri Olsa9cb35002016-05-04 12:16:50 +02001672 fmt->color = dim->se ? NULL : dim->color;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001673 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
Jiri Olsac75540e2016-09-22 17:36:41 +02001674 fmt->header = c2c_header;
1675 fmt->width = c2c_width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001676 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
Jiri Olsac75540e2016-09-22 17:36:41 +02001677 fmt->equal = fmt_equal;
1678 fmt->free = fmt_free;
1679
1680 return c2c_fmt;
1681}
1682
1683static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1684{
1685 struct c2c_fmt *c2c_fmt = get_format(name);
1686
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001687 if (!c2c_fmt) {
1688 reset_dimensions();
1689 return output_field_add(hpp_list, name);
1690 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001691
1692 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1693 return 0;
1694}
1695
1696static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1697{
1698 struct c2c_fmt *c2c_fmt = get_format(name);
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001699 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +02001700
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001701 if (!c2c_fmt) {
1702 reset_dimensions();
1703 return sort_dimension__add(hpp_list, name, NULL, 0);
1704 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001705
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001706 dim = c2c_fmt->dim;
1707 if (dim == &dim_dso)
1708 hpp_list->dso = 1;
1709
Jiri Olsac75540e2016-09-22 17:36:41 +02001710 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1711 return 0;
1712}
1713
1714#define PARSE_LIST(_list, _fn) \
1715 do { \
1716 char *tmp, *tok; \
1717 ret = 0; \
1718 \
1719 if (!_list) \
1720 break; \
1721 \
1722 for (tok = strtok_r((char *)_list, ", ", &tmp); \
1723 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
1724 ret = _fn(hpp_list, tok); \
1725 if (ret == -EINVAL) { \
1726 error("Invalid --fields key: `%s'", tok); \
1727 break; \
1728 } else if (ret == -ESRCH) { \
1729 error("Unknown --fields key: `%s'", tok); \
1730 break; \
1731 } \
1732 } \
1733 } while (0)
1734
1735static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1736 const char *output_,
1737 const char *sort_)
1738{
1739 char *output = output_ ? strdup(output_) : NULL;
1740 char *sort = sort_ ? strdup(sort_) : NULL;
1741 int ret;
1742
1743 PARSE_LIST(output, c2c_hists__init_output);
1744 PARSE_LIST(sort, c2c_hists__init_sort);
1745
1746 /* copy sort keys to output fields */
1747 perf_hpp__setup_output_field(hpp_list);
1748
1749 /*
1750 * We dont need other sorting keys other than those
1751 * we already specified. It also really slows down
1752 * the processing a lot with big number of output
1753 * fields, so switching this off for c2c.
1754 */
1755
1756#if 0
1757 /* and then copy output fields to sort keys */
1758 perf_hpp__append_sort_keys(&hists->list);
1759#endif
1760
1761 free(output);
1762 free(sort);
1763 return ret;
1764}
1765
1766static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001767 const char *sort,
1768 int nr_header_lines)
Jiri Olsac75540e2016-09-22 17:36:41 +02001769{
1770 __hists__init(&hists->hists, &hists->list);
1771
1772 /*
1773 * Initialize only with sort fields, we need to resort
1774 * later anyway, and that's where we add output fields
1775 * as well.
1776 */
1777 perf_hpp_list__init(&hists->list);
1778
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02001779 /* Overload number of header lines.*/
1780 hists->list.nr_header_lines = nr_header_lines;
1781
Jiri Olsac75540e2016-09-22 17:36:41 +02001782 return hpp_list__parse(&hists->list, NULL, sort);
1783}
1784
Jiri Olsac75540e2016-09-22 17:36:41 +02001785static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1786 const char *output,
1787 const char *sort)
1788{
1789 perf_hpp__reset_output_field(&c2c_hists->list);
1790 return hpp_list__parse(&c2c_hists->list, output, sort);
1791}
1792
Jiri Olsa9857b712016-08-17 14:55:23 +02001793#define DISPLAY_LINE_LIMIT 0.0005
1794
1795static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
1796{
1797 struct c2c_hist_entry *c2c_he;
1798 double ld_dist;
1799
Jiri Olsaaf09b2d2016-10-11 13:52:05 +02001800 if (c2c.show_all)
1801 return true;
Jiri Olsa9857b712016-08-17 14:55:23 +02001802
1803 c2c_he = container_of(he, struct c2c_hist_entry, he);
1804
Jiri Olsa55b95772016-05-29 10:21:45 +02001805#define FILTER_HITM(__h) \
1806 if (stats->__h) { \
1807 ld_dist = ((double)c2c_he->stats.__h / stats->__h); \
1808 if (ld_dist < DISPLAY_LINE_LIMIT) \
1809 he->filtered = HIST_FILTER__C2C; \
1810 } else { \
1811 he->filtered = HIST_FILTER__C2C; \
Jiri Olsa9857b712016-08-17 14:55:23 +02001812 }
1813
Jiri Olsa55b95772016-05-29 10:21:45 +02001814 switch (c2c.display) {
1815 case DISPLAY_LCL:
1816 FILTER_HITM(lcl_hitm);
1817 break;
1818 case DISPLAY_RMT:
1819 FILTER_HITM(rmt_hitm);
Jiri Olsad940bac2016-11-21 22:33:30 +01001820 break;
1821 case DISPLAY_TOT:
1822 FILTER_HITM(tot_hitm);
Jiri Olsa55b95772016-05-29 10:21:45 +02001823 default:
1824 break;
1825 };
1826
1827#undef FILTER_HITM
1828
Jiri Olsa9857b712016-08-17 14:55:23 +02001829 return he->filtered == 0;
1830}
1831
1832static inline int valid_hitm_or_store(struct hist_entry *he)
1833{
1834 struct c2c_hist_entry *c2c_he;
Jiri Olsa55b95772016-05-29 10:21:45 +02001835 bool has_hitm;
Jiri Olsa9857b712016-08-17 14:55:23 +02001836
1837 c2c_he = container_of(he, struct c2c_hist_entry, he);
Jiri Olsad940bac2016-11-21 22:33:30 +01001838 has_hitm = c2c.display == DISPLAY_TOT ? c2c_he->stats.tot_hitm :
1839 c2c.display == DISPLAY_LCL ? c2c_he->stats.lcl_hitm :
1840 c2c_he->stats.rmt_hitm;
Jiri Olsa55b95772016-05-29 10:21:45 +02001841 return has_hitm || c2c_he->stats.store;
Jiri Olsa9857b712016-08-17 14:55:23 +02001842}
1843
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001844static void calc_width(struct hist_entry *he)
1845{
1846 struct c2c_hists *c2c_hists;
1847
1848 c2c_hists = container_of(he->hists, struct c2c_hists, hists);
1849 hists__calc_col_len(&c2c_hists->hists, he);
1850}
1851
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001852static int filter_cb(struct hist_entry *he)
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001853{
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001854 if (c2c.show_src && !he->srcline)
1855 he->srcline = hist_entry__get_srcline(he);
1856
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001857 calc_width(he);
1858
Jiri Olsa9857b712016-08-17 14:55:23 +02001859 if (!valid_hitm_or_store(he))
1860 he->filtered = HIST_FILTER__C2C;
1861
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001862 return 0;
1863}
1864
1865static int resort_cl_cb(struct hist_entry *he)
1866{
1867 struct c2c_hist_entry *c2c_he;
1868 struct c2c_hists *c2c_hists;
Jiri Olsa9857b712016-08-17 14:55:23 +02001869 bool display = he__display(he, &c2c.hitm_stats);
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001870
1871 c2c_he = container_of(he, struct c2c_hist_entry, he);
1872 c2c_hists = c2c_he->hists;
1873
Jiri Olsa25aa84e2016-06-07 19:02:43 +02001874 calc_width(he);
1875
Jiri Olsa9857b712016-08-17 14:55:23 +02001876 if (display && c2c_hists) {
Jiri Olsabb342da2016-07-06 15:40:09 +02001877 static unsigned int idx;
1878
1879 c2c_he->cacheline_idx = idx++;
1880
Jiri Olsafc9c6302016-05-24 14:14:38 +02001881 c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort);
Jiri Olsa22dd59d2016-05-10 14:08:29 +02001882
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001883 hists__collapse_resort(&c2c_hists->hists, NULL);
1884 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
1885 }
1886
1887 return 0;
1888}
1889
Jiri Olsa1e181b92016-06-03 15:40:28 +02001890static void setup_nodes_header(void)
1891{
1892 dim_node.header = header_node[c2c.node_info];
1893}
1894
1895static int setup_nodes(struct perf_session *session)
1896{
1897 struct numa_node *n;
1898 unsigned long **nodes;
1899 int node, cpu;
1900 int *cpu2node;
1901
1902 if (c2c.node_info > 2)
1903 c2c.node_info = 2;
1904
1905 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1906 c2c.cpus_cnt = session->header.env.nr_cpus_online;
1907
1908 n = session->header.env.numa_nodes;
1909 if (!n)
1910 return -EINVAL;
1911
1912 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
1913 if (!nodes)
1914 return -ENOMEM;
1915
1916 c2c.nodes = nodes;
1917
1918 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
1919 if (!cpu2node)
1920 return -ENOMEM;
1921
1922 for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
1923 cpu2node[cpu] = -1;
1924
1925 c2c.cpu2node = cpu2node;
1926
1927 for (node = 0; node < c2c.nodes_cnt; node++) {
1928 struct cpu_map *map = n[node].map;
1929 unsigned long *set;
1930
1931 set = bitmap_alloc(c2c.cpus_cnt);
1932 if (!set)
1933 return -ENOMEM;
1934
1935 for (cpu = 0; cpu < map->nr; cpu++) {
1936 set_bit(map->map[cpu], set);
1937
1938 if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
1939 return -EINVAL;
1940
1941 cpu2node[map->map[cpu]] = node;
1942 }
1943
1944 nodes[node] = set;
1945 }
1946
1947 setup_nodes_header();
1948 return 0;
1949}
1950
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02001951#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
1952
1953static int resort_hitm_cb(struct hist_entry *he)
1954{
1955 struct c2c_hist_entry *c2c_he;
1956 c2c_he = container_of(he, struct c2c_hist_entry, he);
1957
1958 if (HAS_HITMS(c2c_he)) {
1959 c2c.shared_clines++;
1960 c2c_add_stats(&c2c.hitm_stats, &c2c_he->stats);
1961 }
1962
1963 return 0;
1964}
1965
1966static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
1967{
1968 struct rb_node *next = rb_first(&hists->entries);
1969 int ret = 0;
1970
1971 while (next) {
1972 struct hist_entry *he;
1973
1974 he = rb_entry(next, struct hist_entry, rb_node);
1975 ret = cb(he);
1976 if (ret)
1977 break;
1978 next = rb_next(&he->rb_node);
1979 }
1980
1981 return ret;
1982}
1983
Jiri Olsa74c63a22016-05-02 20:01:59 +02001984static void print_c2c__display_stats(FILE *out)
1985{
1986 int llc_misses;
1987 struct c2c_stats *stats = &c2c.hists.stats;
1988
1989 llc_misses = stats->lcl_dram +
1990 stats->rmt_dram +
1991 stats->rmt_hit +
1992 stats->rmt_hitm;
1993
1994 fprintf(out, "=================================================\n");
1995 fprintf(out, " Trace Event Information \n");
1996 fprintf(out, "=================================================\n");
1997 fprintf(out, " Total records : %10d\n", stats->nr_entries);
1998 fprintf(out, " Locked Load/Store Operations : %10d\n", stats->locks);
1999 fprintf(out, " Load Operations : %10d\n", stats->load);
2000 fprintf(out, " Loads - uncacheable : %10d\n", stats->ld_uncache);
2001 fprintf(out, " Loads - IO : %10d\n", stats->ld_io);
2002 fprintf(out, " Loads - Miss : %10d\n", stats->ld_miss);
2003 fprintf(out, " Loads - no mapping : %10d\n", stats->ld_noadrs);
2004 fprintf(out, " Load Fill Buffer Hit : %10d\n", stats->ld_fbhit);
2005 fprintf(out, " Load L1D hit : %10d\n", stats->ld_l1hit);
2006 fprintf(out, " Load L2D hit : %10d\n", stats->ld_l2hit);
2007 fprintf(out, " Load LLC hit : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2008 fprintf(out, " Load Local HITM : %10d\n", stats->lcl_hitm);
2009 fprintf(out, " Load Remote HITM : %10d\n", stats->rmt_hitm);
2010 fprintf(out, " Load Remote HIT : %10d\n", stats->rmt_hit);
2011 fprintf(out, " Load Local DRAM : %10d\n", stats->lcl_dram);
2012 fprintf(out, " Load Remote DRAM : %10d\n", stats->rmt_dram);
2013 fprintf(out, " Load MESI State Exclusive : %10d\n", stats->ld_excl);
2014 fprintf(out, " Load MESI State Shared : %10d\n", stats->ld_shared);
2015 fprintf(out, " Load LLC Misses : %10d\n", llc_misses);
2016 fprintf(out, " LLC Misses to Local DRAM : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);
2017 fprintf(out, " LLC Misses to Remote DRAM : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);
2018 fprintf(out, " LLC Misses to Remote cache (HIT) : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.);
2019 fprintf(out, " LLC Misses to Remote cache (HITM) : %10.1f%%\n", ((double)stats->rmt_hitm/(double)llc_misses) * 100.);
2020 fprintf(out, " Store Operations : %10d\n", stats->store);
2021 fprintf(out, " Store - uncacheable : %10d\n", stats->st_uncache);
2022 fprintf(out, " Store - no mapping : %10d\n", stats->st_noadrs);
2023 fprintf(out, " Store L1D Hit : %10d\n", stats->st_l1hit);
2024 fprintf(out, " Store L1D Miss : %10d\n", stats->st_l1miss);
2025 fprintf(out, " No Page Map Rejects : %10d\n", stats->nomap);
2026 fprintf(out, " Unable to parse data source : %10d\n", stats->noparse);
2027}
2028
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002029static void print_shared_cacheline_info(FILE *out)
2030{
2031 struct c2c_stats *stats = &c2c.hitm_stats;
2032 int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
2033
2034 fprintf(out, "=================================================\n");
2035 fprintf(out, " Global Shared Cache Line Event Information \n");
2036 fprintf(out, "=================================================\n");
2037 fprintf(out, " Total Shared Cache Lines : %10d\n", c2c.shared_clines);
2038 fprintf(out, " Load HITs on shared lines : %10d\n", stats->load);
2039 fprintf(out, " Fill Buffer Hits on shared lines : %10d\n", stats->ld_fbhit);
2040 fprintf(out, " L1D hits on shared lines : %10d\n", stats->ld_l1hit);
2041 fprintf(out, " L2D hits on shared lines : %10d\n", stats->ld_l2hit);
2042 fprintf(out, " LLC hits on shared lines : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2043 fprintf(out, " Locked Access on shared lines : %10d\n", stats->locks);
2044 fprintf(out, " Store HITs on shared lines : %10d\n", stats->store);
2045 fprintf(out, " Store L1D hits on shared lines : %10d\n", stats->st_l1hit);
2046 fprintf(out, " Total Merged records : %10d\n", hitm_cnt + stats->store);
2047}
2048
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002049static void print_cacheline(struct c2c_hists *c2c_hists,
2050 struct hist_entry *he_cl,
2051 struct perf_hpp_list *hpp_list,
2052 FILE *out)
2053{
2054 char bf[1000];
2055 struct perf_hpp hpp = {
2056 .buf = bf,
2057 .size = 1000,
2058 };
2059 static bool once;
2060
2061 if (!once) {
2062 hists__fprintf_headers(&c2c_hists->hists, out);
2063 once = true;
2064 } else {
2065 fprintf(out, "\n");
2066 }
2067
Jiri Olsabb342da2016-07-06 15:40:09 +02002068 fprintf(out, " -------------------------------------------------------------\n");
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002069 __hist_entry__snprintf(he_cl, &hpp, hpp_list);
2070 fprintf(out, "%s\n", bf);
Jiri Olsabb342da2016-07-06 15:40:09 +02002071 fprintf(out, " -------------------------------------------------------------\n");
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002072
2073 hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, true);
2074}
2075
2076static void print_pareto(FILE *out)
2077{
2078 struct perf_hpp_list hpp_list;
2079 struct rb_node *nd;
2080 int ret;
2081
2082 perf_hpp_list__init(&hpp_list);
2083 ret = hpp_list__parse(&hpp_list,
Jiri Olsabb342da2016-07-06 15:40:09 +02002084 "cl_num,"
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002085 "cl_rmt_hitm,"
2086 "cl_lcl_hitm,"
2087 "cl_stores_l1hit,"
2088 "cl_stores_l1miss,"
2089 "dcacheline",
2090 NULL);
2091
2092 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
2093 return;
2094
2095 nd = rb_first(&c2c.hists.hists.entries);
2096
2097 for (; nd; nd = rb_next(nd)) {
2098 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2099 struct c2c_hist_entry *c2c_he;
2100
2101 if (he->filtered)
2102 continue;
2103
2104 c2c_he = container_of(he, struct c2c_hist_entry, he);
2105 print_cacheline(c2c_he->hists, he, &hpp_list, out);
2106 }
2107}
2108
Jiri Olsa2709b972016-08-27 11:40:23 +02002109static void print_c2c_info(FILE *out, struct perf_session *session)
2110{
2111 struct perf_evlist *evlist = session->evlist;
2112 struct perf_evsel *evsel;
2113 bool first = true;
2114
2115 fprintf(out, "=================================================\n");
2116 fprintf(out, " c2c details \n");
2117 fprintf(out, "=================================================\n");
2118
2119 evlist__for_each_entry(evlist, evsel) {
2120 fprintf(out, "%-36s: %s\n", first ? " Events" : "",
2121 perf_evsel__name(evsel));
2122 first = false;
2123 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002124 fprintf(out, " Cachelines sort on : %s HITMs\n",
Jiri Olsad940bac2016-11-21 22:33:30 +01002125 display_str[c2c.display]);
Jiri Olsafc9c6302016-05-24 14:14:38 +02002126 fprintf(out, " Cacheline data grouping : %s\n", c2c.cl_sort);
Jiri Olsa2709b972016-08-27 11:40:23 +02002127}
2128
2129static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002130{
2131 setup_pager();
2132
Jiri Olsa74c63a22016-05-02 20:01:59 +02002133 print_c2c__display_stats(out);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002134 fprintf(out, "\n");
2135 print_shared_cacheline_info(out);
Jiri Olsa2709b972016-08-27 11:40:23 +02002136 fprintf(out, "\n");
2137 print_c2c_info(out, session);
Jiri Olsa74c63a22016-05-02 20:01:59 +02002138
2139 if (c2c.stats_only)
2140 return;
2141
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002142 fprintf(out, "\n");
2143 fprintf(out, "=================================================\n");
2144 fprintf(out, " Shared Data Cache Line Table \n");
2145 fprintf(out, "=================================================\n");
2146 fprintf(out, "#\n");
2147
2148 hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, false);
2149
2150 fprintf(out, "\n");
2151 fprintf(out, "=================================================\n");
2152 fprintf(out, " Shared Cache Line Distribution Pareto \n");
2153 fprintf(out, "=================================================\n");
2154 fprintf(out, "#\n");
2155
2156 print_pareto(out);
2157}
Jiri Olsa1e181b92016-06-03 15:40:28 +02002158
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002159#ifdef HAVE_SLANG_SUPPORT
2160static void c2c_browser__update_nr_entries(struct hist_browser *hb)
2161{
2162 u64 nr_entries = 0;
2163 struct rb_node *nd = rb_first(&hb->hists->entries);
2164
2165 while (nd) {
2166 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2167
2168 if (!he->filtered)
2169 nr_entries++;
2170
2171 nd = rb_next(nd);
2172 }
2173
2174 hb->nr_non_filtered_entries = nr_entries;
2175}
2176
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002177struct c2c_cacheline_browser {
2178 struct hist_browser hb;
2179 struct hist_entry *he;
2180};
2181
2182static int
2183perf_c2c_cacheline_browser__title(struct hist_browser *browser,
2184 char *bf, size_t size)
2185{
2186 struct c2c_cacheline_browser *cl_browser;
2187 struct hist_entry *he;
2188 uint64_t addr = 0;
2189
2190 cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
2191 he = cl_browser->he;
2192
2193 if (he->mem_info)
2194 addr = cl_address(he->mem_info->daddr.addr);
2195
2196 scnprintf(bf, size, "Cacheline 0x%lx", addr);
2197 return 0;
2198}
2199
2200static struct c2c_cacheline_browser*
2201c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
2202{
2203 struct c2c_cacheline_browser *browser;
2204
2205 browser = zalloc(sizeof(*browser));
2206 if (browser) {
2207 hist_browser__init(&browser->hb, hists);
2208 browser->hb.c2c_filter = true;
2209 browser->hb.title = perf_c2c_cacheline_browser__title;
2210 browser->he = he;
2211 }
2212
2213 return browser;
2214}
2215
2216static int perf_c2c__browse_cacheline(struct hist_entry *he)
2217{
2218 struct c2c_hist_entry *c2c_he;
2219 struct c2c_hists *c2c_hists;
2220 struct c2c_cacheline_browser *cl_browser;
2221 struct hist_browser *browser;
2222 int key = -1;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002223 const char help[] =
2224 " ENTER Togle callchains (if present) \n"
2225 " n Togle Node details info \n"
2226 " s Togle full lenght of symbol and source line columns \n"
2227 " q Return back to cacheline list \n";
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002228
Jiri Olsa590b6a32016-07-10 16:25:15 +02002229 /* Display compact version first. */
2230 c2c.symbol_full = false;
2231
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002232 c2c_he = container_of(he, struct c2c_hist_entry, he);
2233 c2c_hists = c2c_he->hists;
2234
2235 cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
2236 if (cl_browser == NULL)
2237 return -1;
2238
2239 browser = &cl_browser->hb;
2240
2241 /* reset abort key so that it can get Ctrl-C as a key */
2242 SLang_reset_tty();
2243 SLang_init_tty(0, 0, 0);
2244
2245 c2c_browser__update_nr_entries(browser);
2246
2247 while (1) {
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002248 key = hist_browser__run(browser, "? - help");
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002249
2250 switch (key) {
Jiri Olsa590b6a32016-07-10 16:25:15 +02002251 case 's':
2252 c2c.symbol_full = !c2c.symbol_full;
2253 break;
Jiri Olsa1a56a422016-07-10 16:30:27 +02002254 case 'n':
2255 c2c.node_info = (c2c.node_info + 1) % 3;
2256 setup_nodes_header();
2257 break;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002258 case 'q':
2259 goto out;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002260 case '?':
2261 ui_browser__help_window(&browser->b, help);
2262 break;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002263 default:
2264 break;
2265 }
2266 }
2267
2268out:
2269 free(cl_browser);
2270 return 0;
2271}
2272
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002273static int perf_c2c_browser__title(struct hist_browser *browser,
2274 char *bf, size_t size)
2275{
2276 scnprintf(bf, size,
Jiri Olsa55b95772016-05-29 10:21:45 +02002277 "Shared Data Cache Line Table "
2278 "(%lu entries, sorted on %s HITMs)",
2279 browser->nr_non_filtered_entries,
Jiri Olsad940bac2016-11-21 22:33:30 +01002280 display_str[c2c.display]);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002281 return 0;
2282}
2283
2284static struct hist_browser*
2285perf_c2c_browser__new(struct hists *hists)
2286{
2287 struct hist_browser *browser = hist_browser__new(hists);
2288
2289 if (browser) {
2290 browser->title = perf_c2c_browser__title;
2291 browser->c2c_filter = true;
2292 }
2293
2294 return browser;
2295}
2296
2297static int perf_c2c__hists_browse(struct hists *hists)
2298{
2299 struct hist_browser *browser;
2300 int key = -1;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002301 const char help[] =
2302 " d Display cacheline details \n"
2303 " ENTER Togle callchains (if present) \n"
2304 " q Quit \n";
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002305
2306 browser = perf_c2c_browser__new(hists);
2307 if (browser == NULL)
2308 return -1;
2309
2310 /* reset abort key so that it can get Ctrl-C as a key */
2311 SLang_reset_tty();
2312 SLang_init_tty(0, 0, 0);
2313
2314 c2c_browser__update_nr_entries(browser);
2315
2316 while (1) {
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002317 key = hist_browser__run(browser, "? - help");
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002318
2319 switch (key) {
2320 case 'q':
2321 goto out;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002322 case 'd':
2323 perf_c2c__browse_cacheline(browser->he_selection);
2324 break;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002325 case '?':
2326 ui_browser__help_window(&browser->b, help);
2327 break;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002328 default:
2329 break;
2330 }
2331 }
2332
2333out:
2334 hist_browser__delete(browser);
2335 return 0;
2336}
2337
Jiri Olsa2709b972016-08-27 11:40:23 +02002338static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002339{
Namhyung Kim1936fea2017-03-08 00:08:33 +09002340 if (use_browser == 0)
Jiri Olsa2709b972016-08-27 11:40:23 +02002341 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002342 else
2343 perf_c2c__hists_browse(&c2c.hists.hists);
2344}
2345#else
Jiri Olsa2709b972016-08-27 11:40:23 +02002346static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002347{
2348 use_browser = 0;
Jiri Olsa2709b972016-08-27 11:40:23 +02002349 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002350}
2351#endif /* HAVE_SLANG_SUPPORT */
2352
2353static void ui_quirks(void)
2354{
2355 if (!c2c.use_stdio) {
2356 dim_offset.width = 5;
2357 dim_offset.header = header_offset_tui;
2358 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002359
2360 dim_percent_hitm.header = percent_hitm_header[c2c.display];
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002361}
2362
Jiri Olsadd805762016-05-11 18:23:48 +02002363#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
2364
2365const char callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
2366 CALLCHAIN_REPORT_HELP
2367 "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
2368
2369static int
2370parse_callchain_opt(const struct option *opt, const char *arg, int unset)
2371{
2372 struct callchain_param *callchain = opt->value;
2373
2374 callchain->enabled = !unset;
2375 /*
2376 * --no-call-graph
2377 */
2378 if (unset) {
2379 symbol_conf.use_callchain = false;
2380 callchain->mode = CHAIN_NONE;
2381 return 0;
2382 }
2383
2384 return parse_callchain_report_opt(arg);
2385}
2386
2387static int setup_callchain(struct perf_evlist *evlist)
2388{
2389 u64 sample_type = perf_evlist__combined_sample_type(evlist);
2390 enum perf_call_graph_mode mode = CALLCHAIN_NONE;
2391
2392 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
2393 (sample_type & PERF_SAMPLE_STACK_USER))
2394 mode = CALLCHAIN_DWARF;
2395 else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
2396 mode = CALLCHAIN_LBR;
2397 else if (sample_type & PERF_SAMPLE_CALLCHAIN)
2398 mode = CALLCHAIN_FP;
2399
2400 if (!callchain_param.enabled &&
2401 callchain_param.mode != CHAIN_NONE &&
2402 mode != CALLCHAIN_NONE) {
2403 symbol_conf.use_callchain = true;
2404 if (callchain_register_param(&callchain_param) < 0) {
2405 ui__error("Can't register callchain params.\n");
2406 return -EINVAL;
2407 }
2408 }
2409
2410 callchain_param.record_mode = mode;
2411 callchain_param.min_percent = 0;
2412 return 0;
2413}
2414
Jiri Olsa55b95772016-05-29 10:21:45 +02002415static int setup_display(const char *str)
2416{
Jiri Olsad940bac2016-11-21 22:33:30 +01002417 const char *display = str ?: "tot";
Jiri Olsa55b95772016-05-29 10:21:45 +02002418
Jiri Olsad940bac2016-11-21 22:33:30 +01002419 if (!strcmp(display, "tot"))
2420 c2c.display = DISPLAY_TOT;
2421 else if (!strcmp(display, "rmt"))
Jiri Olsa55b95772016-05-29 10:21:45 +02002422 c2c.display = DISPLAY_RMT;
2423 else if (!strcmp(display, "lcl"))
2424 c2c.display = DISPLAY_LCL;
2425 else {
2426 pr_err("failed: unknown display type: %s\n", str);
2427 return -1;
2428 }
2429
2430 return 0;
2431}
2432
Jiri Olsafc9c6302016-05-24 14:14:38 +02002433#define for_each_token(__tok, __buf, __sep, __tmp) \
2434 for (__tok = strtok_r(__buf, __sep, &__tmp); __tok; \
2435 __tok = strtok_r(NULL, __sep, &__tmp))
2436
Jiri Olsa18f278d2016-10-11 13:39:47 +02002437static int build_cl_output(char *cl_sort, bool no_source)
Jiri Olsafc9c6302016-05-24 14:14:38 +02002438{
2439 char *tok, *tmp, *buf = strdup(cl_sort);
2440 bool add_pid = false;
2441 bool add_tid = false;
2442 bool add_iaddr = false;
2443 bool add_sym = false;
2444 bool add_dso = false;
2445 bool add_src = false;
2446
2447 if (!buf)
2448 return -ENOMEM;
2449
2450 for_each_token(tok, buf, ",", tmp) {
2451 if (!strcmp(tok, "tid")) {
2452 add_tid = true;
2453 } else if (!strcmp(tok, "pid")) {
2454 add_pid = true;
2455 } else if (!strcmp(tok, "iaddr")) {
2456 add_iaddr = true;
2457 add_sym = true;
2458 add_dso = true;
Jiri Olsa18f278d2016-10-11 13:39:47 +02002459 add_src = no_source ? false : true;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002460 } else if (!strcmp(tok, "dso")) {
2461 add_dso = true;
2462 } else if (strcmp(tok, "offset")) {
2463 pr_err("unrecognized sort token: %s\n", tok);
2464 return -EINVAL;
2465 }
2466 }
2467
2468 if (asprintf(&c2c.cl_output,
Jiri Olsabb342da2016-07-06 15:40:09 +02002469 "%s%s%s%s%s%s%s%s%s%s",
2470 c2c.use_stdio ? "cl_num_empty," : "",
Jiri Olsafc9c6302016-05-24 14:14:38 +02002471 "percent_rmt_hitm,"
2472 "percent_lcl_hitm,"
2473 "percent_stores_l1hit,"
2474 "percent_stores_l1miss,"
2475 "offset,",
2476 add_pid ? "pid," : "",
2477 add_tid ? "tid," : "",
2478 add_iaddr ? "iaddr," : "",
2479 "mean_rmt,"
2480 "mean_lcl,"
2481 "mean_load,"
Jiri Olsa8763e6a2017-01-20 10:20:31 +01002482 "tot_recs,"
Jiri Olsafc9c6302016-05-24 14:14:38 +02002483 "cpucnt,",
2484 add_sym ? "symbol," : "",
2485 add_dso ? "dso," : "",
2486 add_src ? "cl_srcline," : "",
2487 "node") < 0)
2488 return -ENOMEM;
2489
2490 c2c.show_src = add_src;
2491
2492 free(buf);
2493 return 0;
2494}
2495
Jiri Olsa18f278d2016-10-11 13:39:47 +02002496static int setup_coalesce(const char *coalesce, bool no_source)
Jiri Olsafc9c6302016-05-24 14:14:38 +02002497{
2498 const char *c = coalesce ?: coalesce_default;
2499
2500 if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)
2501 return -ENOMEM;
2502
Jiri Olsa18f278d2016-10-11 13:39:47 +02002503 if (build_cl_output(c2c.cl_sort, no_source))
Jiri Olsafc9c6302016-05-24 14:14:38 +02002504 return -1;
2505
2506 if (asprintf(&c2c.cl_resort, "offset,%s",
Jiri Olsad940bac2016-11-21 22:33:30 +01002507 c2c.display == DISPLAY_TOT ?
2508 "tot_hitm" :
Jiri Olsafc9c6302016-05-24 14:14:38 +02002509 c2c.display == DISPLAY_RMT ?
2510 "rmt_hitm,lcl_hitm" :
2511 "lcl_hitm,rmt_hitm") < 0)
2512 return -ENOMEM;
2513
2514 pr_debug("coalesce sort fields: %s\n", c2c.cl_sort);
2515 pr_debug("coalesce resort fields: %s\n", c2c.cl_resort);
2516 pr_debug("coalesce output fields: %s\n", c2c.cl_output);
2517 return 0;
2518}
2519
Jiri Olsa903a6f12016-09-22 17:36:40 +02002520static int perf_c2c__report(int argc, const char **argv)
2521{
2522 struct perf_session *session;
Jiri Olsa78b27542016-09-22 17:36:44 +02002523 struct ui_progress prog;
Jiri Olsa903a6f12016-09-22 17:36:40 +02002524 struct perf_data_file file = {
2525 .mode = PERF_DATA_MODE_READ,
2526 };
Jiri Olsadd805762016-05-11 18:23:48 +02002527 char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
Jiri Olsa55b95772016-05-29 10:21:45 +02002528 const char *display = NULL;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002529 const char *coalesce = NULL;
Jiri Olsa18f278d2016-10-11 13:39:47 +02002530 bool no_source = false;
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002531 const struct option options[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +02002532 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
2533 "file", "vmlinux pathname"),
Jiri Olsa903a6f12016-09-22 17:36:40 +02002534 OPT_STRING('i', "input", &input_name, "file",
2535 "the input file to process"),
Jiri Olsa1e181b92016-06-03 15:40:28 +02002536 OPT_INCR('N', "node-info", &c2c.node_info,
2537 "show extra node info in report (repeat for more info)"),
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002538#ifdef HAVE_SLANG_SUPPORT
2539 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2540#endif
Jiri Olsa74c63a22016-05-02 20:01:59 +02002541 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
Namhyung Kimf75d2892017-03-08 00:08:32 +09002542 "Display only statistic tables (implies --stdio)"),
Jiri Olsa590b6a32016-07-10 16:25:15 +02002543 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
2544 "Display full length of symbols"),
Jiri Olsa18f278d2016-10-11 13:39:47 +02002545 OPT_BOOLEAN(0, "no-source", &no_source,
2546 "Do not display Source Line column"),
Jiri Olsaaf09b2d2016-10-11 13:52:05 +02002547 OPT_BOOLEAN(0, "show-all", &c2c.show_all,
2548 "Show all captured HITM lines."),
Jiri Olsadd805762016-05-11 18:23:48 +02002549 OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
2550 "print_type,threshold[,print_limit],order,sort_key[,branch],value",
2551 callchain_help, &parse_callchain_opt,
2552 callchain_default_opt),
Jiri Olsad940bac2016-11-21 22:33:30 +01002553 OPT_STRING('d', "display", &display, "Switch HITM output type", "lcl,rmt"),
Jiri Olsafc9c6302016-05-24 14:14:38 +02002554 OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
2555 "coalesce fields: pid,tid,iaddr,dso"),
Jiri Olsab7ac4f92016-11-21 22:33:28 +01002556 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002557 OPT_PARENT(c2c_options),
Jiri Olsa903a6f12016-09-22 17:36:40 +02002558 OPT_END()
2559 };
2560 int err = 0;
2561
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002562 argc = parse_options(argc, argv, options, report_c2c_usage,
Jiri Olsa903a6f12016-09-22 17:36:40 +02002563 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa78b27542016-09-22 17:36:44 +02002564 if (argc)
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002565 usage_with_options(report_c2c_usage, options);
Jiri Olsa903a6f12016-09-22 17:36:40 +02002566
Jiri Olsa74c63a22016-05-02 20:01:59 +02002567 if (c2c.stats_only)
2568 c2c.use_stdio = true;
2569
Jiri Olsa78b27542016-09-22 17:36:44 +02002570 if (!input_name || !strlen(input_name))
2571 input_name = "perf.data";
2572
Jiri Olsab7ac4f92016-11-21 22:33:28 +01002573 file.path = input_name;
2574 file.force = symbol_conf.force;
Jiri Olsa903a6f12016-09-22 17:36:40 +02002575
Jiri Olsa55b95772016-05-29 10:21:45 +02002576 err = setup_display(display);
2577 if (err)
2578 goto out;
2579
Jiri Olsa18f278d2016-10-11 13:39:47 +02002580 err = setup_coalesce(coalesce, no_source);
Jiri Olsafc9c6302016-05-24 14:14:38 +02002581 if (err) {
2582 pr_debug("Failed to initialize hists\n");
2583 goto out;
2584 }
2585
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02002586 err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
Jiri Olsac75540e2016-09-22 17:36:41 +02002587 if (err) {
2588 pr_debug("Failed to initialize hists\n");
2589 goto out;
2590 }
2591
Jiri Olsa903a6f12016-09-22 17:36:40 +02002592 session = perf_session__new(&file, 0, &c2c.tool);
2593 if (session == NULL) {
2594 pr_debug("No memory for session\n");
2595 goto out;
2596 }
Jiri Olsae8c5fe12016-11-21 22:33:27 +01002597
Jiri Olsa1e181b92016-06-03 15:40:28 +02002598 err = setup_nodes(session);
2599 if (err) {
2600 pr_err("Failed setup nodes\n");
2601 goto out;
2602 }
Jiri Olsa903a6f12016-09-22 17:36:40 +02002603
Jiri Olsadd805762016-05-11 18:23:48 +02002604 err = setup_callchain(session->evlist);
2605 if (err)
2606 goto out_session;
2607
Jiri Olsa903a6f12016-09-22 17:36:40 +02002608 if (symbol__init(&session->header.env) < 0)
2609 goto out_session;
2610
2611 /* No pipe support at the moment. */
2612 if (perf_data_file__is_pipe(session->file)) {
2613 pr_debug("No pipe support at the moment.\n");
2614 goto out_session;
2615 }
2616
Jiri Olsae8c5fe12016-11-21 22:33:27 +01002617 if (c2c.use_stdio)
2618 use_browser = 0;
2619 else
2620 use_browser = 1;
2621
2622 setup_browser(false);
2623
Jiri Olsa78b27542016-09-22 17:36:44 +02002624 err = perf_session__process_events(session);
2625 if (err) {
2626 pr_err("failed to process sample\n");
2627 goto out_session;
2628 }
2629
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002630 c2c_hists__reinit(&c2c.hists,
Jiri Olsabb342da2016-07-06 15:40:09 +02002631 "cl_idx,"
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002632 "dcacheline,"
2633 "tot_recs,"
2634 "percent_hitm,"
2635 "tot_hitm,lcl_hitm,rmt_hitm,"
2636 "stores,stores_l1hit,stores_l1miss,"
2637 "dram_lcl,dram_rmt,"
2638 "ld_llcmiss,"
2639 "tot_loads,"
2640 "ld_fbhit,ld_l1hit,ld_l2hit,"
2641 "ld_lclhit,ld_rmthit",
Jiri Olsad940bac2016-11-21 22:33:30 +01002642 c2c.display == DISPLAY_TOT ? "tot_hitm" :
Jiri Olsa55b95772016-05-29 10:21:45 +02002643 c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm"
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002644 );
2645
Jiri Olsa78b27542016-09-22 17:36:44 +02002646 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
2647
2648 hists__collapse_resort(&c2c.hists.hists, NULL);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002649 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_hitm_cb);
2650 hists__iterate_cb(&c2c.hists.hists, resort_cl_cb);
Jiri Olsa78b27542016-09-22 17:36:44 +02002651
2652 ui_progress__finish();
2653
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002654 ui_quirks();
2655
Jiri Olsa2709b972016-08-27 11:40:23 +02002656 perf_c2c_display(session);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002657
Jiri Olsa903a6f12016-09-22 17:36:40 +02002658out_session:
2659 perf_session__delete(session);
2660out:
2661 return err;
2662}
2663
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03002664static int parse_record_events(const struct option *opt,
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002665 const char *str, int unset __maybe_unused)
2666{
2667 bool *event_set = (bool *) opt->value;
2668
2669 *event_set = true;
2670 return perf_mem_events__parse(str);
2671}
2672
2673
2674static const char * const __usage_record[] = {
2675 "perf c2c record [<options>] [<command>]",
2676 "perf c2c record [<options>] -- <command> [<options>]",
2677 NULL
2678};
2679
2680static const char * const *record_mem_usage = __usage_record;
2681
2682static int perf_c2c__record(int argc, const char **argv)
2683{
2684 int rec_argc, i = 0, j;
2685 const char **rec_argv;
2686 int ret;
2687 bool all_user = false, all_kernel = false;
2688 bool event_set = false;
2689 struct option options[] = {
2690 OPT_CALLBACK('e', "event", &event_set, "event",
2691 "event selector. Use 'perf mem record -e list' to list available events",
2692 parse_record_events),
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002693 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
2694 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
2695 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01002696 OPT_PARENT(c2c_options),
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002697 OPT_END()
2698 };
2699
2700 if (perf_mem_events__init()) {
2701 pr_err("failed: memory events not supported\n");
2702 return -1;
2703 }
2704
2705 argc = parse_options(argc, argv, options, record_mem_usage,
2706 PARSE_OPT_KEEP_UNKNOWN);
2707
2708 rec_argc = argc + 10; /* max number of arguments */
2709 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2710 if (!rec_argv)
2711 return -1;
2712
2713 rec_argv[i++] = "record";
2714
2715 if (!event_set) {
2716 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
2717 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
2718 }
2719
2720 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
2721 rec_argv[i++] = "-W";
2722
2723 rec_argv[i++] = "-d";
2724 rec_argv[i++] = "--sample-cpu";
2725
2726 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
2727 if (!perf_mem_events[j].record)
2728 continue;
2729
2730 if (!perf_mem_events[j].supported) {
2731 pr_err("failed: event '%s' not supported\n",
2732 perf_mem_events[j].name);
2733 return -1;
2734 }
2735
2736 rec_argv[i++] = "-e";
2737 rec_argv[i++] = perf_mem_events__name(j);
2738 };
2739
2740 if (all_user)
2741 rec_argv[i++] = "--all-user";
2742
2743 if (all_kernel)
2744 rec_argv[i++] = "--all-kernel";
2745
2746 for (j = 0; j < argc; j++, i++)
2747 rec_argv[i] = argv[j];
2748
2749 if (verbose > 0) {
2750 pr_debug("calling: ");
2751
2752 j = 0;
2753
2754 while (rec_argv[j]) {
2755 pr_debug("%s ", rec_argv[j]);
2756 j++;
2757 }
2758 pr_debug("\n");
2759 }
2760
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002761 ret = cmd_record(i, rec_argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002762 free(rec_argv);
2763 return ret;
2764}
2765
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002766int cmd_c2c(int argc, const char **argv)
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002767{
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002768 argc = parse_options(argc, argv, c2c_options, c2c_usage,
2769 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002770
2771 if (!argc)
2772 usage_with_options(c2c_usage, c2c_options);
2773
2774 if (!strncmp(argv[0], "rec", 3)) {
2775 return perf_c2c__record(argc, argv);
Jiri Olsa903a6f12016-09-22 17:36:40 +02002776 } else if (!strncmp(argv[0], "rep", 3)) {
2777 return perf_c2c__report(argc, argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02002778 } else {
2779 usage_with_options(c2c_usage, c2c_options);
2780 }
2781
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02002782 return 0;
2783}