blob: 2a1e883580a183fd7305ed159e44a391c68fdf0e [file] [log] [blame]
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02001#include <linux/compiler.h>
2#include <linux/kernel.h>
Jiri Olsacbb88502016-09-22 17:36:48 +02003#include <linux/stringify.h>
Jiri Olsa1e181b92016-06-03 15:40:28 +02004#include <asm/bug.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02005#include "util.h"
6#include "debug.h"
7#include "builtin.h"
8#include <subcmd/parse-options.h>
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02009#include "mem-events.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020010#include "session.h"
11#include "hist.h"
Jiri Olsacbb88502016-09-22 17:36:48 +020012#include "sort.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020013#include "tool.h"
14#include "data.h"
Jiri Olsa8d3f9382016-09-22 17:36:42 +020015#include "sort.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020016
Jiri Olsac75540e2016-09-22 17:36:41 +020017struct c2c_hists {
18 struct hists hists;
19 struct perf_hpp_list list;
Jiri Olsab2252ae2016-09-22 17:36:46 +020020 struct c2c_stats stats;
Jiri Olsac75540e2016-09-22 17:36:41 +020021};
22
Jiri Olsa92062d52016-06-05 13:40:53 +020023struct compute_stats {
24 struct stats lcl_hitm;
25 struct stats rmt_hitm;
26 struct stats load;
27};
28
Jiri Olsa78b27542016-09-22 17:36:44 +020029struct c2c_hist_entry {
30 struct c2c_hists *hists;
Jiri Olsab2252ae2016-09-22 17:36:46 +020031 struct c2c_stats stats;
Jiri Olsa1e181b92016-06-03 15:40:28 +020032 unsigned long *cpuset;
33 struct c2c_stats *node_stats;
Jiri Olsa92062d52016-06-05 13:40:53 +020034
35 struct compute_stats cstats;
36
Jiri Olsa78b27542016-09-22 17:36:44 +020037 /*
38 * must be at the end,
39 * because of its callchain dynamic entry
40 */
41 struct hist_entry he;
42};
43
Jiri Olsa903a6f12016-09-22 17:36:40 +020044struct perf_c2c {
Jiri Olsac75540e2016-09-22 17:36:41 +020045 struct perf_tool tool;
46 struct c2c_hists hists;
Jiri Olsa1e181b92016-06-03 15:40:28 +020047
48 unsigned long **nodes;
49 int nodes_cnt;
50 int cpus_cnt;
51 int *cpu2node;
52 int node_info;
Jiri Olsa903a6f12016-09-22 17:36:40 +020053};
54
55static struct perf_c2c c2c;
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020056
Jiri Olsa78b27542016-09-22 17:36:44 +020057static void *c2c_he_zalloc(size_t size)
58{
59 struct c2c_hist_entry *c2c_he;
60
61 c2c_he = zalloc(size + sizeof(*c2c_he));
62 if (!c2c_he)
63 return NULL;
64
Jiri Olsa1e181b92016-06-03 15:40:28 +020065 c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt);
66 if (!c2c_he->cpuset)
67 return NULL;
68
69 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
70 if (!c2c_he->node_stats)
71 return NULL;
72
Jiri Olsa92062d52016-06-05 13:40:53 +020073 init_stats(&c2c_he->cstats.lcl_hitm);
74 init_stats(&c2c_he->cstats.rmt_hitm);
75 init_stats(&c2c_he->cstats.load);
76
Jiri Olsa78b27542016-09-22 17:36:44 +020077 return &c2c_he->he;
78}
79
80static void c2c_he_free(void *he)
81{
82 struct c2c_hist_entry *c2c_he;
83
84 c2c_he = container_of(he, struct c2c_hist_entry, he);
85 if (c2c_he->hists) {
86 hists__delete_entries(&c2c_he->hists->hists);
87 free(c2c_he->hists);
88 }
89
Jiri Olsa1e181b92016-06-03 15:40:28 +020090 free(c2c_he->cpuset);
91 free(c2c_he->node_stats);
Jiri Olsa78b27542016-09-22 17:36:44 +020092 free(c2c_he);
93}
94
95static struct hist_entry_ops c2c_entry_ops = {
96 .new = c2c_he_zalloc,
97 .free = c2c_he_free,
98};
99
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200100static int c2c_hists__init(struct c2c_hists *hists,
101 const char *sort);
102
Jiri Olsab2252ae2016-09-22 17:36:46 +0200103static struct c2c_hists*
104he__get_c2c_hists(struct hist_entry *he,
105 const char *sort)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200106{
107 struct c2c_hist_entry *c2c_he;
108 struct c2c_hists *hists;
109 int ret;
110
111 c2c_he = container_of(he, struct c2c_hist_entry, he);
112 if (c2c_he->hists)
Jiri Olsab2252ae2016-09-22 17:36:46 +0200113 return c2c_he->hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200114
115 hists = c2c_he->hists = zalloc(sizeof(*hists));
116 if (!hists)
117 return NULL;
118
119 ret = c2c_hists__init(hists, sort);
120 if (ret) {
121 free(hists);
122 return NULL;
123 }
124
Jiri Olsab2252ae2016-09-22 17:36:46 +0200125 return hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200126}
127
Jiri Olsa1e181b92016-06-03 15:40:28 +0200128static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
129 struct perf_sample *sample)
130{
131 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
132 "WARNING: no sample cpu value"))
133 return;
134
135 set_bit(sample->cpu, c2c_he->cpuset);
136}
137
Jiri Olsa92062d52016-06-05 13:40:53 +0200138static void compute_stats(struct c2c_hist_entry *c2c_he,
139 struct c2c_stats *stats,
140 u64 weight)
141{
142 struct compute_stats *cstats = &c2c_he->cstats;
143
144 if (stats->rmt_hitm)
145 update_stats(&cstats->rmt_hitm, weight);
146 else if (stats->lcl_hitm)
147 update_stats(&cstats->lcl_hitm, weight);
148 else if (stats->load)
149 update_stats(&cstats->load, weight);
150}
151
Jiri Olsa78b27542016-09-22 17:36:44 +0200152static int process_sample_event(struct perf_tool *tool __maybe_unused,
153 union perf_event *event,
154 struct perf_sample *sample,
155 struct perf_evsel *evsel __maybe_unused,
156 struct machine *machine)
157{
Jiri Olsab2252ae2016-09-22 17:36:46 +0200158 struct c2c_hists *c2c_hists = &c2c.hists;
159 struct c2c_hist_entry *c2c_he;
160 struct c2c_stats stats = { .nr_entries = 0, };
Jiri Olsa78b27542016-09-22 17:36:44 +0200161 struct hist_entry *he;
162 struct addr_location al;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200163 struct mem_info *mi, *mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200164 int ret;
165
166 if (machine__resolve(machine, &al, sample) < 0) {
167 pr_debug("problem processing %d event, skipping it.\n",
168 event->header.type);
169 return -1;
170 }
171
172 mi = sample__resolve_mem(sample, &al);
173 if (mi == NULL)
174 return -ENOMEM;
175
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200176 mi_dup = memdup(mi, sizeof(*mi));
177 if (!mi_dup)
178 goto free_mi;
179
Jiri Olsab2252ae2016-09-22 17:36:46 +0200180 c2c_decode_stats(&stats, mi);
181
182 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsa78b27542016-09-22 17:36:44 +0200183 &al, NULL, NULL, mi,
184 sample, true);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200185 if (he == NULL)
186 goto free_mi_dup;
Jiri Olsa78b27542016-09-22 17:36:44 +0200187
Jiri Olsab2252ae2016-09-22 17:36:46 +0200188 c2c_he = container_of(he, struct c2c_hist_entry, he);
189 c2c_add_stats(&c2c_he->stats, &stats);
190 c2c_add_stats(&c2c_hists->stats, &stats);
191
Jiri Olsa1e181b92016-06-03 15:40:28 +0200192 c2c_he__set_cpu(c2c_he, sample);
193
Jiri Olsab2252ae2016-09-22 17:36:46 +0200194 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsa78b27542016-09-22 17:36:44 +0200195 ret = hist_entry__append_callchain(he, sample);
196
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200197 if (!ret) {
Jiri Olsa1e181b92016-06-03 15:40:28 +0200198 /*
199 * There's already been warning about missing
200 * sample's cpu value. Let's account all to
201 * node 0 in this case, without any further
202 * warning.
203 *
204 * Doing node stats only for single callchain data.
205 */
206 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
207 int node = c2c.cpu2node[cpu];
208
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200209 mi = mi_dup;
210
211 mi_dup = memdup(mi, sizeof(*mi));
212 if (!mi_dup)
213 goto free_mi;
214
Jiri Olsab2252ae2016-09-22 17:36:46 +0200215 c2c_hists = he__get_c2c_hists(he, "offset");
216 if (!c2c_hists)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200217 goto free_mi_dup;
218
Jiri Olsab2252ae2016-09-22 17:36:46 +0200219 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200220 &al, NULL, NULL, mi,
221 sample, true);
222 if (he == NULL)
223 goto free_mi_dup;
224
Jiri Olsab2252ae2016-09-22 17:36:46 +0200225 c2c_he = container_of(he, struct c2c_hist_entry, he);
226 c2c_add_stats(&c2c_he->stats, &stats);
227 c2c_add_stats(&c2c_hists->stats, &stats);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200228 c2c_add_stats(&c2c_he->node_stats[node], &stats);
229
Jiri Olsa92062d52016-06-05 13:40:53 +0200230 compute_stats(c2c_he, &stats, sample->weight);
231
Jiri Olsa1e181b92016-06-03 15:40:28 +0200232 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200233
234 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200235 ret = hist_entry__append_callchain(he, sample);
236 }
237
238out:
Jiri Olsa78b27542016-09-22 17:36:44 +0200239 addr_location__put(&al);
240 return ret;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200241
242free_mi_dup:
243 free(mi_dup);
244free_mi:
245 free(mi);
246 ret = -ENOMEM;
247 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200248}
249
250static struct perf_c2c c2c = {
251 .tool = {
252 .sample = process_sample_event,
253 .mmap = perf_event__process_mmap,
254 .mmap2 = perf_event__process_mmap2,
255 .comm = perf_event__process_comm,
256 .exit = perf_event__process_exit,
257 .fork = perf_event__process_fork,
258 .lost = perf_event__process_lost,
259 .ordered_events = true,
260 .ordering_requires_timestamps = true,
261 },
262};
263
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200264static const char * const c2c_usage[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +0200265 "perf c2c {record|report}",
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200266 NULL
267};
268
Jiri Olsa903a6f12016-09-22 17:36:40 +0200269static const char * const __usage_report[] = {
270 "perf c2c report",
271 NULL
272};
273
274static const char * const *report_c2c_usage = __usage_report;
275
Jiri Olsac75540e2016-09-22 17:36:41 +0200276#define C2C_HEADER_MAX 2
277
278struct c2c_header {
279 struct {
280 const char *text;
281 int span;
282 } line[C2C_HEADER_MAX];
283};
284
285struct c2c_dimension {
286 struct c2c_header header;
287 const char *name;
288 int width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200289 struct sort_entry *se;
Jiri Olsac75540e2016-09-22 17:36:41 +0200290
291 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
292 struct hist_entry *, struct hist_entry *);
293 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
294 struct hist_entry *he);
295 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
296 struct hist_entry *he);
297};
298
299struct c2c_fmt {
300 struct perf_hpp_fmt fmt;
301 struct c2c_dimension *dim;
302};
303
304static int c2c_width(struct perf_hpp_fmt *fmt,
305 struct perf_hpp *hpp __maybe_unused,
306 struct hists *hists __maybe_unused)
307{
308 struct c2c_fmt *c2c_fmt;
Jiri Olsac75540e2016-09-22 17:36:41 +0200309 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +0200310
311 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
312 dim = c2c_fmt->dim;
313
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200314 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
315 c2c_fmt->dim->width;
316}
317
318static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
319 struct hists *hists, int line, int *span)
320{
321 struct perf_hpp_list *hpp_list = hists->hpp_list;
322 struct c2c_fmt *c2c_fmt;
323 struct c2c_dimension *dim;
324 const char *text = NULL;
325 int width = c2c_width(fmt, hpp, hists);
326
327 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
328 dim = c2c_fmt->dim;
329
330 if (dim->se) {
331 text = dim->header.line[line].text;
332 /* Use the last line from sort_entry if not defined. */
333 if (!text && (line == hpp_list->nr_header_lines - 1))
334 text = dim->se->se_header;
335 } else {
336 text = dim->header.line[line].text;
337
338 if (*span) {
339 (*span)--;
340 return 0;
341 } else {
342 *span = dim->header.line[line].span;
343 }
344 }
345
Jiri Olsac75540e2016-09-22 17:36:41 +0200346 if (text == NULL)
347 text = "";
348
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200349 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
Jiri Olsac75540e2016-09-22 17:36:41 +0200350}
351
Jiri Olsacbb88502016-09-22 17:36:48 +0200352#define HEX_STR(__s, __v) \
353({ \
354 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
355 __s; \
356})
357
358static int64_t
359dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
360 struct hist_entry *left, struct hist_entry *right)
361{
362 return sort__dcacheline_cmp(left, right);
363}
364
365static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
366 struct hist_entry *he)
367{
368 uint64_t addr = 0;
369 int width = c2c_width(fmt, hpp, he->hists);
370 char buf[20];
371
372 if (he->mem_info)
373 addr = cl_address(he->mem_info->daddr.addr);
374
375 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
376}
377
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200378static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
379 struct hist_entry *he)
380{
381 uint64_t addr = 0;
382 int width = c2c_width(fmt, hpp, he->hists);
383 char buf[20];
384
385 if (he->mem_info)
386 addr = cl_offset(he->mem_info->daddr.al_addr);
387
388 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
389}
390
391static int64_t
392offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
393 struct hist_entry *left, struct hist_entry *right)
394{
395 uint64_t l = 0, r = 0;
396
397 if (left->mem_info)
398 l = cl_offset(left->mem_info->daddr.addr);
399 if (right->mem_info)
400 r = cl_offset(right->mem_info->daddr.addr);
401
402 return (int64_t)(r - l);
403}
404
Jiri Olsa43575a92016-05-03 21:48:56 +0200405static int
406iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
407 struct hist_entry *he)
408{
409 uint64_t addr = 0;
410 int width = c2c_width(fmt, hpp, he->hists);
411 char buf[20];
412
413 if (he->mem_info)
414 addr = he->mem_info->iaddr.addr;
415
416 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
417}
418
419static int64_t
420iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
421 struct hist_entry *left, struct hist_entry *right)
422{
423 return sort__iaddr_cmp(left, right);
424}
425
Jiri Olsa97cb4862016-05-23 16:20:14 +0200426static int
427tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
428 struct hist_entry *he)
429{
430 struct c2c_hist_entry *c2c_he;
431 int width = c2c_width(fmt, hpp, he->hists);
432 unsigned int tot_hitm;
433
434 c2c_he = container_of(he, struct c2c_hist_entry, he);
435 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
436
437 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
438}
439
440static int64_t
441tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
442 struct hist_entry *left, struct hist_entry *right)
443{
444 struct c2c_hist_entry *c2c_left;
445 struct c2c_hist_entry *c2c_right;
446 unsigned int tot_hitm_left;
447 unsigned int tot_hitm_right;
448
449 c2c_left = container_of(left, struct c2c_hist_entry, he);
450 c2c_right = container_of(right, struct c2c_hist_entry, he);
451
452 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
453 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
454
455 return tot_hitm_left - tot_hitm_right;
456}
457
458#define STAT_FN_ENTRY(__f) \
459static int \
460__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
461 struct hist_entry *he) \
462{ \
463 struct c2c_hist_entry *c2c_he; \
464 int width = c2c_width(fmt, hpp, he->hists); \
465 \
466 c2c_he = container_of(he, struct c2c_hist_entry, he); \
467 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
468 c2c_he->stats.__f); \
469}
470
471#define STAT_FN_CMP(__f) \
472static int64_t \
473__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
474 struct hist_entry *left, struct hist_entry *right) \
475{ \
476 struct c2c_hist_entry *c2c_left, *c2c_right; \
477 \
478 c2c_left = container_of(left, struct c2c_hist_entry, he); \
479 c2c_right = container_of(right, struct c2c_hist_entry, he); \
480 return c2c_left->stats.__f - c2c_right->stats.__f; \
481}
482
483#define STAT_FN(__f) \
484 STAT_FN_ENTRY(__f) \
485 STAT_FN_CMP(__f)
486
487STAT_FN(rmt_hitm)
488STAT_FN(lcl_hitm)
Jiri Olsa0f188962016-05-04 10:10:11 +0200489STAT_FN(store)
490STAT_FN(st_l1hit)
491STAT_FN(st_l1miss)
Jiri Olsa1295f682016-05-04 10:18:24 +0200492STAT_FN(ld_fbhit)
493STAT_FN(ld_l1hit)
494STAT_FN(ld_l2hit)
Jiri Olsa4d089102016-05-04 10:27:51 +0200495STAT_FN(ld_llchit)
496STAT_FN(rmt_hit)
Jiri Olsa97cb4862016-05-23 16:20:14 +0200497
Jiri Olsa04402d22016-05-19 10:10:51 +0200498static uint64_t llc_miss(struct c2c_stats *stats)
499{
500 uint64_t llcmiss;
501
502 llcmiss = stats->lcl_dram +
503 stats->rmt_dram +
504 stats->rmt_hitm +
505 stats->rmt_hit;
506
507 return llcmiss;
508}
509
510static int
511ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
512 struct hist_entry *he)
513{
514 struct c2c_hist_entry *c2c_he;
515 int width = c2c_width(fmt, hpp, he->hists);
516
517 c2c_he = container_of(he, struct c2c_hist_entry, he);
518
519 return scnprintf(hpp->buf, hpp->size, "%*lu", width,
520 llc_miss(&c2c_he->stats));
521}
522
523static int64_t
524ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
525 struct hist_entry *left, struct hist_entry *right)
526{
527 struct c2c_hist_entry *c2c_left;
528 struct c2c_hist_entry *c2c_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 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);
534}
535
Jiri Olsa01b84d72016-05-04 10:35:29 +0200536static uint64_t total_records(struct c2c_stats *stats)
537{
538 uint64_t lclmiss, ldcnt, total;
539
540 lclmiss = stats->lcl_dram +
541 stats->rmt_dram +
542 stats->rmt_hitm +
543 stats->rmt_hit;
544
545 ldcnt = lclmiss +
546 stats->ld_fbhit +
547 stats->ld_l1hit +
548 stats->ld_l2hit +
549 stats->ld_llchit +
550 stats->lcl_hitm;
551
552 total = ldcnt +
553 stats->st_l1hit +
554 stats->st_l1miss;
555
556 return total;
557}
558
559static int
560tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
561 struct hist_entry *he)
562{
563 struct c2c_hist_entry *c2c_he;
564 int width = c2c_width(fmt, hpp, he->hists);
565 uint64_t tot_recs;
566
567 c2c_he = container_of(he, struct c2c_hist_entry, he);
568 tot_recs = total_records(&c2c_he->stats);
569
570 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
571}
572
573static int64_t
574tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
575 struct hist_entry *left, struct hist_entry *right)
576{
577 struct c2c_hist_entry *c2c_left;
578 struct c2c_hist_entry *c2c_right;
579 uint64_t tot_recs_left;
580 uint64_t tot_recs_right;
581
582 c2c_left = container_of(left, struct c2c_hist_entry, he);
583 c2c_right = container_of(right, struct c2c_hist_entry, he);
584
585 tot_recs_left = total_records(&c2c_left->stats);
586 tot_recs_right = total_records(&c2c_right->stats);
587
588 return tot_recs_left - tot_recs_right;
589}
590
Jiri Olsa55177c42016-05-19 09:52:37 +0200591static uint64_t total_loads(struct c2c_stats *stats)
592{
593 uint64_t lclmiss, ldcnt;
594
595 lclmiss = stats->lcl_dram +
596 stats->rmt_dram +
597 stats->rmt_hitm +
598 stats->rmt_hit;
599
600 ldcnt = lclmiss +
601 stats->ld_fbhit +
602 stats->ld_l1hit +
603 stats->ld_l2hit +
604 stats->ld_llchit +
605 stats->lcl_hitm;
606
607 return ldcnt;
608}
609
610static int
611tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
612 struct hist_entry *he)
613{
614 struct c2c_hist_entry *c2c_he;
615 int width = c2c_width(fmt, hpp, he->hists);
616 uint64_t tot_recs;
617
618 c2c_he = container_of(he, struct c2c_hist_entry, he);
619 tot_recs = total_loads(&c2c_he->stats);
620
621 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
622}
623
624static int64_t
625tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
626 struct hist_entry *left, struct hist_entry *right)
627{
628 struct c2c_hist_entry *c2c_left;
629 struct c2c_hist_entry *c2c_right;
630 uint64_t tot_recs_left;
631 uint64_t tot_recs_right;
632
633 c2c_left = container_of(left, struct c2c_hist_entry, he);
634 c2c_right = container_of(right, struct c2c_hist_entry, he);
635
636 tot_recs_left = total_loads(&c2c_left->stats);
637 tot_recs_right = total_loads(&c2c_right->stats);
638
639 return tot_recs_left - tot_recs_right;
640}
641
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200642typedef double (get_percent_cb)(struct c2c_hist_entry *);
643
644static int
645percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
646 struct hist_entry *he, get_percent_cb get_percent)
647{
648 struct c2c_hist_entry *c2c_he;
649 int width = c2c_width(fmt, hpp, he->hists);
650 double per;
651
652 c2c_he = container_of(he, struct c2c_hist_entry, he);
653 per = get_percent(c2c_he);
654
655 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
656}
657
658static double percent_hitm(struct c2c_hist_entry *c2c_he)
659{
660 struct c2c_hists *hists;
661 struct c2c_stats *stats;
662 struct c2c_stats *total;
663 int tot, st;
664 double p;
665
666 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
667 stats = &c2c_he->stats;
668 total = &hists->stats;
669
670 st = stats->rmt_hitm;
671 tot = total->rmt_hitm;
672
673 p = tot ? (double) st / tot : 0;
674
675 return 100 * p;
676}
677
678#define PERC_STR(__s, __v) \
679({ \
680 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
681 __s; \
682})
683
684static int
685percent_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
686 struct hist_entry *he)
687{
688 struct c2c_hist_entry *c2c_he;
689 int width = c2c_width(fmt, hpp, he->hists);
690 char buf[10];
691 double per;
692
693 c2c_he = container_of(he, struct c2c_hist_entry, he);
694 per = percent_hitm(c2c_he);
695 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
696}
697
698static int
699percent_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
700 struct hist_entry *he)
701{
702 return percent_color(fmt, hpp, he, percent_hitm);
703}
704
705static int64_t
706percent_hitm_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 double per_left;
712 double per_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 per_left = percent_hitm(c2c_left);
718 per_right = percent_hitm(c2c_right);
719
720 return per_left - per_right;
721}
722
Jiri Olsa9cb35002016-05-04 12:16:50 +0200723static struct c2c_stats *he_stats(struct hist_entry *he)
724{
725 struct c2c_hist_entry *c2c_he;
726
727 c2c_he = container_of(he, struct c2c_hist_entry, he);
728 return &c2c_he->stats;
729}
730
731static struct c2c_stats *total_stats(struct hist_entry *he)
732{
733 struct c2c_hists *hists;
734
735 hists = container_of(he->hists, struct c2c_hists, hists);
736 return &hists->stats;
737}
738
739static double percent(int st, int tot)
740{
741 return tot ? 100. * (double) st / (double) tot : 0;
742}
743
744#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
745
746#define PERCENT_FN(__f) \
747static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
748{ \
749 struct c2c_hists *hists; \
750 \
751 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
752 return percent(c2c_he->stats.__f, hists->stats.__f); \
753}
754
755PERCENT_FN(rmt_hitm)
756PERCENT_FN(lcl_hitm)
757PERCENT_FN(st_l1hit)
758PERCENT_FN(st_l1miss)
759
760static int
761percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
762 struct hist_entry *he)
763{
764 int width = c2c_width(fmt, hpp, he->hists);
765 double per = PERCENT(he, rmt_hitm);
766 char buf[10];
767
768 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
769}
770
771static int
772percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
773 struct hist_entry *he)
774{
775 return percent_color(fmt, hpp, he, percent_rmt_hitm);
776}
777
778static int64_t
779percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
780 struct hist_entry *left, struct hist_entry *right)
781{
782 double per_left;
783 double per_right;
784
785 per_left = PERCENT(left, lcl_hitm);
786 per_right = PERCENT(right, lcl_hitm);
787
788 return per_left - per_right;
789}
790
791static int
792percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
793 struct hist_entry *he)
794{
795 int width = c2c_width(fmt, hpp, he->hists);
796 double per = PERCENT(he, lcl_hitm);
797 char buf[10];
798
799 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
800}
801
802static int
803percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
804 struct hist_entry *he)
805{
806 return percent_color(fmt, hpp, he, percent_lcl_hitm);
807}
808
809static int64_t
810percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
811 struct hist_entry *left, struct hist_entry *right)
812{
813 double per_left;
814 double per_right;
815
816 per_left = PERCENT(left, lcl_hitm);
817 per_right = PERCENT(right, lcl_hitm);
818
819 return per_left - per_right;
820}
821
822static int
823percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
824 struct hist_entry *he)
825{
826 int width = c2c_width(fmt, hpp, he->hists);
827 double per = PERCENT(he, st_l1hit);
828 char buf[10];
829
830 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
831}
832
833static int
834percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
835 struct hist_entry *he)
836{
837 return percent_color(fmt, hpp, he, percent_st_l1hit);
838}
839
840static int64_t
841percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
842 struct hist_entry *left, struct hist_entry *right)
843{
844 double per_left;
845 double per_right;
846
847 per_left = PERCENT(left, st_l1hit);
848 per_right = PERCENT(right, st_l1hit);
849
850 return per_left - per_right;
851}
852
853static int
854percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
855 struct hist_entry *he)
856{
857 int width = c2c_width(fmt, hpp, he->hists);
858 double per = PERCENT(he, st_l1miss);
859 char buf[10];
860
861 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
862}
863
864static int
865percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
866 struct hist_entry *he)
867{
868 return percent_color(fmt, hpp, he, percent_st_l1miss);
869}
870
871static int64_t
872percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
873 struct hist_entry *left, struct hist_entry *right)
874{
875 double per_left;
876 double per_right;
877
878 per_left = PERCENT(left, st_l1miss);
879 per_right = PERCENT(right, st_l1miss);
880
881 return per_left - per_right;
882}
883
Jiri Olsa6c70f542016-05-28 12:30:13 +0200884STAT_FN(lcl_dram)
885STAT_FN(rmt_dram)
886
Jiri Olsa36d3deb2016-05-24 13:09:47 +0200887static int
888pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
889 struct hist_entry *he)
890{
891 int width = c2c_width(fmt, hpp, he->hists);
892
893 return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
894}
895
896static int64_t
897pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
898 struct hist_entry *left, struct hist_entry *right)
899{
900 return left->thread->pid_ - right->thread->pid_;
901}
902
Jiri Olsa1e181b92016-06-03 15:40:28 +0200903static int64_t
904empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
905 struct hist_entry *left __maybe_unused,
906 struct hist_entry *right __maybe_unused)
907{
908 return 0;
909}
910
911static int
912node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
913 struct hist_entry *he)
914{
915 struct c2c_hist_entry *c2c_he;
916 bool first = true;
917 int node;
918 int ret = 0;
919
920 c2c_he = container_of(he, struct c2c_hist_entry, he);
921
922 for (node = 0; node < c2c.nodes_cnt; node++) {
923 DECLARE_BITMAP(set, c2c.cpus_cnt);
924
925 bitmap_zero(set, c2c.cpus_cnt);
926 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
927
928 if (!bitmap_weight(set, c2c.cpus_cnt)) {
929 if (c2c.node_info == 1) {
930 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
931 advance_hpp(hpp, ret);
932 }
933 continue;
934 }
935
936 if (!first) {
937 ret = scnprintf(hpp->buf, hpp->size, " ");
938 advance_hpp(hpp, ret);
939 }
940
941 switch (c2c.node_info) {
942 case 0:
943 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
944 advance_hpp(hpp, ret);
945 break;
946 case 1:
947 {
948 int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
949 struct c2c_stats *stats = &c2c_he->node_stats[node];
950
951 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
952 advance_hpp(hpp, ret);
953
954
955 if (c2c_he->stats.rmt_hitm > 0) {
956 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ",
957 percent(stats->rmt_hitm, c2c_he->stats.rmt_hitm));
958 } else {
959 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a");
960 }
961
962 advance_hpp(hpp, ret);
963
964 if (c2c_he->stats.store > 0) {
965 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
966 percent(stats->store, c2c_he->stats.store));
967 } else {
968 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
969 }
970
971 advance_hpp(hpp, ret);
972 break;
973 }
974 case 2:
975 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
976 advance_hpp(hpp, ret);
977
978 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
979 advance_hpp(hpp, ret);
980
981 ret = scnprintf(hpp->buf, hpp->size, "}");
982 advance_hpp(hpp, ret);
983 break;
984 default:
985 break;
986 }
987
988 first = false;
989 }
990
991 return 0;
992}
993
Jiri Olsa92062d52016-06-05 13:40:53 +0200994static int
995mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
996 struct hist_entry *he, double mean)
997{
998 int width = c2c_width(fmt, hpp, he->hists);
999 char buf[10];
1000
1001 scnprintf(buf, 10, "%6.0f", mean);
1002 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1003}
1004
1005#define MEAN_ENTRY(__func, __val) \
1006static int \
1007__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1008{ \
1009 struct c2c_hist_entry *c2c_he; \
1010 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1011 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1012}
1013
1014MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1015MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1016MEAN_ENTRY(mean_load_entry, load);
1017
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001018static int
1019cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1020 struct hist_entry *he)
1021{
1022 struct c2c_hist_entry *c2c_he;
1023 int width = c2c_width(fmt, hpp, he->hists);
1024 char buf[10];
1025
1026 c2c_he = container_of(he, struct c2c_hist_entry, he);
1027
1028 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1029 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1030}
1031
Jiri Olsa600a8cf2016-09-22 17:36:47 +02001032#define HEADER_LOW(__h) \
1033 { \
1034 .line[1] = { \
1035 .text = __h, \
1036 }, \
1037 }
1038
1039#define HEADER_BOTH(__h0, __h1) \
1040 { \
1041 .line[0] = { \
1042 .text = __h0, \
1043 }, \
1044 .line[1] = { \
1045 .text = __h1, \
1046 }, \
1047 }
1048
1049#define HEADER_SPAN(__h0, __h1, __s) \
1050 { \
1051 .line[0] = { \
1052 .text = __h0, \
1053 .span = __s, \
1054 }, \
1055 .line[1] = { \
1056 .text = __h1, \
1057 }, \
1058 }
1059
1060#define HEADER_SPAN_LOW(__h) \
1061 { \
1062 .line[1] = { \
1063 .text = __h, \
1064 }, \
1065 }
1066
Jiri Olsacbb88502016-09-22 17:36:48 +02001067static struct c2c_dimension dim_dcacheline = {
1068 .header = HEADER_LOW("Cacheline"),
1069 .name = "dcacheline",
1070 .cmp = dcacheline_cmp,
1071 .entry = dcacheline_entry,
1072 .width = 18,
1073};
1074
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001075static struct c2c_dimension dim_offset = {
1076 .header = HEADER_BOTH("Data address", "Offset"),
1077 .name = "offset",
1078 .cmp = offset_cmp,
1079 .entry = offset_entry,
1080 .width = 18,
1081};
1082
Jiri Olsa43575a92016-05-03 21:48:56 +02001083static struct c2c_dimension dim_iaddr = {
1084 .header = HEADER_LOW("Code address"),
1085 .name = "iaddr",
1086 .cmp = iaddr_cmp,
1087 .entry = iaddr_entry,
1088 .width = 18,
1089};
1090
Jiri Olsa97cb4862016-05-23 16:20:14 +02001091static struct c2c_dimension dim_tot_hitm = {
1092 .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1093 .name = "tot_hitm",
1094 .cmp = tot_hitm_cmp,
1095 .entry = tot_hitm_entry,
1096 .width = 7,
1097};
1098
1099static struct c2c_dimension dim_lcl_hitm = {
1100 .header = HEADER_SPAN_LOW("Lcl"),
1101 .name = "lcl_hitm",
1102 .cmp = lcl_hitm_cmp,
1103 .entry = lcl_hitm_entry,
1104 .width = 7,
1105};
1106
1107static struct c2c_dimension dim_rmt_hitm = {
1108 .header = HEADER_SPAN_LOW("Rmt"),
1109 .name = "rmt_hitm",
1110 .cmp = rmt_hitm_cmp,
1111 .entry = rmt_hitm_entry,
1112 .width = 7,
1113};
1114
1115static struct c2c_dimension dim_cl_rmt_hitm = {
1116 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1117 .name = "cl_rmt_hitm",
1118 .cmp = rmt_hitm_cmp,
1119 .entry = rmt_hitm_entry,
1120 .width = 7,
1121};
1122
1123static struct c2c_dimension dim_cl_lcl_hitm = {
1124 .header = HEADER_SPAN_LOW("Lcl"),
1125 .name = "cl_lcl_hitm",
1126 .cmp = lcl_hitm_cmp,
1127 .entry = lcl_hitm_entry,
1128 .width = 7,
1129};
1130
Jiri Olsa0f188962016-05-04 10:10:11 +02001131static struct c2c_dimension dim_stores = {
1132 .header = HEADER_SPAN("---- Store Reference ----", "Total", 2),
1133 .name = "stores",
1134 .cmp = store_cmp,
1135 .entry = store_entry,
1136 .width = 7,
1137};
1138
1139static struct c2c_dimension dim_stores_l1hit = {
1140 .header = HEADER_SPAN_LOW("L1Hit"),
1141 .name = "stores_l1hit",
1142 .cmp = st_l1hit_cmp,
1143 .entry = st_l1hit_entry,
1144 .width = 7,
1145};
1146
1147static struct c2c_dimension dim_stores_l1miss = {
1148 .header = HEADER_SPAN_LOW("L1Miss"),
1149 .name = "stores_l1miss",
1150 .cmp = st_l1miss_cmp,
1151 .entry = st_l1miss_entry,
1152 .width = 7,
1153};
1154
1155static struct c2c_dimension dim_cl_stores_l1hit = {
1156 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1157 .name = "cl_stores_l1hit",
1158 .cmp = st_l1hit_cmp,
1159 .entry = st_l1hit_entry,
1160 .width = 7,
1161};
1162
1163static struct c2c_dimension dim_cl_stores_l1miss = {
1164 .header = HEADER_SPAN_LOW("L1 Miss"),
1165 .name = "cl_stores_l1miss",
1166 .cmp = st_l1miss_cmp,
1167 .entry = st_l1miss_entry,
1168 .width = 7,
1169};
1170
Jiri Olsa1295f682016-05-04 10:18:24 +02001171static struct c2c_dimension dim_ld_fbhit = {
1172 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1173 .name = "ld_fbhit",
1174 .cmp = ld_fbhit_cmp,
1175 .entry = ld_fbhit_entry,
1176 .width = 7,
1177};
1178
1179static struct c2c_dimension dim_ld_l1hit = {
1180 .header = HEADER_SPAN_LOW("L1"),
1181 .name = "ld_l1hit",
1182 .cmp = ld_l1hit_cmp,
1183 .entry = ld_l1hit_entry,
1184 .width = 7,
1185};
1186
1187static struct c2c_dimension dim_ld_l2hit = {
1188 .header = HEADER_SPAN_LOW("L2"),
1189 .name = "ld_l2hit",
1190 .cmp = ld_l2hit_cmp,
1191 .entry = ld_l2hit_entry,
1192 .width = 7,
1193};
1194
Jiri Olsa4d089102016-05-04 10:27:51 +02001195static struct c2c_dimension dim_ld_llchit = {
1196 .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1),
1197 .name = "ld_lclhit",
1198 .cmp = ld_llchit_cmp,
1199 .entry = ld_llchit_entry,
1200 .width = 8,
1201};
1202
1203static struct c2c_dimension dim_ld_rmthit = {
1204 .header = HEADER_SPAN_LOW("Rmt"),
1205 .name = "ld_rmthit",
1206 .cmp = rmt_hit_cmp,
1207 .entry = rmt_hit_entry,
1208 .width = 8,
1209};
1210
Jiri Olsa04402d22016-05-19 10:10:51 +02001211static struct c2c_dimension dim_ld_llcmiss = {
1212 .header = HEADER_BOTH("LLC", "Ld Miss"),
1213 .name = "ld_llcmiss",
1214 .cmp = ld_llcmiss_cmp,
1215 .entry = ld_llcmiss_entry,
1216 .width = 7,
1217};
1218
Jiri Olsa01b84d72016-05-04 10:35:29 +02001219static struct c2c_dimension dim_tot_recs = {
1220 .header = HEADER_BOTH("Total", "records"),
1221 .name = "tot_recs",
1222 .cmp = tot_recs_cmp,
1223 .entry = tot_recs_entry,
1224 .width = 7,
1225};
1226
Jiri Olsa55177c42016-05-19 09:52:37 +02001227static struct c2c_dimension dim_tot_loads = {
1228 .header = HEADER_BOTH("Total", "Loads"),
1229 .name = "tot_loads",
1230 .cmp = tot_loads_cmp,
1231 .entry = tot_loads_entry,
1232 .width = 7,
1233};
1234
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001235static struct c2c_dimension dim_percent_hitm = {
1236 .header = HEADER_LOW("%hitm"),
1237 .name = "percent_hitm",
1238 .cmp = percent_hitm_cmp,
1239 .entry = percent_hitm_entry,
1240 .color = percent_hitm_color,
1241 .width = 7,
1242};
1243
Jiri Olsa9cb35002016-05-04 12:16:50 +02001244static struct c2c_dimension dim_percent_rmt_hitm = {
1245 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1246 .name = "percent_rmt_hitm",
1247 .cmp = percent_rmt_hitm_cmp,
1248 .entry = percent_rmt_hitm_entry,
1249 .color = percent_rmt_hitm_color,
1250 .width = 7,
1251};
1252
1253static struct c2c_dimension dim_percent_lcl_hitm = {
1254 .header = HEADER_SPAN_LOW("Lcl"),
1255 .name = "percent_lcl_hitm",
1256 .cmp = percent_lcl_hitm_cmp,
1257 .entry = percent_lcl_hitm_entry,
1258 .color = percent_lcl_hitm_color,
1259 .width = 7,
1260};
1261
1262static struct c2c_dimension dim_percent_stores_l1hit = {
1263 .header = HEADER_SPAN("-- Store Refs --", "L1 Hit", 1),
1264 .name = "percent_stores_l1hit",
1265 .cmp = percent_stores_l1hit_cmp,
1266 .entry = percent_stores_l1hit_entry,
1267 .color = percent_stores_l1hit_color,
1268 .width = 7,
1269};
1270
1271static struct c2c_dimension dim_percent_stores_l1miss = {
1272 .header = HEADER_SPAN_LOW("L1 Miss"),
1273 .name = "percent_stores_l1miss",
1274 .cmp = percent_stores_l1miss_cmp,
1275 .entry = percent_stores_l1miss_entry,
1276 .color = percent_stores_l1miss_color,
1277 .width = 7,
1278};
1279
Jiri Olsa6c70f542016-05-28 12:30:13 +02001280static struct c2c_dimension dim_dram_lcl = {
1281 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1282 .name = "dram_lcl",
1283 .cmp = lcl_dram_cmp,
1284 .entry = lcl_dram_entry,
1285 .width = 8,
1286};
1287
1288static struct c2c_dimension dim_dram_rmt = {
1289 .header = HEADER_SPAN_LOW("Rmt"),
1290 .name = "dram_rmt",
1291 .cmp = rmt_dram_cmp,
1292 .entry = rmt_dram_entry,
1293 .width = 8,
1294};
1295
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001296static struct c2c_dimension dim_pid = {
1297 .header = HEADER_LOW("Pid"),
1298 .name = "pid",
1299 .cmp = pid_cmp,
1300 .entry = pid_entry,
1301 .width = 7,
1302};
1303
Jiri Olsae87019c2016-05-25 08:50:10 +02001304static struct c2c_dimension dim_tid = {
1305 .header = HEADER_LOW("Tid"),
1306 .name = "tid",
1307 .se = &sort_thread,
1308};
1309
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001310static struct c2c_dimension dim_symbol = {
1311 .name = "symbol",
1312 .se = &sort_sym,
1313};
1314
1315static struct c2c_dimension dim_dso = {
1316 .header = HEADER_BOTH("Shared", "Object"),
1317 .name = "dso",
1318 .se = &sort_dso,
1319};
1320
Jiri Olsa1e181b92016-06-03 15:40:28 +02001321static struct c2c_header header_node[3] = {
1322 HEADER_LOW("Node"),
1323 HEADER_LOW("Node{cpus %hitms %stores}"),
1324 HEADER_LOW("Node{cpu list}"),
1325};
1326
1327static struct c2c_dimension dim_node = {
1328 .name = "node",
1329 .cmp = empty_cmp,
1330 .entry = node_entry,
1331 .width = 4,
1332};
1333
Jiri Olsa92062d52016-06-05 13:40:53 +02001334static struct c2c_dimension dim_mean_rmt = {
1335 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1336 .name = "mean_rmt",
1337 .cmp = empty_cmp,
1338 .entry = mean_rmt_entry,
1339 .width = 8,
1340};
1341
1342static struct c2c_dimension dim_mean_lcl = {
1343 .header = HEADER_SPAN_LOW("lcl hitm"),
1344 .name = "mean_lcl",
1345 .cmp = empty_cmp,
1346 .entry = mean_lcl_entry,
1347 .width = 8,
1348};
1349
1350static struct c2c_dimension dim_mean_load = {
1351 .header = HEADER_SPAN_LOW("load"),
1352 .name = "mean_load",
1353 .cmp = empty_cmp,
1354 .entry = mean_load_entry,
1355 .width = 8,
1356};
1357
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001358static struct c2c_dimension dim_cpucnt = {
1359 .header = HEADER_BOTH("cpu", "cnt"),
1360 .name = "cpucnt",
1361 .cmp = empty_cmp,
1362 .entry = cpucnt_entry,
1363 .width = 8,
1364};
1365
Jiri Olsac75540e2016-09-22 17:36:41 +02001366static struct c2c_dimension *dimensions[] = {
Jiri Olsacbb88502016-09-22 17:36:48 +02001367 &dim_dcacheline,
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001368 &dim_offset,
Jiri Olsa43575a92016-05-03 21:48:56 +02001369 &dim_iaddr,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001370 &dim_tot_hitm,
1371 &dim_lcl_hitm,
1372 &dim_rmt_hitm,
1373 &dim_cl_lcl_hitm,
1374 &dim_cl_rmt_hitm,
Jiri Olsa0f188962016-05-04 10:10:11 +02001375 &dim_stores,
1376 &dim_stores_l1hit,
1377 &dim_stores_l1miss,
1378 &dim_cl_stores_l1hit,
1379 &dim_cl_stores_l1miss,
Jiri Olsa1295f682016-05-04 10:18:24 +02001380 &dim_ld_fbhit,
1381 &dim_ld_l1hit,
1382 &dim_ld_l2hit,
Jiri Olsa4d089102016-05-04 10:27:51 +02001383 &dim_ld_llchit,
1384 &dim_ld_rmthit,
Jiri Olsa04402d22016-05-19 10:10:51 +02001385 &dim_ld_llcmiss,
Jiri Olsa01b84d72016-05-04 10:35:29 +02001386 &dim_tot_recs,
Jiri Olsa55177c42016-05-19 09:52:37 +02001387 &dim_tot_loads,
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001388 &dim_percent_hitm,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001389 &dim_percent_rmt_hitm,
1390 &dim_percent_lcl_hitm,
1391 &dim_percent_stores_l1hit,
1392 &dim_percent_stores_l1miss,
Jiri Olsa6c70f542016-05-28 12:30:13 +02001393 &dim_dram_lcl,
1394 &dim_dram_rmt,
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001395 &dim_pid,
Jiri Olsae87019c2016-05-25 08:50:10 +02001396 &dim_tid,
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001397 &dim_symbol,
1398 &dim_dso,
Jiri Olsa1e181b92016-06-03 15:40:28 +02001399 &dim_node,
Jiri Olsa92062d52016-06-05 13:40:53 +02001400 &dim_mean_rmt,
1401 &dim_mean_lcl,
1402 &dim_mean_load,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001403 &dim_cpucnt,
Jiri Olsac75540e2016-09-22 17:36:41 +02001404 NULL,
1405};
1406
1407static void fmt_free(struct perf_hpp_fmt *fmt)
1408{
1409 struct c2c_fmt *c2c_fmt;
1410
1411 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1412 free(c2c_fmt);
1413}
1414
1415static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1416{
1417 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1418 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1419
1420 return c2c_a->dim == c2c_b->dim;
1421}
1422
1423static struct c2c_dimension *get_dimension(const char *name)
1424{
1425 unsigned int i;
1426
1427 for (i = 0; dimensions[i]; i++) {
1428 struct c2c_dimension *dim = dimensions[i];
1429
1430 if (!strcmp(dim->name, name))
1431 return dim;
1432 };
1433
1434 return NULL;
1435}
1436
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001437static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1438 struct hist_entry *he)
1439{
1440 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1441 struct c2c_dimension *dim = c2c_fmt->dim;
1442 size_t len = fmt->user_len;
1443
1444 if (!len)
1445 len = hists__col_len(he->hists, dim->se->se_width_idx);
1446
1447 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1448}
1449
1450static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1451 struct hist_entry *a, struct hist_entry *b)
1452{
1453 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1454 struct c2c_dimension *dim = c2c_fmt->dim;
1455
1456 return dim->se->se_cmp(a, b);
1457}
1458
1459static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1460 struct hist_entry *a, struct hist_entry *b)
1461{
1462 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1463 struct c2c_dimension *dim = c2c_fmt->dim;
1464 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1465
1466 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1467 return collapse_fn(a, b);
1468}
1469
Jiri Olsac75540e2016-09-22 17:36:41 +02001470static struct c2c_fmt *get_format(const char *name)
1471{
1472 struct c2c_dimension *dim = get_dimension(name);
1473 struct c2c_fmt *c2c_fmt;
1474 struct perf_hpp_fmt *fmt;
1475
1476 if (!dim)
1477 return NULL;
1478
1479 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1480 if (!c2c_fmt)
1481 return NULL;
1482
1483 c2c_fmt->dim = dim;
1484
1485 fmt = &c2c_fmt->fmt;
1486 INIT_LIST_HEAD(&fmt->list);
1487 INIT_LIST_HEAD(&fmt->sort_list);
1488
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001489 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1490 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
Jiri Olsa9cb35002016-05-04 12:16:50 +02001491 fmt->color = dim->se ? NULL : dim->color;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001492 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
Jiri Olsac75540e2016-09-22 17:36:41 +02001493 fmt->header = c2c_header;
1494 fmt->width = c2c_width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001495 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
Jiri Olsac75540e2016-09-22 17:36:41 +02001496 fmt->equal = fmt_equal;
1497 fmt->free = fmt_free;
1498
1499 return c2c_fmt;
1500}
1501
1502static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1503{
1504 struct c2c_fmt *c2c_fmt = get_format(name);
1505
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001506 if (!c2c_fmt) {
1507 reset_dimensions();
1508 return output_field_add(hpp_list, name);
1509 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001510
1511 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1512 return 0;
1513}
1514
1515static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
1516{
1517 struct c2c_fmt *c2c_fmt = get_format(name);
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001518 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +02001519
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001520 if (!c2c_fmt) {
1521 reset_dimensions();
1522 return sort_dimension__add(hpp_list, name, NULL, 0);
1523 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001524
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001525 dim = c2c_fmt->dim;
1526 if (dim == &dim_dso)
1527 hpp_list->dso = 1;
1528
Jiri Olsac75540e2016-09-22 17:36:41 +02001529 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
1530 return 0;
1531}
1532
1533#define PARSE_LIST(_list, _fn) \
1534 do { \
1535 char *tmp, *tok; \
1536 ret = 0; \
1537 \
1538 if (!_list) \
1539 break; \
1540 \
1541 for (tok = strtok_r((char *)_list, ", ", &tmp); \
1542 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
1543 ret = _fn(hpp_list, tok); \
1544 if (ret == -EINVAL) { \
1545 error("Invalid --fields key: `%s'", tok); \
1546 break; \
1547 } else if (ret == -ESRCH) { \
1548 error("Unknown --fields key: `%s'", tok); \
1549 break; \
1550 } \
1551 } \
1552 } while (0)
1553
1554static int hpp_list__parse(struct perf_hpp_list *hpp_list,
1555 const char *output_,
1556 const char *sort_)
1557{
1558 char *output = output_ ? strdup(output_) : NULL;
1559 char *sort = sort_ ? strdup(sort_) : NULL;
1560 int ret;
1561
1562 PARSE_LIST(output, c2c_hists__init_output);
1563 PARSE_LIST(sort, c2c_hists__init_sort);
1564
1565 /* copy sort keys to output fields */
1566 perf_hpp__setup_output_field(hpp_list);
1567
1568 /*
1569 * We dont need other sorting keys other than those
1570 * we already specified. It also really slows down
1571 * the processing a lot with big number of output
1572 * fields, so switching this off for c2c.
1573 */
1574
1575#if 0
1576 /* and then copy output fields to sort keys */
1577 perf_hpp__append_sort_keys(&hists->list);
1578#endif
1579
1580 free(output);
1581 free(sort);
1582 return ret;
1583}
1584
1585static int c2c_hists__init(struct c2c_hists *hists,
1586 const char *sort)
1587{
1588 __hists__init(&hists->hists, &hists->list);
1589
1590 /*
1591 * Initialize only with sort fields, we need to resort
1592 * later anyway, and that's where we add output fields
1593 * as well.
1594 */
1595 perf_hpp_list__init(&hists->list);
1596
1597 return hpp_list__parse(&hists->list, NULL, sort);
1598}
1599
1600__maybe_unused
1601static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1602 const char *output,
1603 const char *sort)
1604{
1605 perf_hpp__reset_output_field(&c2c_hists->list);
1606 return hpp_list__parse(&c2c_hists->list, output, sort);
1607}
1608
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001609static int filter_cb(struct hist_entry *he __maybe_unused)
1610{
1611 return 0;
1612}
1613
1614static int resort_cl_cb(struct hist_entry *he)
1615{
1616 struct c2c_hist_entry *c2c_he;
1617 struct c2c_hists *c2c_hists;
1618
1619 c2c_he = container_of(he, struct c2c_hist_entry, he);
1620 c2c_hists = c2c_he->hists;
1621
1622 if (c2c_hists) {
1623 hists__collapse_resort(&c2c_hists->hists, NULL);
1624 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
1625 }
1626
1627 return 0;
1628}
1629
Jiri Olsa1e181b92016-06-03 15:40:28 +02001630static void setup_nodes_header(void)
1631{
1632 dim_node.header = header_node[c2c.node_info];
1633}
1634
1635static int setup_nodes(struct perf_session *session)
1636{
1637 struct numa_node *n;
1638 unsigned long **nodes;
1639 int node, cpu;
1640 int *cpu2node;
1641
1642 if (c2c.node_info > 2)
1643 c2c.node_info = 2;
1644
1645 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
1646 c2c.cpus_cnt = session->header.env.nr_cpus_online;
1647
1648 n = session->header.env.numa_nodes;
1649 if (!n)
1650 return -EINVAL;
1651
1652 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
1653 if (!nodes)
1654 return -ENOMEM;
1655
1656 c2c.nodes = nodes;
1657
1658 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
1659 if (!cpu2node)
1660 return -ENOMEM;
1661
1662 for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
1663 cpu2node[cpu] = -1;
1664
1665 c2c.cpu2node = cpu2node;
1666
1667 for (node = 0; node < c2c.nodes_cnt; node++) {
1668 struct cpu_map *map = n[node].map;
1669 unsigned long *set;
1670
1671 set = bitmap_alloc(c2c.cpus_cnt);
1672 if (!set)
1673 return -ENOMEM;
1674
1675 for (cpu = 0; cpu < map->nr; cpu++) {
1676 set_bit(map->map[cpu], set);
1677
1678 if (WARN_ONCE(cpu2node[map->map[cpu]] != -1, "node/cpu topology bug"))
1679 return -EINVAL;
1680
1681 cpu2node[map->map[cpu]] = node;
1682 }
1683
1684 nodes[node] = set;
1685 }
1686
1687 setup_nodes_header();
1688 return 0;
1689}
1690
1691
Jiri Olsa903a6f12016-09-22 17:36:40 +02001692static int perf_c2c__report(int argc, const char **argv)
1693{
1694 struct perf_session *session;
Jiri Olsa78b27542016-09-22 17:36:44 +02001695 struct ui_progress prog;
Jiri Olsa903a6f12016-09-22 17:36:40 +02001696 struct perf_data_file file = {
1697 .mode = PERF_DATA_MODE_READ,
1698 };
1699 const struct option c2c_options[] = {
1700 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1701 "file", "vmlinux pathname"),
1702 OPT_INCR('v', "verbose", &verbose,
1703 "be more verbose (show counter open errors, etc)"),
1704 OPT_STRING('i', "input", &input_name, "file",
1705 "the input file to process"),
Jiri Olsa1e181b92016-06-03 15:40:28 +02001706 OPT_INCR('N', "node-info", &c2c.node_info,
1707 "show extra node info in report (repeat for more info)"),
Jiri Olsa903a6f12016-09-22 17:36:40 +02001708 OPT_END()
1709 };
1710 int err = 0;
1711
1712 argc = parse_options(argc, argv, c2c_options, report_c2c_usage,
1713 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa78b27542016-09-22 17:36:44 +02001714 if (argc)
Jiri Olsa903a6f12016-09-22 17:36:40 +02001715 usage_with_options(report_c2c_usage, c2c_options);
1716
Jiri Olsa78b27542016-09-22 17:36:44 +02001717 if (!input_name || !strlen(input_name))
1718 input_name = "perf.data";
1719
Jiri Olsa903a6f12016-09-22 17:36:40 +02001720 file.path = input_name;
1721
Jiri Olsac75540e2016-09-22 17:36:41 +02001722 err = c2c_hists__init(&c2c.hists, "dcacheline");
1723 if (err) {
1724 pr_debug("Failed to initialize hists\n");
1725 goto out;
1726 }
1727
Jiri Olsa903a6f12016-09-22 17:36:40 +02001728 session = perf_session__new(&file, 0, &c2c.tool);
1729 if (session == NULL) {
1730 pr_debug("No memory for session\n");
1731 goto out;
1732 }
Jiri Olsa1e181b92016-06-03 15:40:28 +02001733 err = setup_nodes(session);
1734 if (err) {
1735 pr_err("Failed setup nodes\n");
1736 goto out;
1737 }
Jiri Olsa903a6f12016-09-22 17:36:40 +02001738
1739 if (symbol__init(&session->header.env) < 0)
1740 goto out_session;
1741
1742 /* No pipe support at the moment. */
1743 if (perf_data_file__is_pipe(session->file)) {
1744 pr_debug("No pipe support at the moment.\n");
1745 goto out_session;
1746 }
1747
Jiri Olsa78b27542016-09-22 17:36:44 +02001748 err = perf_session__process_events(session);
1749 if (err) {
1750 pr_err("failed to process sample\n");
1751 goto out_session;
1752 }
1753
1754 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
1755
1756 hists__collapse_resort(&c2c.hists.hists, NULL);
Jiri Olsaec06f9b2016-09-22 17:36:45 +02001757 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_cl_cb);
Jiri Olsa78b27542016-09-22 17:36:44 +02001758
1759 ui_progress__finish();
1760
Jiri Olsa903a6f12016-09-22 17:36:40 +02001761out_session:
1762 perf_session__delete(session);
1763out:
1764 return err;
1765}
1766
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02001767static int parse_record_events(const struct option *opt __maybe_unused,
1768 const char *str, int unset __maybe_unused)
1769{
1770 bool *event_set = (bool *) opt->value;
1771
1772 *event_set = true;
1773 return perf_mem_events__parse(str);
1774}
1775
1776
1777static const char * const __usage_record[] = {
1778 "perf c2c record [<options>] [<command>]",
1779 "perf c2c record [<options>] -- <command> [<options>]",
1780 NULL
1781};
1782
1783static const char * const *record_mem_usage = __usage_record;
1784
1785static int perf_c2c__record(int argc, const char **argv)
1786{
1787 int rec_argc, i = 0, j;
1788 const char **rec_argv;
1789 int ret;
1790 bool all_user = false, all_kernel = false;
1791 bool event_set = false;
1792 struct option options[] = {
1793 OPT_CALLBACK('e', "event", &event_set, "event",
1794 "event selector. Use 'perf mem record -e list' to list available events",
1795 parse_record_events),
1796 OPT_INCR('v', "verbose", &verbose,
1797 "be more verbose (show counter open errors, etc)"),
1798 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
1799 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
1800 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
1801 OPT_END()
1802 };
1803
1804 if (perf_mem_events__init()) {
1805 pr_err("failed: memory events not supported\n");
1806 return -1;
1807 }
1808
1809 argc = parse_options(argc, argv, options, record_mem_usage,
1810 PARSE_OPT_KEEP_UNKNOWN);
1811
1812 rec_argc = argc + 10; /* max number of arguments */
1813 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1814 if (!rec_argv)
1815 return -1;
1816
1817 rec_argv[i++] = "record";
1818
1819 if (!event_set) {
1820 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
1821 perf_mem_events[PERF_MEM_EVENTS__STORE].record = true;
1822 }
1823
1824 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
1825 rec_argv[i++] = "-W";
1826
1827 rec_argv[i++] = "-d";
1828 rec_argv[i++] = "--sample-cpu";
1829
1830 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
1831 if (!perf_mem_events[j].record)
1832 continue;
1833
1834 if (!perf_mem_events[j].supported) {
1835 pr_err("failed: event '%s' not supported\n",
1836 perf_mem_events[j].name);
1837 return -1;
1838 }
1839
1840 rec_argv[i++] = "-e";
1841 rec_argv[i++] = perf_mem_events__name(j);
1842 };
1843
1844 if (all_user)
1845 rec_argv[i++] = "--all-user";
1846
1847 if (all_kernel)
1848 rec_argv[i++] = "--all-kernel";
1849
1850 for (j = 0; j < argc; j++, i++)
1851 rec_argv[i] = argv[j];
1852
1853 if (verbose > 0) {
1854 pr_debug("calling: ");
1855
1856 j = 0;
1857
1858 while (rec_argv[j]) {
1859 pr_debug("%s ", rec_argv[j]);
1860 j++;
1861 }
1862 pr_debug("\n");
1863 }
1864
1865 ret = cmd_record(i, rec_argv, NULL);
1866 free(rec_argv);
1867 return ret;
1868}
1869
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02001870int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused)
1871{
1872 const struct option c2c_options[] = {
1873 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
1874 OPT_END()
1875 };
1876
1877 argc = parse_options(argc, argv, c2c_options, c2c_usage,
1878 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02001879
1880 if (!argc)
1881 usage_with_options(c2c_usage, c2c_options);
1882
1883 if (!strncmp(argv[0], "rec", 3)) {
1884 return perf_c2c__record(argc, argv);
Jiri Olsa903a6f12016-09-22 17:36:40 +02001885 } else if (!strncmp(argv[0], "rep", 3)) {
1886 return perf_c2c__report(argc, argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02001887 } else {
1888 usage_with_options(c2c_usage, c2c_options);
1889 }
1890
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02001891 return 0;
1892}