blob: c157bd31f2e5a462087e928718e7bfbf7b4cf0bf [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Jiri Olsa465f27a2016-08-26 10:36:12 +02002/*
3 * This is rewrite of original c2c tool introduced in here:
4 * http://lwn.net/Articles/588866/
5 *
6 * The original tool was changed to fit in current perf state.
7 *
8 * Original authors:
9 * Don Zickus <dzickus@redhat.com>
10 * Dick Fowles <fowles@inreach.com>
11 * Joe Mario <jmario@redhat.com>
12 */
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030013#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030014#include <inttypes.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020015#include <linux/compiler.h>
Mamatha Inamdar6ef81c52019-08-22 12:50:49 +053016#include <linux/err.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020017#include <linux/kernel.h>
Jiri Olsacbb88502016-09-22 17:36:48 +020018#include <linux/stringify.h>
Arnaldo Carvalho de Melo7f7c5362019-07-04 11:32:27 -030019#include <linux/zalloc.h>
Jiri Olsa1e181b92016-06-03 15:40:28 +020020#include <asm/bug.h>
Arnaldo Carvalho de Melo391e4202017-04-19 18:51:14 -030021#include <sys/param.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020022#include "debug.h"
23#include "builtin.h"
Arnaldo Carvalho de Melo87ffb6c2019-09-10 16:29:02 +010024#include <perf/cpumap.h>
Arnaldo Carvalho de Melo8520a982019-08-29 16:18:59 -030025#include <subcmd/pager.h>
Jiri Olsa7aef3bf2016-09-22 17:36:38 +020026#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melod3300a32019-08-30 15:09:54 -030027#include "map_symbol.h"
Jiri Olsa39bcd4a2016-09-22 17:36:39 +020028#include "mem-events.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020029#include "session.h"
30#include "hist.h"
Jiri Olsacbb88502016-09-22 17:36:48 +020031#include "sort.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020032#include "tool.h"
Arnaldo Carvalho de Melo12500902019-08-22 16:58:29 -030033#include "cacheline.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020034#include "data.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030035#include "event.h"
Jiri Olsa2709b972016-08-27 11:40:23 +020036#include "evlist.h"
37#include "evsel.h"
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010038#include "ui/browsers/hists.h"
Arnaldo Carvalho de Meloe7ff8922017-04-19 21:34:35 -030039#include "thread.h"
Jiri Olsa7f834c22018-03-09 11:14:40 +010040#include "mem2node.h"
Ian Rogersad3003a2024-05-07 11:35:43 -070041#include "mem-info.h"
Arnaldo Carvalho de Melodaecf9e2019-01-28 00:03:34 +010042#include "symbol.h"
Arnaldo Carvalho de Melo8520a982019-08-29 16:18:59 -030043#include "ui/ui.h"
Arnaldo Carvalho de Melo171f7472019-08-30 11:28:14 -030044#include "ui/progress.h"
Ian Rogers1eaf4962023-05-27 00:22:03 -070045#include "pmus.h"
Wei Liae0f4eb2022-03-25 17:20:32 +080046#include "string2.h"
Ian Rogersf12ad272023-04-10 09:25:10 -070047#include "util/util.h"
Jiri Olsa903a6f12016-09-22 17:36:40 +020048
Jiri Olsac75540e2016-09-22 17:36:41 +020049struct c2c_hists {
50 struct hists hists;
51 struct perf_hpp_list list;
Jiri Olsab2252ae2016-09-22 17:36:46 +020052 struct c2c_stats stats;
Jiri Olsac75540e2016-09-22 17:36:41 +020053};
54
Jiri Olsa92062d52016-06-05 13:40:53 +020055struct compute_stats {
56 struct stats lcl_hitm;
57 struct stats rmt_hitm;
Leo Yan682352e2022-08-11 14:24:44 +080058 struct stats lcl_peer;
59 struct stats rmt_peer;
Jiri Olsa92062d52016-06-05 13:40:53 +020060 struct stats load;
61};
62
Jiri Olsa78b27542016-09-22 17:36:44 +020063struct c2c_hist_entry {
64 struct c2c_hists *hists;
Jiri Olsab2252ae2016-09-22 17:36:46 +020065 struct c2c_stats stats;
Jiri Olsa1e181b92016-06-03 15:40:28 +020066 unsigned long *cpuset;
Jiri Olsa7f834c22018-03-09 11:14:40 +010067 unsigned long *nodeset;
Jiri Olsa1e181b92016-06-03 15:40:28 +020068 struct c2c_stats *node_stats;
Jiri Olsabb342dae2016-07-06 15:40:09 +020069 unsigned int cacheline_idx;
Jiri Olsa92062d52016-06-05 13:40:53 +020070
71 struct compute_stats cstats;
72
Jiri Olsa4c820522018-06-08 02:22:11 +020073 unsigned long paddr;
74 unsigned long paddr_cnt;
75 bool paddr_zero;
76 char *nodestr;
77
Jiri Olsa78b27542016-09-22 17:36:44 +020078 /*
79 * must be at the end,
80 * because of its callchain dynamic entry
81 */
82 struct hist_entry he;
83};
84
Jiri Olsa423701a2018-12-28 11:18:19 +010085static char const *coalesce_default = "iaddr";
Jiri Olsafc9c6302016-05-24 14:14:38 +020086
Jiri Olsa903a6f12016-09-22 17:36:40 +020087struct perf_c2c {
Jiri Olsac75540e2016-09-22 17:36:41 +020088 struct perf_tool tool;
89 struct c2c_hists hists;
Jiri Olsa7f834c22018-03-09 11:14:40 +010090 struct mem2node mem2node;
Jiri Olsa1e181b92016-06-03 15:40:28 +020091
92 unsigned long **nodes;
93 int nodes_cnt;
94 int cpus_cnt;
95 int *cpu2node;
96 int node_info;
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +020097
98 bool show_src;
Jiri Olsaaf09b2d2016-10-11 13:52:05 +020099 bool show_all;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +0100100 bool use_stdio;
Jiri Olsa74c63a22016-05-02 20:01:59 +0200101 bool stats_only;
Jiri Olsa590b6a32016-07-10 16:25:15 +0200102 bool symbol_full;
Kan Liangd80da762020-03-19 13:25:16 -0700103 bool stitch_lbr;
Jiri Olsa7ef2efa2016-07-01 11:12:11 +0200104
Leo Yan18344362021-01-14 23:46:41 +0800105 /* Shared cache line stats */
106 struct c2c_stats shared_clines_stats;
Jiri Olsa7ef2efa2016-07-01 11:12:11 +0200107 int shared_clines;
Jiri Olsa55b95772016-05-29 10:21:45 +0200108
109 int display;
Jiri Olsafc9c6302016-05-24 14:14:38 +0200110
111 const char *coalesce;
112 char *cl_sort;
113 char *cl_resort;
114 char *cl_output;
Jiri Olsa55b95772016-05-29 10:21:45 +0200115};
116
117enum {
Leo Yanc82ccc32022-08-11 14:24:45 +0800118 DISPLAY_LCL_HITM,
119 DISPLAY_RMT_HITM,
120 DISPLAY_TOT_HITM,
Leo Yanf37c5d92022-08-11 14:24:49 +0800121 DISPLAY_SNP_PEER,
Jiri Olsad940bac2016-11-21 22:33:30 +0100122 DISPLAY_MAX,
123};
124
125static const char *display_str[DISPLAY_MAX] = {
Leo Yanfaa30df2022-08-11 14:24:48 +0800126 [DISPLAY_LCL_HITM] = "Local HITMs",
127 [DISPLAY_RMT_HITM] = "Remote HITMs",
128 [DISPLAY_TOT_HITM] = "Total HITMs",
Leo Yanf37c5d92022-08-11 14:24:49 +0800129 [DISPLAY_SNP_PEER] = "Peer Snoop",
Jiri Olsa903a6f12016-09-22 17:36:40 +0200130};
131
Jiri Olsa3a5bfab2016-11-21 22:33:31 +0100132static const struct option c2c_options[] = {
133 OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),
134 OPT_END()
135};
136
Jiri Olsa903a6f12016-09-22 17:36:40 +0200137static struct perf_c2c c2c;
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200138
Jiri Olsa78b27542016-09-22 17:36:44 +0200139static void *c2c_he_zalloc(size_t size)
140{
141 struct c2c_hist_entry *c2c_he;
142
143 c2c_he = zalloc(size + sizeof(*c2c_he));
144 if (!c2c_he)
145 return NULL;
146
Andy Shevchenko7fc5b572021-09-07 19:59:35 -0700147 c2c_he->cpuset = bitmap_zalloc(c2c.cpus_cnt);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200148 if (!c2c_he->cpuset)
Shang XiaoJing4efa8e32022-09-06 11:29:06 +0800149 goto out_free;
Jiri Olsa1e181b92016-06-03 15:40:28 +0200150
Andy Shevchenko7fc5b572021-09-07 19:59:35 -0700151 c2c_he->nodeset = bitmap_zalloc(c2c.nodes_cnt);
Jiri Olsa7f834c22018-03-09 11:14:40 +0100152 if (!c2c_he->nodeset)
Shang XiaoJing4efa8e32022-09-06 11:29:06 +0800153 goto out_free;
Jiri Olsa7f834c22018-03-09 11:14:40 +0100154
Jiri Olsa1e181b92016-06-03 15:40:28 +0200155 c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
156 if (!c2c_he->node_stats)
Shang XiaoJing4efa8e32022-09-06 11:29:06 +0800157 goto out_free;
Jiri Olsa1e181b92016-06-03 15:40:28 +0200158
Jiri Olsa92062d52016-06-05 13:40:53 +0200159 init_stats(&c2c_he->cstats.lcl_hitm);
160 init_stats(&c2c_he->cstats.rmt_hitm);
Leo Yan682352e2022-08-11 14:24:44 +0800161 init_stats(&c2c_he->cstats.lcl_peer);
162 init_stats(&c2c_he->cstats.rmt_peer);
Jiri Olsa92062d52016-06-05 13:40:53 +0200163 init_stats(&c2c_he->cstats.load);
164
Jiri Olsa78b27542016-09-22 17:36:44 +0200165 return &c2c_he->he;
Shang XiaoJing4efa8e32022-09-06 11:29:06 +0800166
167out_free:
Arnaldo Carvalho de Melo190de752023-04-12 09:50:08 -0300168 zfree(&c2c_he->nodeset);
169 zfree(&c2c_he->cpuset);
Shang XiaoJing4efa8e32022-09-06 11:29:06 +0800170 free(c2c_he);
171 return NULL;
Jiri Olsa78b27542016-09-22 17:36:44 +0200172}
173
174static void c2c_he_free(void *he)
175{
176 struct c2c_hist_entry *c2c_he;
177
178 c2c_he = container_of(he, struct c2c_hist_entry, he);
179 if (c2c_he->hists) {
180 hists__delete_entries(&c2c_he->hists->hists);
Arnaldo Carvalho de Melo190de752023-04-12 09:50:08 -0300181 zfree(&c2c_he->hists);
Jiri Olsa78b27542016-09-22 17:36:44 +0200182 }
183
Arnaldo Carvalho de Melo190de752023-04-12 09:50:08 -0300184 zfree(&c2c_he->cpuset);
185 zfree(&c2c_he->nodeset);
186 zfree(&c2c_he->nodestr);
187 zfree(&c2c_he->node_stats);
Jiri Olsa78b27542016-09-22 17:36:44 +0200188 free(c2c_he);
189}
190
191static struct hist_entry_ops c2c_entry_ops = {
192 .new = c2c_he_zalloc,
193 .free = c2c_he_free,
194};
195
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200196static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200197 const char *sort,
198 int nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200199
Jiri Olsab2252ae2016-09-22 17:36:46 +0200200static struct c2c_hists*
201he__get_c2c_hists(struct hist_entry *he,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200202 const char *sort,
203 int nr_header_lines)
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200204{
205 struct c2c_hist_entry *c2c_he;
206 struct c2c_hists *hists;
207 int ret;
208
209 c2c_he = container_of(he, struct c2c_hist_entry, he);
210 if (c2c_he->hists)
Jiri Olsab2252ae2016-09-22 17:36:46 +0200211 return c2c_he->hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200212
213 hists = c2c_he->hists = zalloc(sizeof(*hists));
214 if (!hists)
215 return NULL;
216
Jiri Olsa1d62fcd2016-05-24 10:12:31 +0200217 ret = c2c_hists__init(hists, sort, nr_header_lines);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200218 if (ret) {
219 free(hists);
220 return NULL;
221 }
222
Jiri Olsab2252ae2016-09-22 17:36:46 +0200223 return hists;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200224}
225
Jiri Olsa1e181b92016-06-03 15:40:28 +0200226static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
227 struct perf_sample *sample)
228{
229 if (WARN_ONCE(sample->cpu == (unsigned int) -1,
230 "WARNING: no sample cpu value"))
231 return;
232
Sean Christopherson75d7ba32022-11-19 01:34:46 +0000233 __set_bit(sample->cpu, c2c_he->cpuset);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200234}
235
Jiri Olsa7f834c22018-03-09 11:14:40 +0100236static void c2c_he__set_node(struct c2c_hist_entry *c2c_he,
237 struct perf_sample *sample)
238{
239 int node;
240
241 if (!sample->phys_addr) {
242 c2c_he->paddr_zero = true;
243 return;
244 }
245
246 node = mem2node__node(&c2c.mem2node, sample->phys_addr);
247 if (WARN_ONCE(node < 0, "WARNING: failed to find node\n"))
248 return;
249
Sean Christopherson75d7ba32022-11-19 01:34:46 +0000250 __set_bit(node, c2c_he->nodeset);
Jiri Olsa7f834c22018-03-09 11:14:40 +0100251
252 if (c2c_he->paddr != sample->phys_addr) {
253 c2c_he->paddr_cnt++;
254 c2c_he->paddr = sample->phys_addr;
255 }
256}
257
Jiri Olsa92062d52016-06-05 13:40:53 +0200258static void compute_stats(struct c2c_hist_entry *c2c_he,
259 struct c2c_stats *stats,
260 u64 weight)
261{
262 struct compute_stats *cstats = &c2c_he->cstats;
263
264 if (stats->rmt_hitm)
265 update_stats(&cstats->rmt_hitm, weight);
266 else if (stats->lcl_hitm)
267 update_stats(&cstats->lcl_hitm, weight);
Leo Yan682352e2022-08-11 14:24:44 +0800268 else if (stats->rmt_peer)
269 update_stats(&cstats->rmt_peer, weight);
270 else if (stats->lcl_peer)
271 update_stats(&cstats->lcl_peer, weight);
Jiri Olsa92062d52016-06-05 13:40:53 +0200272 else if (stats->load)
273 update_stats(&cstats->load, weight);
274}
275
Jiri Olsa78b27542016-09-22 17:36:44 +0200276static int process_sample_event(struct perf_tool *tool __maybe_unused,
277 union perf_event *event,
278 struct perf_sample *sample,
Jiri Olsa32dcd022019-07-21 13:23:51 +0200279 struct evsel *evsel,
Jiri Olsa78b27542016-09-22 17:36:44 +0200280 struct machine *machine)
281{
Jiri Olsab2252ae2016-09-22 17:36:46 +0200282 struct c2c_hists *c2c_hists = &c2c.hists;
283 struct c2c_hist_entry *c2c_he;
284 struct c2c_stats stats = { .nr_entries = 0, };
Jiri Olsa78b27542016-09-22 17:36:44 +0200285 struct hist_entry *he;
286 struct addr_location al;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200287 struct mem_info *mi, *mi_dup;
Ian Rogers8ab12a22023-06-08 16:28:21 -0700288 struct callchain_cursor *cursor;
Jiri Olsa78b27542016-09-22 17:36:44 +0200289 int ret;
290
Ian Rogers0dd50412023-06-08 16:28:03 -0700291 addr_location__init(&al);
Jiri Olsa78b27542016-09-22 17:36:44 +0200292 if (machine__resolve(machine, &al, sample) < 0) {
293 pr_debug("problem processing %d event, skipping it.\n",
294 event->header.type);
Ian Rogers0dd50412023-06-08 16:28:03 -0700295 ret = -1;
296 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200297 }
298
Kan Liangd80da762020-03-19 13:25:16 -0700299 if (c2c.stitch_lbr)
Ian Rogersee84a302023-06-08 16:28:00 -0700300 thread__set_lbr_stitch_enable(al.thread, true);
Kan Liangd80da762020-03-19 13:25:16 -0700301
Ian Rogers8ab12a22023-06-08 16:28:21 -0700302 cursor = get_tls_callchain_cursor();
303 ret = sample__resolve_callchain(sample, cursor, NULL,
Jiri Olsadd805762016-05-11 18:23:48 +0200304 evsel, &al, sysctl_perf_event_max_stack);
305 if (ret)
306 goto out;
307
Jiri Olsa78b27542016-09-22 17:36:44 +0200308 mi = sample__resolve_mem(sample, &al);
Ian Rogers0dd50412023-06-08 16:28:03 -0700309 if (mi == NULL) {
310 ret = -ENOMEM;
311 goto out;
312 }
Jiri Olsa78b27542016-09-22 17:36:44 +0200313
Jiri Olsa5cedb412018-03-07 16:50:07 +0100314 /*
315 * The mi object is released in hists__add_entry_ops,
316 * if it gets sorted out into existing data, so we need
317 * to take the copy now.
318 */
319 mi_dup = mem_info__get(mi);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200320
Jiri Olsab2252ae2016-09-22 17:36:46 +0200321 c2c_decode_stats(&stats, mi);
322
323 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Leo Yanebf39d22023-03-15 22:51:05 +0800324 &al, NULL, NULL, mi, NULL,
Jiri Olsa78b27542016-09-22 17:36:44 +0200325 sample, true);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200326 if (he == NULL)
Jiri Olsa5cedb412018-03-07 16:50:07 +0100327 goto free_mi;
Jiri Olsa78b27542016-09-22 17:36:44 +0200328
Jiri Olsab2252ae2016-09-22 17:36:46 +0200329 c2c_he = container_of(he, struct c2c_hist_entry, he);
330 c2c_add_stats(&c2c_he->stats, &stats);
331 c2c_add_stats(&c2c_hists->stats, &stats);
332
Jiri Olsa1e181b92016-06-03 15:40:28 +0200333 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsa7f834c22018-03-09 11:14:40 +0100334 c2c_he__set_node(c2c_he, sample);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200335
Jiri Olsab2252ae2016-09-22 17:36:46 +0200336 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsa78b27542016-09-22 17:36:44 +0200337 ret = hist_entry__append_callchain(he, sample);
338
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200339 if (!ret) {
Jiri Olsa1e181b92016-06-03 15:40:28 +0200340 /*
341 * There's already been warning about missing
342 * sample's cpu value. Let's account all to
343 * node 0 in this case, without any further
344 * warning.
345 *
346 * Doing node stats only for single callchain data.
347 */
348 int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
349 int node = c2c.cpu2node[cpu];
350
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200351 mi = mi_dup;
352
Jiri Olsafc9c6302016-05-24 14:14:38 +0200353 c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200354 if (!c2c_hists)
Jiri Olsa5cedb412018-03-07 16:50:07 +0100355 goto free_mi;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200356
Jiri Olsab2252ae2016-09-22 17:36:46 +0200357 he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
Leo Yanebf39d22023-03-15 22:51:05 +0800358 &al, NULL, NULL, mi, NULL,
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200359 sample, true);
360 if (he == NULL)
Jiri Olsa5cedb412018-03-07 16:50:07 +0100361 goto free_mi;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200362
Jiri Olsab2252ae2016-09-22 17:36:46 +0200363 c2c_he = container_of(he, struct c2c_hist_entry, he);
364 c2c_add_stats(&c2c_he->stats, &stats);
365 c2c_add_stats(&c2c_hists->stats, &stats);
Jiri Olsa1e181b92016-06-03 15:40:28 +0200366 c2c_add_stats(&c2c_he->node_stats[node], &stats);
367
Jiri Olsa92062d52016-06-05 13:40:53 +0200368 compute_stats(c2c_he, &stats, sample->weight);
369
Jiri Olsa1e181b92016-06-03 15:40:28 +0200370 c2c_he__set_cpu(c2c_he, sample);
Jiri Olsa7f834c22018-03-09 11:14:40 +0100371 c2c_he__set_node(c2c_he, sample);
Jiri Olsab2252ae2016-09-22 17:36:46 +0200372
373 hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200374 ret = hist_entry__append_callchain(he, sample);
375 }
376
377out:
Ian Rogers0dd50412023-06-08 16:28:03 -0700378 addr_location__exit(&al);
Jiri Olsa78b27542016-09-22 17:36:44 +0200379 return ret;
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200380
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200381free_mi:
Jiri Olsa5cedb412018-03-07 16:50:07 +0100382 mem_info__put(mi_dup);
383 mem_info__put(mi);
Jiri Olsaec06f9b2016-09-22 17:36:45 +0200384 ret = -ENOMEM;
385 goto out;
Jiri Olsa78b27542016-09-22 17:36:44 +0200386}
387
388static struct perf_c2c c2c = {
389 .tool = {
390 .sample = process_sample_event,
391 .mmap = perf_event__process_mmap,
392 .mmap2 = perf_event__process_mmap2,
393 .comm = perf_event__process_comm,
394 .exit = perf_event__process_exit,
395 .fork = perf_event__process_fork,
396 .lost = perf_event__process_lost,
Leo Yanc825f782020-11-06 17:48:52 +0800397 .attr = perf_event__process_attr,
398 .auxtrace_info = perf_event__process_auxtrace_info,
399 .auxtrace = perf_event__process_auxtrace,
400 .auxtrace_error = perf_event__process_auxtrace_error,
Jiri Olsa78b27542016-09-22 17:36:44 +0200401 .ordered_events = true,
402 .ordering_requires_timestamps = true,
403 },
404};
405
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200406static const char * const c2c_usage[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +0200407 "perf c2c {record|report}",
Jiri Olsa7aef3bf2016-09-22 17:36:38 +0200408 NULL
409};
410
Jiri Olsa903a6f12016-09-22 17:36:40 +0200411static const char * const __usage_report[] = {
412 "perf c2c report",
413 NULL
414};
415
416static const char * const *report_c2c_usage = __usage_report;
417
Jiri Olsac75540e2016-09-22 17:36:41 +0200418#define C2C_HEADER_MAX 2
419
420struct c2c_header {
421 struct {
422 const char *text;
423 int span;
424 } line[C2C_HEADER_MAX];
425};
426
427struct c2c_dimension {
428 struct c2c_header header;
429 const char *name;
430 int width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200431 struct sort_entry *se;
Jiri Olsac75540e2016-09-22 17:36:41 +0200432
433 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
434 struct hist_entry *, struct hist_entry *);
435 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
436 struct hist_entry *he);
437 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
438 struct hist_entry *he);
439};
440
441struct c2c_fmt {
442 struct perf_hpp_fmt fmt;
443 struct c2c_dimension *dim;
444};
445
Jiri Olsa590b6a32016-07-10 16:25:15 +0200446#define SYMBOL_WIDTH 30
447
448static struct c2c_dimension dim_symbol;
449static struct c2c_dimension dim_srcline;
450
451static int symbol_width(struct hists *hists, struct sort_entry *se)
452{
453 int width = hists__col_len(hists, se->se_width_idx);
454
455 if (!c2c.symbol_full)
456 width = MIN(width, SYMBOL_WIDTH);
457
458 return width;
459}
460
Jiri Olsac75540e2016-09-22 17:36:41 +0200461static int c2c_width(struct perf_hpp_fmt *fmt,
462 struct perf_hpp *hpp __maybe_unused,
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -0300463 struct hists *hists)
Jiri Olsac75540e2016-09-22 17:36:41 +0200464{
465 struct c2c_fmt *c2c_fmt;
Jiri Olsac75540e2016-09-22 17:36:41 +0200466 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +0200467
468 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
469 dim = c2c_fmt->dim;
470
Jiri Olsa590b6a32016-07-10 16:25:15 +0200471 if (dim == &dim_symbol || dim == &dim_srcline)
472 return symbol_width(hists, dim->se);
473
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200474 return dim->se ? hists__col_len(hists, dim->se->se_width_idx) :
475 c2c_fmt->dim->width;
476}
477
478static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
479 struct hists *hists, int line, int *span)
480{
481 struct perf_hpp_list *hpp_list = hists->hpp_list;
482 struct c2c_fmt *c2c_fmt;
483 struct c2c_dimension *dim;
484 const char *text = NULL;
485 int width = c2c_width(fmt, hpp, hists);
486
487 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
488 dim = c2c_fmt->dim;
489
490 if (dim->se) {
491 text = dim->header.line[line].text;
492 /* Use the last line from sort_entry if not defined. */
493 if (!text && (line == hpp_list->nr_header_lines - 1))
494 text = dim->se->se_header;
495 } else {
496 text = dim->header.line[line].text;
497
498 if (*span) {
499 (*span)--;
500 return 0;
501 } else {
502 *span = dim->header.line[line].span;
503 }
504 }
505
Jiri Olsac75540e2016-09-22 17:36:41 +0200506 if (text == NULL)
507 text = "";
508
Jiri Olsa8d3f9382016-09-22 17:36:42 +0200509 return scnprintf(hpp->buf, hpp->size, "%*s", width, text);
Jiri Olsac75540e2016-09-22 17:36:41 +0200510}
511
Jiri Olsacbb88502016-09-22 17:36:48 +0200512#define HEX_STR(__s, __v) \
513({ \
514 scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \
515 __s; \
516})
517
518static int64_t
519dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
520 struct hist_entry *left, struct hist_entry *right)
521{
522 return sort__dcacheline_cmp(left, right);
523}
524
525static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
526 struct hist_entry *he)
527{
528 uint64_t addr = 0;
529 int width = c2c_width(fmt, hpp, he->hists);
530 char buf[20];
531
532 if (he->mem_info)
Ian Rogers1a8c2e02024-05-07 11:35:44 -0700533 addr = cl_address(mem_info__daddr(he->mem_info)->addr, chk_double_cl);
Jiri Olsacbb88502016-09-22 17:36:48 +0200534
535 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
536}
537
Jiri Olsa7f834c22018-03-09 11:14:40 +0100538static int
539dcacheline_node_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
540 struct hist_entry *he)
541{
542 struct c2c_hist_entry *c2c_he;
543 int width = c2c_width(fmt, hpp, he->hists);
544
545 c2c_he = container_of(he, struct c2c_hist_entry, he);
546 if (WARN_ON_ONCE(!c2c_he->nodestr))
547 return 0;
548
549 return scnprintf(hpp->buf, hpp->size, "%*s", width, c2c_he->nodestr);
550}
551
Jiri Olsa03d9fcb2018-03-09 11:14:42 +0100552static int
553dcacheline_node_count(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
554 struct hist_entry *he)
555{
556 struct c2c_hist_entry *c2c_he;
557 int width = c2c_width(fmt, hpp, he->hists);
558
559 c2c_he = container_of(he, struct c2c_hist_entry, he);
560 return scnprintf(hpp->buf, hpp->size, "%*lu", width, c2c_he->paddr_cnt);
561}
562
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200563static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
564 struct hist_entry *he)
565{
566 uint64_t addr = 0;
567 int width = c2c_width(fmt, hpp, he->hists);
568 char buf[20];
569
570 if (he->mem_info)
Ian Rogers1a8c2e02024-05-07 11:35:44 -0700571 addr = cl_offset(mem_info__daddr(he->mem_info)->al_addr, chk_double_cl);
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200572
573 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
574}
575
576static int64_t
577offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
578 struct hist_entry *left, struct hist_entry *right)
579{
580 uint64_t l = 0, r = 0;
581
582 if (left->mem_info)
Ian Rogers1a8c2e02024-05-07 11:35:44 -0700583 l = cl_offset(mem_info__daddr(left->mem_info)->addr, chk_double_cl);
Feng Tang1470a102023-02-14 15:58:23 +0800584
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200585 if (right->mem_info)
Ian Rogers1a8c2e02024-05-07 11:35:44 -0700586 r = cl_offset(mem_info__daddr(right->mem_info)->addr, chk_double_cl);
Jiri Olsa48acdeb2016-04-29 14:37:06 +0200587
588 return (int64_t)(r - l);
589}
590
Jiri Olsa43575a92016-05-03 21:48:56 +0200591static int
592iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
593 struct hist_entry *he)
594{
595 uint64_t addr = 0;
596 int width = c2c_width(fmt, hpp, he->hists);
597 char buf[20];
598
599 if (he->mem_info)
Ian Rogers1a8c2e02024-05-07 11:35:44 -0700600 addr = mem_info__iaddr(he->mem_info)->addr;
Jiri Olsa43575a92016-05-03 21:48:56 +0200601
602 return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
603}
604
605static int64_t
606iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
607 struct hist_entry *left, struct hist_entry *right)
608{
609 return sort__iaddr_cmp(left, right);
610}
611
Jiri Olsa97cb4862016-05-23 16:20:14 +0200612static int
613tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
614 struct hist_entry *he)
615{
616 struct c2c_hist_entry *c2c_he;
617 int width = c2c_width(fmt, hpp, he->hists);
618 unsigned int tot_hitm;
619
620 c2c_he = container_of(he, struct c2c_hist_entry, he);
621 tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm;
622
623 return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm);
624}
625
626static int64_t
627tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
628 struct hist_entry *left, struct hist_entry *right)
629{
630 struct c2c_hist_entry *c2c_left;
631 struct c2c_hist_entry *c2c_right;
Andres Freundc1c80132020-01-08 20:30:30 -0800632 uint64_t tot_hitm_left;
633 uint64_t tot_hitm_right;
Jiri Olsa97cb4862016-05-23 16:20:14 +0200634
635 c2c_left = container_of(left, struct c2c_hist_entry, he);
636 c2c_right = container_of(right, struct c2c_hist_entry, he);
637
638 tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm;
639 tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm;
640
641 return tot_hitm_left - tot_hitm_right;
642}
643
644#define STAT_FN_ENTRY(__f) \
645static int \
646__f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \
647 struct hist_entry *he) \
648{ \
649 struct c2c_hist_entry *c2c_he; \
650 int width = c2c_width(fmt, hpp, he->hists); \
651 \
652 c2c_he = container_of(he, struct c2c_hist_entry, he); \
653 return scnprintf(hpp->buf, hpp->size, "%*u", width, \
654 c2c_he->stats.__f); \
655}
656
657#define STAT_FN_CMP(__f) \
658static int64_t \
659__f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \
660 struct hist_entry *left, struct hist_entry *right) \
661{ \
662 struct c2c_hist_entry *c2c_left, *c2c_right; \
663 \
664 c2c_left = container_of(left, struct c2c_hist_entry, he); \
665 c2c_right = container_of(right, struct c2c_hist_entry, he); \
Andres Freundc1c80132020-01-08 20:30:30 -0800666 return (uint64_t) c2c_left->stats.__f - \
667 (uint64_t) c2c_right->stats.__f; \
Jiri Olsa97cb4862016-05-23 16:20:14 +0200668}
669
670#define STAT_FN(__f) \
671 STAT_FN_ENTRY(__f) \
672 STAT_FN_CMP(__f)
673
674STAT_FN(rmt_hitm)
675STAT_FN(lcl_hitm)
Leo Yan63e74ab2022-08-11 14:24:42 +0800676STAT_FN(rmt_peer)
677STAT_FN(lcl_peer)
678STAT_FN(tot_peer)
Jiri Olsa0f188962016-05-04 10:10:11 +0200679STAT_FN(store)
680STAT_FN(st_l1hit)
681STAT_FN(st_l1miss)
Leo Yan550b4d62022-05-18 13:57:20 +0800682STAT_FN(st_na)
Jiri Olsa1295f682016-05-04 10:18:24 +0200683STAT_FN(ld_fbhit)
684STAT_FN(ld_l1hit)
685STAT_FN(ld_l2hit)
Jiri Olsa4d089102016-05-04 10:27:51 +0200686STAT_FN(ld_llchit)
687STAT_FN(rmt_hit)
Jiri Olsa97cb4862016-05-23 16:20:14 +0200688
Shang XiaoJingcf874a02022-09-06 11:29:05 +0800689static uint64_t get_load_llc_misses(struct c2c_stats *stats)
690{
691 return stats->lcl_dram +
692 stats->rmt_dram +
693 stats->rmt_hitm +
694 stats->rmt_hit;
695}
696
697static uint64_t get_load_cache_hits(struct c2c_stats *stats)
698{
699 return stats->ld_fbhit +
700 stats->ld_l1hit +
701 stats->ld_l2hit +
702 stats->ld_llchit +
703 stats->lcl_hitm;
704}
705
706static uint64_t get_stores(struct c2c_stats *stats)
707{
708 return stats->st_l1hit +
709 stats->st_l1miss +
710 stats->st_na;
711}
712
Jiri Olsa01b84d72016-05-04 10:35:29 +0200713static uint64_t total_records(struct c2c_stats *stats)
714{
Shang XiaoJingcf874a02022-09-06 11:29:05 +0800715 return get_load_llc_misses(stats) +
716 get_load_cache_hits(stats) +
717 get_stores(stats);
Jiri Olsa01b84d72016-05-04 10:35:29 +0200718}
719
720static int
721tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
722 struct hist_entry *he)
723{
724 struct c2c_hist_entry *c2c_he;
725 int width = c2c_width(fmt, hpp, he->hists);
726 uint64_t tot_recs;
727
728 c2c_he = container_of(he, struct c2c_hist_entry, he);
729 tot_recs = total_records(&c2c_he->stats);
730
731 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
732}
733
734static int64_t
735tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
736 struct hist_entry *left, struct hist_entry *right)
737{
738 struct c2c_hist_entry *c2c_left;
739 struct c2c_hist_entry *c2c_right;
740 uint64_t tot_recs_left;
741 uint64_t tot_recs_right;
742
743 c2c_left = container_of(left, struct c2c_hist_entry, he);
744 c2c_right = container_of(right, struct c2c_hist_entry, he);
745
746 tot_recs_left = total_records(&c2c_left->stats);
747 tot_recs_right = total_records(&c2c_right->stats);
748
749 return tot_recs_left - tot_recs_right;
750}
751
Jiri Olsa55177c42016-05-19 09:52:37 +0200752static uint64_t total_loads(struct c2c_stats *stats)
753{
Shang XiaoJingcf874a02022-09-06 11:29:05 +0800754 return get_load_llc_misses(stats) +
755 get_load_cache_hits(stats);
Jiri Olsa55177c42016-05-19 09:52:37 +0200756}
757
758static int
759tot_loads_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
760 struct hist_entry *he)
761{
762 struct c2c_hist_entry *c2c_he;
763 int width = c2c_width(fmt, hpp, he->hists);
764 uint64_t tot_recs;
765
766 c2c_he = container_of(he, struct c2c_hist_entry, he);
767 tot_recs = total_loads(&c2c_he->stats);
768
769 return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs);
770}
771
772static int64_t
773tot_loads_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
774 struct hist_entry *left, struct hist_entry *right)
775{
776 struct c2c_hist_entry *c2c_left;
777 struct c2c_hist_entry *c2c_right;
778 uint64_t tot_recs_left;
779 uint64_t tot_recs_right;
780
781 c2c_left = container_of(left, struct c2c_hist_entry, he);
782 c2c_right = container_of(right, struct c2c_hist_entry, he);
783
784 tot_recs_left = total_loads(&c2c_left->stats);
785 tot_recs_right = total_loads(&c2c_right->stats);
786
787 return tot_recs_left - tot_recs_right;
788}
789
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200790typedef double (get_percent_cb)(struct c2c_hist_entry *);
791
792static int
793percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
794 struct hist_entry *he, get_percent_cb get_percent)
795{
796 struct c2c_hist_entry *c2c_he;
797 int width = c2c_width(fmt, hpp, he->hists);
798 double per;
799
800 c2c_he = container_of(he, struct c2c_hist_entry, he);
801 per = get_percent(c2c_he);
802
Jiri Olsa5a1a99c2016-01-06 16:59:02 +0100803#ifdef HAVE_SLANG_SUPPORT
804 if (use_browser)
805 return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per);
806#endif
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200807 return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per);
808}
809
Leo Yan2be0bc72022-08-11 14:24:46 +0800810static double percent_costly_snoop(struct c2c_hist_entry *c2c_he)
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200811{
812 struct c2c_hists *hists;
813 struct c2c_stats *stats;
814 struct c2c_stats *total;
Jiri Olsa55b95772016-05-29 10:21:45 +0200815 int tot = 0, st = 0;
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200816 double p;
817
818 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
819 stats = &c2c_he->stats;
820 total = &hists->stats;
821
Jiri Olsa55b95772016-05-29 10:21:45 +0200822 switch (c2c.display) {
Leo Yanc82ccc32022-08-11 14:24:45 +0800823 case DISPLAY_RMT_HITM:
Jiri Olsa55b95772016-05-29 10:21:45 +0200824 st = stats->rmt_hitm;
825 tot = total->rmt_hitm;
826 break;
Leo Yanc82ccc32022-08-11 14:24:45 +0800827 case DISPLAY_LCL_HITM:
Jiri Olsa55b95772016-05-29 10:21:45 +0200828 st = stats->lcl_hitm;
829 tot = total->lcl_hitm;
Jiri Olsad940bac2016-11-21 22:33:30 +0100830 break;
Leo Yanc82ccc32022-08-11 14:24:45 +0800831 case DISPLAY_TOT_HITM:
Jiri Olsad940bac2016-11-21 22:33:30 +0100832 st = stats->tot_hitm;
833 tot = total->tot_hitm;
Leo Yanf37c5d92022-08-11 14:24:49 +0800834 break;
835 case DISPLAY_SNP_PEER:
836 st = stats->tot_peer;
837 tot = total->tot_peer;
838 break;
Jiri Olsa55b95772016-05-29 10:21:45 +0200839 default:
840 break;
841 }
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200842
843 p = tot ? (double) st / tot : 0;
844
845 return 100 * p;
846}
847
848#define PERC_STR(__s, __v) \
849({ \
850 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \
851 __s; \
852})
853
854static int
Leo Yan2be0bc72022-08-11 14:24:46 +0800855percent_costly_snoop_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
856 struct hist_entry *he)
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200857{
858 struct c2c_hist_entry *c2c_he;
859 int width = c2c_width(fmt, hpp, he->hists);
860 char buf[10];
861 double per;
862
863 c2c_he = container_of(he, struct c2c_hist_entry, he);
Leo Yan2be0bc72022-08-11 14:24:46 +0800864 per = percent_costly_snoop(c2c_he);
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200865 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
866}
867
868static int
Leo Yan2be0bc72022-08-11 14:24:46 +0800869percent_costly_snoop_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
870 struct hist_entry *he)
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200871{
Leo Yan2be0bc72022-08-11 14:24:46 +0800872 return percent_color(fmt, hpp, he, percent_costly_snoop);
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200873}
874
875static int64_t
Leo Yan2be0bc72022-08-11 14:24:46 +0800876percent_costly_snoop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
877 struct hist_entry *left, struct hist_entry *right)
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200878{
879 struct c2c_hist_entry *c2c_left;
880 struct c2c_hist_entry *c2c_right;
881 double per_left;
882 double per_right;
883
884 c2c_left = container_of(left, struct c2c_hist_entry, he);
885 c2c_right = container_of(right, struct c2c_hist_entry, he);
886
Leo Yan2be0bc72022-08-11 14:24:46 +0800887 per_left = percent_costly_snoop(c2c_left);
888 per_right = percent_costly_snoop(c2c_right);
Jiri Olsaf0c50c12016-05-04 10:50:09 +0200889
890 return per_left - per_right;
891}
892
Jiri Olsa9cb35002016-05-04 12:16:50 +0200893static struct c2c_stats *he_stats(struct hist_entry *he)
894{
895 struct c2c_hist_entry *c2c_he;
896
897 c2c_he = container_of(he, struct c2c_hist_entry, he);
898 return &c2c_he->stats;
899}
900
901static struct c2c_stats *total_stats(struct hist_entry *he)
902{
903 struct c2c_hists *hists;
904
905 hists = container_of(he->hists, struct c2c_hists, hists);
906 return &hists->stats;
907}
908
Leo Yan111c1412021-01-14 23:46:44 +0800909static double percent(u32 st, u32 tot)
Jiri Olsa9cb35002016-05-04 12:16:50 +0200910{
911 return tot ? 100. * (double) st / (double) tot : 0;
912}
913
914#define PERCENT(__h, __f) percent(he_stats(__h)->__f, total_stats(__h)->__f)
915
916#define PERCENT_FN(__f) \
917static double percent_ ## __f(struct c2c_hist_entry *c2c_he) \
918{ \
919 struct c2c_hists *hists; \
920 \
921 hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); \
922 return percent(c2c_he->stats.__f, hists->stats.__f); \
923}
924
925PERCENT_FN(rmt_hitm)
926PERCENT_FN(lcl_hitm)
Leo Yan90822822022-08-11 14:24:43 +0800927PERCENT_FN(rmt_peer)
928PERCENT_FN(lcl_peer)
Jiri Olsa9cb35002016-05-04 12:16:50 +0200929PERCENT_FN(st_l1hit)
930PERCENT_FN(st_l1miss)
Leo Yan550b4d62022-05-18 13:57:20 +0800931PERCENT_FN(st_na)
Jiri Olsa9cb35002016-05-04 12:16:50 +0200932
933static int
934percent_rmt_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
935 struct hist_entry *he)
936{
937 int width = c2c_width(fmt, hpp, he->hists);
938 double per = PERCENT(he, rmt_hitm);
939 char buf[10];
940
941 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
942}
943
944static int
945percent_rmt_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
946 struct hist_entry *he)
947{
948 return percent_color(fmt, hpp, he, percent_rmt_hitm);
949}
950
951static int64_t
952percent_rmt_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
953 struct hist_entry *left, struct hist_entry *right)
954{
955 double per_left;
956 double per_right;
957
Leo Yanb24192a2022-05-30 16:42:53 +0800958 per_left = PERCENT(left, rmt_hitm);
959 per_right = PERCENT(right, rmt_hitm);
Jiri Olsa9cb35002016-05-04 12:16:50 +0200960
961 return per_left - per_right;
962}
963
964static int
965percent_lcl_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
966 struct hist_entry *he)
967{
968 int width = c2c_width(fmt, hpp, he->hists);
969 double per = PERCENT(he, lcl_hitm);
970 char buf[10];
971
972 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
973}
974
975static int
976percent_lcl_hitm_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
977 struct hist_entry *he)
978{
979 return percent_color(fmt, hpp, he, percent_lcl_hitm);
980}
981
982static int64_t
983percent_lcl_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
984 struct hist_entry *left, struct hist_entry *right)
985{
986 double per_left;
987 double per_right;
988
989 per_left = PERCENT(left, lcl_hitm);
990 per_right = PERCENT(right, lcl_hitm);
991
992 return per_left - per_right;
993}
994
995static int
Leo Yan90822822022-08-11 14:24:43 +0800996percent_lcl_peer_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
997 struct hist_entry *he)
998{
999 int width = c2c_width(fmt, hpp, he->hists);
1000 double per = PERCENT(he, lcl_peer);
1001 char buf[10];
1002
1003 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1004}
1005
1006static int
1007percent_lcl_peer_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1008 struct hist_entry *he)
1009{
1010 return percent_color(fmt, hpp, he, percent_lcl_peer);
1011}
1012
1013static int64_t
1014percent_lcl_peer_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1015 struct hist_entry *left, struct hist_entry *right)
1016{
1017 double per_left;
1018 double per_right;
1019
1020 per_left = PERCENT(left, lcl_peer);
1021 per_right = PERCENT(right, lcl_peer);
1022
1023 return per_left - per_right;
1024}
1025
1026static int
1027percent_rmt_peer_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1028 struct hist_entry *he)
1029{
1030 int width = c2c_width(fmt, hpp, he->hists);
1031 double per = PERCENT(he, rmt_peer);
1032 char buf[10];
1033
1034 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1035}
1036
1037static int
1038percent_rmt_peer_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1039 struct hist_entry *he)
1040{
1041 return percent_color(fmt, hpp, he, percent_rmt_peer);
1042}
1043
1044static int64_t
1045percent_rmt_peer_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1046 struct hist_entry *left, struct hist_entry *right)
1047{
1048 double per_left;
1049 double per_right;
1050
1051 per_left = PERCENT(left, rmt_peer);
1052 per_right = PERCENT(right, rmt_peer);
1053
1054 return per_left - per_right;
1055}
1056
1057static int
Jiri Olsa9cb35002016-05-04 12:16:50 +02001058percent_stores_l1hit_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1059 struct hist_entry *he)
1060{
1061 int width = c2c_width(fmt, hpp, he->hists);
1062 double per = PERCENT(he, st_l1hit);
1063 char buf[10];
1064
1065 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1066}
1067
1068static int
1069percent_stores_l1hit_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1070 struct hist_entry *he)
1071{
1072 return percent_color(fmt, hpp, he, percent_st_l1hit);
1073}
1074
1075static int64_t
1076percent_stores_l1hit_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1077 struct hist_entry *left, struct hist_entry *right)
1078{
1079 double per_left;
1080 double per_right;
1081
1082 per_left = PERCENT(left, st_l1hit);
1083 per_right = PERCENT(right, st_l1hit);
1084
1085 return per_left - per_right;
1086}
1087
1088static int
1089percent_stores_l1miss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1090 struct hist_entry *he)
1091{
1092 int width = c2c_width(fmt, hpp, he->hists);
1093 double per = PERCENT(he, st_l1miss);
1094 char buf[10];
1095
1096 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1097}
1098
1099static int
1100percent_stores_l1miss_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1101 struct hist_entry *he)
1102{
1103 return percent_color(fmt, hpp, he, percent_st_l1miss);
1104}
1105
1106static int64_t
1107percent_stores_l1miss_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1108 struct hist_entry *left, struct hist_entry *right)
1109{
1110 double per_left;
1111 double per_right;
1112
1113 per_left = PERCENT(left, st_l1miss);
1114 per_right = PERCENT(right, st_l1miss);
1115
1116 return per_left - per_right;
1117}
1118
Leo Yan550b4d62022-05-18 13:57:20 +08001119static int
1120percent_stores_na_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1121 struct hist_entry *he)
1122{
1123 int width = c2c_width(fmt, hpp, he->hists);
1124 double per = PERCENT(he, st_na);
1125 char buf[10];
1126
1127 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));
1128}
1129
1130static int
1131percent_stores_na_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1132 struct hist_entry *he)
1133{
1134 return percent_color(fmt, hpp, he, percent_st_na);
1135}
1136
1137static int64_t
1138percent_stores_na_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1139 struct hist_entry *left, struct hist_entry *right)
1140{
1141 double per_left;
1142 double per_right;
1143
1144 per_left = PERCENT(left, st_na);
1145 per_right = PERCENT(right, st_na);
1146
1147 return per_left - per_right;
1148}
1149
Jiri Olsa6c70f542016-05-28 12:30:13 +02001150STAT_FN(lcl_dram)
1151STAT_FN(rmt_dram)
1152
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001153static int
1154pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1155 struct hist_entry *he)
1156{
1157 int width = c2c_width(fmt, hpp, he->hists);
1158
Ian Rogersee84a302023-06-08 16:28:00 -07001159 return scnprintf(hpp->buf, hpp->size, "%*d", width, thread__pid(he->thread));
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001160}
1161
1162static int64_t
1163pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1164 struct hist_entry *left, struct hist_entry *right)
1165{
Ian Rogersee84a302023-06-08 16:28:00 -07001166 return thread__pid(left->thread) - thread__pid(right->thread);
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001167}
1168
Jiri Olsa1e181b92016-06-03 15:40:28 +02001169static int64_t
1170empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
1171 struct hist_entry *left __maybe_unused,
1172 struct hist_entry *right __maybe_unused)
1173{
1174 return 0;
1175}
1176
Leo Yanf3d0a552021-01-14 23:46:45 +08001177static int display_metrics(struct perf_hpp *hpp, u32 val, u32 sum)
1178{
1179 int ret;
1180
1181 if (sum != 0)
1182 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ",
1183 percent(val, sum));
1184 else
1185 ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a");
1186
1187 return ret;
1188}
1189
Jiri Olsa1e181b92016-06-03 15:40:28 +02001190static int
1191node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1192 struct hist_entry *he)
1193{
1194 struct c2c_hist_entry *c2c_he;
1195 bool first = true;
1196 int node;
1197 int ret = 0;
1198
1199 c2c_he = container_of(he, struct c2c_hist_entry, he);
1200
1201 for (node = 0; node < c2c.nodes_cnt; node++) {
1202 DECLARE_BITMAP(set, c2c.cpus_cnt);
1203
1204 bitmap_zero(set, c2c.cpus_cnt);
1205 bitmap_and(set, c2c_he->cpuset, c2c.nodes[node], c2c.cpus_cnt);
1206
Yury Norov1006c5c2022-01-23 10:38:43 -08001207 if (bitmap_empty(set, c2c.cpus_cnt)) {
Jiri Olsa1e181b92016-06-03 15:40:28 +02001208 if (c2c.node_info == 1) {
1209 ret = scnprintf(hpp->buf, hpp->size, "%21s", " ");
1210 advance_hpp(hpp, ret);
1211 }
1212 continue;
1213 }
1214
1215 if (!first) {
1216 ret = scnprintf(hpp->buf, hpp->size, " ");
1217 advance_hpp(hpp, ret);
1218 }
1219
1220 switch (c2c.node_info) {
1221 case 0:
1222 ret = scnprintf(hpp->buf, hpp->size, "%2d", node);
1223 advance_hpp(hpp, ret);
1224 break;
1225 case 1:
1226 {
Jiri Olsa67260e82019-08-20 16:02:19 +02001227 int num = bitmap_weight(set, c2c.cpus_cnt);
Jiri Olsa1e181b92016-06-03 15:40:28 +02001228 struct c2c_stats *stats = &c2c_he->node_stats[node];
1229
1230 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
1231 advance_hpp(hpp, ret);
1232
Jiri Olsa55b95772016-05-29 10:21:45 +02001233 switch (c2c.display) {
Leo Yanc82ccc32022-08-11 14:24:45 +08001234 case DISPLAY_RMT_HITM:
Leo Yanf3d0a552021-01-14 23:46:45 +08001235 ret = display_metrics(hpp, stats->rmt_hitm,
1236 c2c_he->stats.rmt_hitm);
Jiri Olsa55b95772016-05-29 10:21:45 +02001237 break;
Leo Yanc82ccc32022-08-11 14:24:45 +08001238 case DISPLAY_LCL_HITM:
Leo Yanf3d0a552021-01-14 23:46:45 +08001239 ret = display_metrics(hpp, stats->lcl_hitm,
1240 c2c_he->stats.lcl_hitm);
Jiri Olsad940bac2016-11-21 22:33:30 +01001241 break;
Leo Yanc82ccc32022-08-11 14:24:45 +08001242 case DISPLAY_TOT_HITM:
Leo Yanf3d0a552021-01-14 23:46:45 +08001243 ret = display_metrics(hpp, stats->tot_hitm,
1244 c2c_he->stats.tot_hitm);
1245 break;
Leo Yanf37c5d92022-08-11 14:24:49 +08001246 case DISPLAY_SNP_PEER:
1247 ret = display_metrics(hpp, stats->tot_peer,
1248 c2c_he->stats.tot_peer);
1249 break;
Jiri Olsa55b95772016-05-29 10:21:45 +02001250 default:
1251 break;
1252 }
1253
Jiri Olsa1e181b92016-06-03 15:40:28 +02001254 advance_hpp(hpp, ret);
1255
1256 if (c2c_he->stats.store > 0) {
1257 ret = scnprintf(hpp->buf, hpp->size, "%5.1f%%}",
1258 percent(stats->store, c2c_he->stats.store));
1259 } else {
1260 ret = scnprintf(hpp->buf, hpp->size, "%6s}", "n/a");
1261 }
1262
1263 advance_hpp(hpp, ret);
1264 break;
1265 }
1266 case 2:
1267 ret = scnprintf(hpp->buf, hpp->size, "%2d{", node);
1268 advance_hpp(hpp, ret);
1269
1270 ret = bitmap_scnprintf(set, c2c.cpus_cnt, hpp->buf, hpp->size);
1271 advance_hpp(hpp, ret);
1272
1273 ret = scnprintf(hpp->buf, hpp->size, "}");
1274 advance_hpp(hpp, ret);
1275 break;
1276 default:
1277 break;
1278 }
1279
1280 first = false;
1281 }
1282
1283 return 0;
1284}
1285
Jiri Olsa92062d52016-06-05 13:40:53 +02001286static int
1287mean_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1288 struct hist_entry *he, double mean)
1289{
1290 int width = c2c_width(fmt, hpp, he->hists);
1291 char buf[10];
1292
1293 scnprintf(buf, 10, "%6.0f", mean);
1294 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1295}
1296
1297#define MEAN_ENTRY(__func, __val) \
1298static int \
1299__func(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) \
1300{ \
1301 struct c2c_hist_entry *c2c_he; \
1302 c2c_he = container_of(he, struct c2c_hist_entry, he); \
1303 return mean_entry(fmt, hpp, he, avg_stats(&c2c_he->cstats.__val)); \
1304}
1305
1306MEAN_ENTRY(mean_rmt_entry, rmt_hitm);
1307MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1308MEAN_ENTRY(mean_load_entry, load);
Leo Yan682352e2022-08-11 14:24:44 +08001309MEAN_ENTRY(mean_rmt_peer_entry, rmt_peer);
1310MEAN_ENTRY(mean_lcl_peer_entry, lcl_peer);
Jiri Olsa92062d52016-06-05 13:40:53 +02001311
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001312static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001313cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001314 struct hist_entry *he)
1315{
1316 struct c2c_hist_entry *c2c_he;
1317 int width = c2c_width(fmt, hpp, he->hists);
1318 char buf[10];
1319
1320 c2c_he = container_of(he, struct c2c_hist_entry, he);
1321
1322 scnprintf(buf, 10, "%d", bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt));
1323 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1324}
1325
Jiri Olsabb342dae2016-07-06 15:40:09 +02001326static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001327cl_idx_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsabb342dae2016-07-06 15:40:09 +02001328 struct hist_entry *he)
1329{
1330 struct c2c_hist_entry *c2c_he;
1331 int width = c2c_width(fmt, hpp, he->hists);
1332 char buf[10];
1333
1334 c2c_he = container_of(he, struct c2c_hist_entry, he);
1335
1336 scnprintf(buf, 10, "%u", c2c_he->cacheline_idx);
1337 return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1338}
1339
1340static int
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03001341cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
Jiri Olsabb342dae2016-07-06 15:40:09 +02001342 struct hist_entry *he)
1343{
1344 int width = c2c_width(fmt, hpp, he->hists);
1345
1346 return scnprintf(hpp->buf, hpp->size, "%*s", width, "");
1347}
1348
Jiri Olsa600a8cf2016-09-22 17:36:47 +02001349#define HEADER_LOW(__h) \
1350 { \
1351 .line[1] = { \
1352 .text = __h, \
1353 }, \
1354 }
1355
1356#define HEADER_BOTH(__h0, __h1) \
1357 { \
1358 .line[0] = { \
1359 .text = __h0, \
1360 }, \
1361 .line[1] = { \
1362 .text = __h1, \
1363 }, \
1364 }
1365
1366#define HEADER_SPAN(__h0, __h1, __s) \
1367 { \
1368 .line[0] = { \
1369 .text = __h0, \
1370 .span = __s, \
1371 }, \
1372 .line[1] = { \
1373 .text = __h1, \
1374 }, \
1375 }
1376
1377#define HEADER_SPAN_LOW(__h) \
1378 { \
1379 .line[1] = { \
1380 .text = __h, \
1381 }, \
1382 }
1383
Jiri Olsacbb88502016-09-22 17:36:48 +02001384static struct c2c_dimension dim_dcacheline = {
Jiri Olsa03d9fcb2018-03-09 11:14:42 +01001385 .header = HEADER_SPAN("--- Cacheline ----", "Address", 2),
Jiri Olsacbb88502016-09-22 17:36:48 +02001386 .name = "dcacheline",
1387 .cmp = dcacheline_cmp,
1388 .entry = dcacheline_entry,
1389 .width = 18,
1390};
1391
Jiri Olsa7f834c22018-03-09 11:14:40 +01001392static struct c2c_dimension dim_dcacheline_node = {
1393 .header = HEADER_LOW("Node"),
1394 .name = "dcacheline_node",
1395 .cmp = empty_cmp,
1396 .entry = dcacheline_node_entry,
1397 .width = 4,
1398};
1399
Jiri Olsa03d9fcb2018-03-09 11:14:42 +01001400static struct c2c_dimension dim_dcacheline_count = {
1401 .header = HEADER_LOW("PA cnt"),
1402 .name = "dcacheline_count",
1403 .cmp = empty_cmp,
1404 .entry = dcacheline_node_count,
1405 .width = 6,
1406};
1407
1408static struct c2c_header header_offset_tui = HEADER_SPAN("-----", "Off", 2);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01001409
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001410static struct c2c_dimension dim_offset = {
Jiri Olsa03d9fcb2018-03-09 11:14:42 +01001411 .header = HEADER_SPAN("--- Data address -", "Offset", 2),
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001412 .name = "offset",
1413 .cmp = offset_cmp,
1414 .entry = offset_entry,
1415 .width = 18,
1416};
1417
Jiri Olsa7f834c22018-03-09 11:14:40 +01001418static struct c2c_dimension dim_offset_node = {
1419 .header = HEADER_LOW("Node"),
1420 .name = "offset_node",
1421 .cmp = empty_cmp,
1422 .entry = dcacheline_node_entry,
1423 .width = 4,
1424};
1425
Jiri Olsa43575a92016-05-03 21:48:56 +02001426static struct c2c_dimension dim_iaddr = {
1427 .header = HEADER_LOW("Code address"),
1428 .name = "iaddr",
1429 .cmp = iaddr_cmp,
1430 .entry = iaddr_entry,
1431 .width = 18,
1432};
1433
Jiri Olsa97cb4862016-05-23 16:20:14 +02001434static struct c2c_dimension dim_tot_hitm = {
Leo Yanfdd32d72020-10-14 06:09:17 +01001435 .header = HEADER_SPAN("------- Load Hitm -------", "Total", 2),
Jiri Olsa97cb4862016-05-23 16:20:14 +02001436 .name = "tot_hitm",
1437 .cmp = tot_hitm_cmp,
1438 .entry = tot_hitm_entry,
1439 .width = 7,
1440};
1441
1442static struct c2c_dimension dim_lcl_hitm = {
Leo Yan0fbe2fe2020-10-14 06:09:18 +01001443 .header = HEADER_SPAN_LOW("LclHitm"),
Jiri Olsa97cb4862016-05-23 16:20:14 +02001444 .name = "lcl_hitm",
1445 .cmp = lcl_hitm_cmp,
1446 .entry = lcl_hitm_entry,
1447 .width = 7,
1448};
1449
1450static struct c2c_dimension dim_rmt_hitm = {
Leo Yan0fbe2fe2020-10-14 06:09:18 +01001451 .header = HEADER_SPAN_LOW("RmtHitm"),
Jiri Olsa97cb4862016-05-23 16:20:14 +02001452 .name = "rmt_hitm",
1453 .cmp = rmt_hitm_cmp,
1454 .entry = rmt_hitm_entry,
1455 .width = 7,
1456};
1457
Leo Yan63e74ab2022-08-11 14:24:42 +08001458static struct c2c_dimension dim_tot_peer = {
1459 .header = HEADER_SPAN("------- Load Peer -------", "Total", 2),
1460 .name = "tot_peer",
1461 .cmp = tot_peer_cmp,
1462 .entry = tot_peer_entry,
1463 .width = 7,
1464};
1465
1466static struct c2c_dimension dim_lcl_peer = {
1467 .header = HEADER_SPAN_LOW("Local"),
1468 .name = "lcl_peer",
1469 .cmp = lcl_peer_cmp,
1470 .entry = lcl_peer_entry,
1471 .width = 7,
1472};
1473
1474static struct c2c_dimension dim_rmt_peer = {
1475 .header = HEADER_SPAN_LOW("Remote"),
1476 .name = "rmt_peer",
1477 .cmp = rmt_peer_cmp,
1478 .entry = rmt_peer_entry,
1479 .width = 7,
1480};
1481
Jiri Olsa97cb4862016-05-23 16:20:14 +02001482static struct c2c_dimension dim_cl_rmt_hitm = {
1483 .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1484 .name = "cl_rmt_hitm",
1485 .cmp = rmt_hitm_cmp,
1486 .entry = rmt_hitm_entry,
1487 .width = 7,
1488};
1489
1490static struct c2c_dimension dim_cl_lcl_hitm = {
1491 .header = HEADER_SPAN_LOW("Lcl"),
1492 .name = "cl_lcl_hitm",
1493 .cmp = lcl_hitm_cmp,
1494 .entry = lcl_hitm_entry,
1495 .width = 7,
1496};
1497
Leo Yan90822822022-08-11 14:24:43 +08001498static struct c2c_dimension dim_cl_rmt_peer = {
1499 .header = HEADER_SPAN("----- Peer -----", "Rmt", 1),
1500 .name = "cl_rmt_peer",
1501 .cmp = rmt_peer_cmp,
1502 .entry = rmt_peer_entry,
1503 .width = 7,
1504};
1505
1506static struct c2c_dimension dim_cl_lcl_peer = {
1507 .header = HEADER_SPAN_LOW("Lcl"),
1508 .name = "cl_lcl_peer",
1509 .cmp = lcl_peer_cmp,
1510 .entry = lcl_peer_entry,
1511 .width = 7,
1512};
1513
Leo Yan4f28641b2020-10-14 06:09:15 +01001514static struct c2c_dimension dim_tot_stores = {
1515 .header = HEADER_BOTH("Total", "Stores"),
1516 .name = "tot_stores",
Jiri Olsa0f188962016-05-04 10:10:11 +02001517 .cmp = store_cmp,
1518 .entry = store_entry,
1519 .width = 7,
1520};
1521
1522static struct c2c_dimension dim_stores_l1hit = {
Leo Yan550b4d62022-05-18 13:57:20 +08001523 .header = HEADER_SPAN("--------- Stores --------", "L1Hit", 2),
Jiri Olsa0f188962016-05-04 10:10:11 +02001524 .name = "stores_l1hit",
1525 .cmp = st_l1hit_cmp,
1526 .entry = st_l1hit_entry,
1527 .width = 7,
1528};
1529
1530static struct c2c_dimension dim_stores_l1miss = {
1531 .header = HEADER_SPAN_LOW("L1Miss"),
1532 .name = "stores_l1miss",
1533 .cmp = st_l1miss_cmp,
1534 .entry = st_l1miss_entry,
1535 .width = 7,
1536};
1537
Leo Yan550b4d62022-05-18 13:57:20 +08001538static struct c2c_dimension dim_stores_na = {
1539 .header = HEADER_SPAN_LOW("N/A"),
1540 .name = "stores_na",
1541 .cmp = st_na_cmp,
1542 .entry = st_na_entry,
1543 .width = 7,
1544};
1545
Jiri Olsa0f188962016-05-04 10:10:11 +02001546static struct c2c_dimension dim_cl_stores_l1hit = {
Leo Yan550b4d62022-05-18 13:57:20 +08001547 .header = HEADER_SPAN("------- Store Refs ------", "L1 Hit", 2),
Jiri Olsa0f188962016-05-04 10:10:11 +02001548 .name = "cl_stores_l1hit",
1549 .cmp = st_l1hit_cmp,
1550 .entry = st_l1hit_entry,
1551 .width = 7,
1552};
1553
1554static struct c2c_dimension dim_cl_stores_l1miss = {
1555 .header = HEADER_SPAN_LOW("L1 Miss"),
1556 .name = "cl_stores_l1miss",
1557 .cmp = st_l1miss_cmp,
1558 .entry = st_l1miss_entry,
1559 .width = 7,
1560};
1561
Leo Yan550b4d62022-05-18 13:57:20 +08001562static struct c2c_dimension dim_cl_stores_na = {
1563 .header = HEADER_SPAN_LOW("N/A"),
1564 .name = "cl_stores_na",
1565 .cmp = st_na_cmp,
1566 .entry = st_na_entry,
1567 .width = 7,
1568};
1569
Jiri Olsa1295f682016-05-04 10:18:24 +02001570static struct c2c_dimension dim_ld_fbhit = {
1571 .header = HEADER_SPAN("----- Core Load Hit -----", "FB", 2),
1572 .name = "ld_fbhit",
1573 .cmp = ld_fbhit_cmp,
1574 .entry = ld_fbhit_entry,
1575 .width = 7,
1576};
1577
1578static struct c2c_dimension dim_ld_l1hit = {
1579 .header = HEADER_SPAN_LOW("L1"),
1580 .name = "ld_l1hit",
1581 .cmp = ld_l1hit_cmp,
1582 .entry = ld_l1hit_entry,
1583 .width = 7,
1584};
1585
1586static struct c2c_dimension dim_ld_l2hit = {
1587 .header = HEADER_SPAN_LOW("L2"),
1588 .name = "ld_l2hit",
1589 .cmp = ld_l2hit_cmp,
1590 .entry = ld_l2hit_entry,
1591 .width = 7,
1592};
1593
Jiri Olsa4d089102016-05-04 10:27:51 +02001594static struct c2c_dimension dim_ld_llchit = {
Leo Yan77c15862020-10-14 06:09:20 +01001595 .header = HEADER_SPAN("- LLC Load Hit --", "LclHit", 1),
Jiri Olsa4d089102016-05-04 10:27:51 +02001596 .name = "ld_lclhit",
1597 .cmp = ld_llchit_cmp,
1598 .entry = ld_llchit_entry,
1599 .width = 8,
1600};
1601
1602static struct c2c_dimension dim_ld_rmthit = {
Leo Yan91d933c22020-10-14 06:09:21 +01001603 .header = HEADER_SPAN("- RMT Load Hit --", "RmtHit", 1),
Jiri Olsa4d089102016-05-04 10:27:51 +02001604 .name = "ld_rmthit",
1605 .cmp = rmt_hit_cmp,
1606 .entry = rmt_hit_entry,
1607 .width = 8,
1608};
1609
Jiri Olsa01b84d72016-05-04 10:35:29 +02001610static struct c2c_dimension dim_tot_recs = {
1611 .header = HEADER_BOTH("Total", "records"),
1612 .name = "tot_recs",
1613 .cmp = tot_recs_cmp,
1614 .entry = tot_recs_entry,
1615 .width = 7,
1616};
1617
Jiri Olsa55177c42016-05-19 09:52:37 +02001618static struct c2c_dimension dim_tot_loads = {
1619 .header = HEADER_BOTH("Total", "Loads"),
1620 .name = "tot_loads",
1621 .cmp = tot_loads_cmp,
1622 .entry = tot_loads_entry,
1623 .width = 7,
1624};
1625
Leo Yan2be0bc72022-08-11 14:24:46 +08001626static struct c2c_header percent_costly_snoop_header[] = {
Leo Yanc82ccc32022-08-11 14:24:45 +08001627 [DISPLAY_LCL_HITM] = HEADER_BOTH("Lcl", "Hitm"),
1628 [DISPLAY_RMT_HITM] = HEADER_BOTH("Rmt", "Hitm"),
1629 [DISPLAY_TOT_HITM] = HEADER_BOTH("Tot", "Hitm"),
Leo Yanf37c5d92022-08-11 14:24:49 +08001630 [DISPLAY_SNP_PEER] = HEADER_BOTH("Peer", "Snoop"),
Jiri Olsa55b95772016-05-29 10:21:45 +02001631};
1632
Leo Yan2be0bc72022-08-11 14:24:46 +08001633static struct c2c_dimension dim_percent_costly_snoop = {
1634 .name = "percent_costly_snoop",
1635 .cmp = percent_costly_snoop_cmp,
1636 .entry = percent_costly_snoop_entry,
1637 .color = percent_costly_snoop_color,
Jiri Olsaf0c50c12016-05-04 10:50:09 +02001638 .width = 7,
1639};
1640
Jiri Olsa9cb35002016-05-04 12:16:50 +02001641static struct c2c_dimension dim_percent_rmt_hitm = {
Leo Yan0fbe2fe2020-10-14 06:09:18 +01001642 .header = HEADER_SPAN("----- HITM -----", "RmtHitm", 1),
Jiri Olsa9cb35002016-05-04 12:16:50 +02001643 .name = "percent_rmt_hitm",
1644 .cmp = percent_rmt_hitm_cmp,
1645 .entry = percent_rmt_hitm_entry,
1646 .color = percent_rmt_hitm_color,
1647 .width = 7,
1648};
1649
1650static struct c2c_dimension dim_percent_lcl_hitm = {
Leo Yan0fbe2fe2020-10-14 06:09:18 +01001651 .header = HEADER_SPAN_LOW("LclHitm"),
Jiri Olsa9cb35002016-05-04 12:16:50 +02001652 .name = "percent_lcl_hitm",
1653 .cmp = percent_lcl_hitm_cmp,
1654 .entry = percent_lcl_hitm_entry,
1655 .color = percent_lcl_hitm_color,
1656 .width = 7,
1657};
1658
Leo Yan90822822022-08-11 14:24:43 +08001659static struct c2c_dimension dim_percent_rmt_peer = {
1660 .header = HEADER_SPAN("-- Peer Snoop --", "Rmt", 1),
1661 .name = "percent_rmt_peer",
1662 .cmp = percent_rmt_peer_cmp,
1663 .entry = percent_rmt_peer_entry,
1664 .color = percent_rmt_peer_color,
1665 .width = 7,
1666};
1667
1668static struct c2c_dimension dim_percent_lcl_peer = {
1669 .header = HEADER_SPAN_LOW("Lcl"),
1670 .name = "percent_lcl_peer",
1671 .cmp = percent_lcl_peer_cmp,
1672 .entry = percent_lcl_peer_entry,
1673 .color = percent_lcl_peer_color,
1674 .width = 7,
1675};
1676
Jiri Olsa9cb35002016-05-04 12:16:50 +02001677static struct c2c_dimension dim_percent_stores_l1hit = {
Leo Yan550b4d62022-05-18 13:57:20 +08001678 .header = HEADER_SPAN("------- Store Refs ------", "L1 Hit", 2),
Jiri Olsa9cb35002016-05-04 12:16:50 +02001679 .name = "percent_stores_l1hit",
1680 .cmp = percent_stores_l1hit_cmp,
1681 .entry = percent_stores_l1hit_entry,
1682 .color = percent_stores_l1hit_color,
1683 .width = 7,
1684};
1685
1686static struct c2c_dimension dim_percent_stores_l1miss = {
1687 .header = HEADER_SPAN_LOW("L1 Miss"),
1688 .name = "percent_stores_l1miss",
1689 .cmp = percent_stores_l1miss_cmp,
1690 .entry = percent_stores_l1miss_entry,
1691 .color = percent_stores_l1miss_color,
1692 .width = 7,
1693};
1694
Leo Yan550b4d62022-05-18 13:57:20 +08001695static struct c2c_dimension dim_percent_stores_na = {
1696 .header = HEADER_SPAN_LOW("N/A"),
1697 .name = "percent_stores_na",
1698 .cmp = percent_stores_na_cmp,
1699 .entry = percent_stores_na_entry,
1700 .color = percent_stores_na_color,
1701 .width = 7,
1702};
1703
Jiri Olsa6c70f542016-05-28 12:30:13 +02001704static struct c2c_dimension dim_dram_lcl = {
1705 .header = HEADER_SPAN("--- Load Dram ----", "Lcl", 1),
1706 .name = "dram_lcl",
1707 .cmp = lcl_dram_cmp,
1708 .entry = lcl_dram_entry,
1709 .width = 8,
1710};
1711
1712static struct c2c_dimension dim_dram_rmt = {
1713 .header = HEADER_SPAN_LOW("Rmt"),
1714 .name = "dram_rmt",
1715 .cmp = rmt_dram_cmp,
1716 .entry = rmt_dram_entry,
1717 .width = 8,
1718};
1719
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001720static struct c2c_dimension dim_pid = {
1721 .header = HEADER_LOW("Pid"),
1722 .name = "pid",
1723 .cmp = pid_cmp,
1724 .entry = pid_entry,
1725 .width = 7,
1726};
1727
Jiri Olsae87019c2016-05-25 08:50:10 +02001728static struct c2c_dimension dim_tid = {
1729 .header = HEADER_LOW("Tid"),
1730 .name = "tid",
1731 .se = &sort_thread,
1732};
1733
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001734static struct c2c_dimension dim_symbol = {
1735 .name = "symbol",
1736 .se = &sort_sym,
1737};
1738
1739static struct c2c_dimension dim_dso = {
1740 .header = HEADER_BOTH("Shared", "Object"),
1741 .name = "dso",
1742 .se = &sort_dso,
1743};
1744
Jiri Olsa1e181b92016-06-03 15:40:28 +02001745static struct c2c_dimension dim_node = {
1746 .name = "node",
1747 .cmp = empty_cmp,
1748 .entry = node_entry,
1749 .width = 4,
1750};
1751
Jiri Olsa92062d52016-06-05 13:40:53 +02001752static struct c2c_dimension dim_mean_rmt = {
1753 .header = HEADER_SPAN("---------- cycles ----------", "rmt hitm", 2),
1754 .name = "mean_rmt",
1755 .cmp = empty_cmp,
1756 .entry = mean_rmt_entry,
1757 .width = 8,
1758};
1759
1760static struct c2c_dimension dim_mean_lcl = {
1761 .header = HEADER_SPAN_LOW("lcl hitm"),
1762 .name = "mean_lcl",
1763 .cmp = empty_cmp,
1764 .entry = mean_lcl_entry,
1765 .width = 8,
1766};
1767
1768static struct c2c_dimension dim_mean_load = {
1769 .header = HEADER_SPAN_LOW("load"),
1770 .name = "mean_load",
1771 .cmp = empty_cmp,
1772 .entry = mean_load_entry,
1773 .width = 8,
1774};
1775
Leo Yan682352e2022-08-11 14:24:44 +08001776static struct c2c_dimension dim_mean_rmt_peer = {
1777 .header = HEADER_SPAN("---------- cycles ----------", "rmt peer", 2),
1778 .name = "mean_rmt_peer",
1779 .cmp = empty_cmp,
1780 .entry = mean_rmt_peer_entry,
1781 .width = 8,
1782};
1783
1784static struct c2c_dimension dim_mean_lcl_peer = {
1785 .header = HEADER_SPAN_LOW("lcl peer"),
1786 .name = "mean_lcl_peer",
1787 .cmp = empty_cmp,
1788 .entry = mean_lcl_peer_entry,
1789 .width = 8,
1790};
1791
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001792static struct c2c_dimension dim_cpucnt = {
1793 .header = HEADER_BOTH("cpu", "cnt"),
1794 .name = "cpucnt",
1795 .cmp = empty_cmp,
1796 .entry = cpucnt_entry,
1797 .width = 8,
1798};
1799
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001800static struct c2c_dimension dim_srcline = {
1801 .name = "cl_srcline",
1802 .se = &sort_srcline,
1803};
1804
Jiri Olsabb342dae2016-07-06 15:40:09 +02001805static struct c2c_dimension dim_dcacheline_idx = {
1806 .header = HEADER_LOW("Index"),
1807 .name = "cl_idx",
1808 .cmp = empty_cmp,
1809 .entry = cl_idx_entry,
1810 .width = 5,
1811};
1812
1813static struct c2c_dimension dim_dcacheline_num = {
1814 .header = HEADER_LOW("Num"),
1815 .name = "cl_num",
1816 .cmp = empty_cmp,
1817 .entry = cl_idx_entry,
1818 .width = 5,
1819};
1820
1821static struct c2c_dimension dim_dcacheline_num_empty = {
1822 .header = HEADER_LOW("Num"),
1823 .name = "cl_num_empty",
1824 .cmp = empty_cmp,
1825 .entry = cl_idx_empty_entry,
1826 .width = 5,
1827};
1828
Jiri Olsac75540e2016-09-22 17:36:41 +02001829static struct c2c_dimension *dimensions[] = {
Jiri Olsacbb88502016-09-22 17:36:48 +02001830 &dim_dcacheline,
Jiri Olsa7f834c22018-03-09 11:14:40 +01001831 &dim_dcacheline_node,
Jiri Olsa03d9fcb2018-03-09 11:14:42 +01001832 &dim_dcacheline_count,
Jiri Olsa48acdeb2016-04-29 14:37:06 +02001833 &dim_offset,
Jiri Olsa7f834c22018-03-09 11:14:40 +01001834 &dim_offset_node,
Jiri Olsa43575a92016-05-03 21:48:56 +02001835 &dim_iaddr,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001836 &dim_tot_hitm,
1837 &dim_lcl_hitm,
1838 &dim_rmt_hitm,
Leo Yan63e74ab2022-08-11 14:24:42 +08001839 &dim_tot_peer,
1840 &dim_lcl_peer,
1841 &dim_rmt_peer,
Jiri Olsa97cb4862016-05-23 16:20:14 +02001842 &dim_cl_lcl_hitm,
1843 &dim_cl_rmt_hitm,
Leo Yan90822822022-08-11 14:24:43 +08001844 &dim_cl_lcl_peer,
1845 &dim_cl_rmt_peer,
Leo Yan4f28641b2020-10-14 06:09:15 +01001846 &dim_tot_stores,
Jiri Olsa0f188962016-05-04 10:10:11 +02001847 &dim_stores_l1hit,
1848 &dim_stores_l1miss,
Leo Yan550b4d62022-05-18 13:57:20 +08001849 &dim_stores_na,
Jiri Olsa0f188962016-05-04 10:10:11 +02001850 &dim_cl_stores_l1hit,
1851 &dim_cl_stores_l1miss,
Leo Yan550b4d62022-05-18 13:57:20 +08001852 &dim_cl_stores_na,
Jiri Olsa1295f682016-05-04 10:18:24 +02001853 &dim_ld_fbhit,
1854 &dim_ld_l1hit,
1855 &dim_ld_l2hit,
Jiri Olsa4d089102016-05-04 10:27:51 +02001856 &dim_ld_llchit,
1857 &dim_ld_rmthit,
Jiri Olsa01b84d72016-05-04 10:35:29 +02001858 &dim_tot_recs,
Jiri Olsa55177c42016-05-19 09:52:37 +02001859 &dim_tot_loads,
Leo Yan2be0bc72022-08-11 14:24:46 +08001860 &dim_percent_costly_snoop,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001861 &dim_percent_rmt_hitm,
1862 &dim_percent_lcl_hitm,
Leo Yan90822822022-08-11 14:24:43 +08001863 &dim_percent_rmt_peer,
1864 &dim_percent_lcl_peer,
Jiri Olsa9cb35002016-05-04 12:16:50 +02001865 &dim_percent_stores_l1hit,
1866 &dim_percent_stores_l1miss,
Leo Yan550b4d62022-05-18 13:57:20 +08001867 &dim_percent_stores_na,
Jiri Olsa6c70f542016-05-28 12:30:13 +02001868 &dim_dram_lcl,
1869 &dim_dram_rmt,
Jiri Olsa36d3deb2016-05-24 13:09:47 +02001870 &dim_pid,
Jiri Olsae87019c2016-05-25 08:50:10 +02001871 &dim_tid,
Jiri Olsa51dedaa2016-05-24 23:41:52 +02001872 &dim_symbol,
1873 &dim_dso,
Jiri Olsa1e181b92016-06-03 15:40:28 +02001874 &dim_node,
Jiri Olsa92062d52016-06-05 13:40:53 +02001875 &dim_mean_rmt,
1876 &dim_mean_lcl,
Leo Yan682352e2022-08-11 14:24:44 +08001877 &dim_mean_rmt_peer,
1878 &dim_mean_lcl_peer,
Jiri Olsa92062d52016-06-05 13:40:53 +02001879 &dim_mean_load,
Jiri Olsab6fe2bb2016-06-23 23:05:52 +02001880 &dim_cpucnt,
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02001881 &dim_srcline,
Jiri Olsabb342dae2016-07-06 15:40:09 +02001882 &dim_dcacheline_idx,
1883 &dim_dcacheline_num,
1884 &dim_dcacheline_num_empty,
Jiri Olsac75540e2016-09-22 17:36:41 +02001885 NULL,
1886};
1887
1888static void fmt_free(struct perf_hpp_fmt *fmt)
1889{
1890 struct c2c_fmt *c2c_fmt;
1891
1892 c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1893 free(c2c_fmt);
1894}
1895
1896static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1897{
1898 struct c2c_fmt *c2c_a = container_of(a, struct c2c_fmt, fmt);
1899 struct c2c_fmt *c2c_b = container_of(b, struct c2c_fmt, fmt);
1900
1901 return c2c_a->dim == c2c_b->dim;
1902}
1903
1904static struct c2c_dimension *get_dimension(const char *name)
1905{
1906 unsigned int i;
1907
1908 for (i = 0; dimensions[i]; i++) {
1909 struct c2c_dimension *dim = dimensions[i];
1910
1911 if (!strcmp(dim->name, name))
1912 return dim;
Zou Wei2cca5122020-04-28 16:58:56 +08001913 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001914
1915 return NULL;
1916}
1917
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001918static int c2c_se_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1919 struct hist_entry *he)
1920{
1921 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1922 struct c2c_dimension *dim = c2c_fmt->dim;
1923 size_t len = fmt->user_len;
1924
Jiri Olsa590b6a32016-07-10 16:25:15 +02001925 if (!len) {
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001926 len = hists__col_len(he->hists, dim->se->se_width_idx);
1927
Jiri Olsa590b6a32016-07-10 16:25:15 +02001928 if (dim == &dim_symbol || dim == &dim_srcline)
1929 len = symbol_width(he->hists, dim->se);
1930 }
1931
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001932 return dim->se->se_snprintf(he, hpp->buf, hpp->size, len);
1933}
1934
1935static int64_t c2c_se_cmp(struct perf_hpp_fmt *fmt,
1936 struct hist_entry *a, struct hist_entry *b)
1937{
1938 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1939 struct c2c_dimension *dim = c2c_fmt->dim;
1940
1941 return dim->se->se_cmp(a, b);
1942}
1943
1944static int64_t c2c_se_collapse(struct perf_hpp_fmt *fmt,
1945 struct hist_entry *a, struct hist_entry *b)
1946{
1947 struct c2c_fmt *c2c_fmt = container_of(fmt, struct c2c_fmt, fmt);
1948 struct c2c_dimension *dim = c2c_fmt->dim;
1949 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1950
1951 collapse_fn = dim->se->se_collapse ?: dim->se->se_cmp;
1952 return collapse_fn(a, b);
1953}
1954
Jiri Olsac75540e2016-09-22 17:36:41 +02001955static struct c2c_fmt *get_format(const char *name)
1956{
1957 struct c2c_dimension *dim = get_dimension(name);
1958 struct c2c_fmt *c2c_fmt;
1959 struct perf_hpp_fmt *fmt;
1960
1961 if (!dim)
1962 return NULL;
1963
1964 c2c_fmt = zalloc(sizeof(*c2c_fmt));
1965 if (!c2c_fmt)
1966 return NULL;
1967
1968 c2c_fmt->dim = dim;
1969
1970 fmt = &c2c_fmt->fmt;
1971 INIT_LIST_HEAD(&fmt->list);
1972 INIT_LIST_HEAD(&fmt->sort_list);
1973
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001974 fmt->cmp = dim->se ? c2c_se_cmp : dim->cmp;
1975 fmt->sort = dim->se ? c2c_se_cmp : dim->cmp;
Jiri Olsa9cb35002016-05-04 12:16:50 +02001976 fmt->color = dim->se ? NULL : dim->color;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001977 fmt->entry = dim->se ? c2c_se_entry : dim->entry;
Jiri Olsac75540e2016-09-22 17:36:41 +02001978 fmt->header = c2c_header;
1979 fmt->width = c2c_width;
Jiri Olsa8d3f9382016-09-22 17:36:42 +02001980 fmt->collapse = dim->se ? c2c_se_collapse : dim->cmp;
Jiri Olsac75540e2016-09-22 17:36:41 +02001981 fmt->equal = fmt_equal;
1982 fmt->free = fmt_free;
1983
1984 return c2c_fmt;
1985}
1986
1987static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name)
1988{
1989 struct c2c_fmt *c2c_fmt = get_format(name);
1990
Jiri Olsa5f2eca82016-09-22 17:36:43 +02001991 if (!c2c_fmt) {
1992 reset_dimensions();
1993 return output_field_add(hpp_list, name);
1994 }
Jiri Olsac75540e2016-09-22 17:36:41 +02001995
1996 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
1997 return 0;
1998}
1999
2000static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)
2001{
2002 struct c2c_fmt *c2c_fmt = get_format(name);
Jiri Olsa51dedaa2016-05-24 23:41:52 +02002003 struct c2c_dimension *dim;
Jiri Olsac75540e2016-09-22 17:36:41 +02002004
Jiri Olsa5f2eca82016-09-22 17:36:43 +02002005 if (!c2c_fmt) {
2006 reset_dimensions();
2007 return sort_dimension__add(hpp_list, name, NULL, 0);
2008 }
Jiri Olsac75540e2016-09-22 17:36:41 +02002009
Jiri Olsa51dedaa2016-05-24 23:41:52 +02002010 dim = c2c_fmt->dim;
2011 if (dim == &dim_dso)
2012 hpp_list->dso = 1;
2013
Jiri Olsac75540e2016-09-22 17:36:41 +02002014 perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt);
2015 return 0;
2016}
2017
2018#define PARSE_LIST(_list, _fn) \
2019 do { \
2020 char *tmp, *tok; \
2021 ret = 0; \
2022 \
2023 if (!_list) \
2024 break; \
2025 \
2026 for (tok = strtok_r((char *)_list, ", ", &tmp); \
2027 tok; tok = strtok_r(NULL, ", ", &tmp)) { \
2028 ret = _fn(hpp_list, tok); \
2029 if (ret == -EINVAL) { \
Arnaldo Carvalho de Melo62d94b02017-06-27 11:22:31 -03002030 pr_err("Invalid --fields key: `%s'", tok); \
Jiri Olsac75540e2016-09-22 17:36:41 +02002031 break; \
2032 } else if (ret == -ESRCH) { \
Arnaldo Carvalho de Melo62d94b02017-06-27 11:22:31 -03002033 pr_err("Unknown --fields key: `%s'", tok); \
Jiri Olsac75540e2016-09-22 17:36:41 +02002034 break; \
2035 } \
2036 } \
2037 } while (0)
2038
2039static int hpp_list__parse(struct perf_hpp_list *hpp_list,
2040 const char *output_,
2041 const char *sort_)
2042{
2043 char *output = output_ ? strdup(output_) : NULL;
2044 char *sort = sort_ ? strdup(sort_) : NULL;
2045 int ret;
2046
2047 PARSE_LIST(output, c2c_hists__init_output);
2048 PARSE_LIST(sort, c2c_hists__init_sort);
2049
2050 /* copy sort keys to output fields */
2051 perf_hpp__setup_output_field(hpp_list);
2052
2053 /*
Bhaskar Chowdhury4b3761e2021-03-20 04:58:24 +05302054 * We don't need other sorting keys other than those
Jiri Olsac75540e2016-09-22 17:36:41 +02002055 * we already specified. It also really slows down
2056 * the processing a lot with big number of output
2057 * fields, so switching this off for c2c.
2058 */
2059
2060#if 0
2061 /* and then copy output fields to sort keys */
2062 perf_hpp__append_sort_keys(&hists->list);
2063#endif
2064
2065 free(output);
2066 free(sort);
2067 return ret;
2068}
2069
2070static int c2c_hists__init(struct c2c_hists *hists,
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02002071 const char *sort,
2072 int nr_header_lines)
Jiri Olsac75540e2016-09-22 17:36:41 +02002073{
2074 __hists__init(&hists->hists, &hists->list);
2075
2076 /*
2077 * Initialize only with sort fields, we need to resort
2078 * later anyway, and that's where we add output fields
2079 * as well.
2080 */
2081 perf_hpp_list__init(&hists->list);
2082
Jiri Olsa1d62fcd2016-05-24 10:12:31 +02002083 /* Overload number of header lines.*/
2084 hists->list.nr_header_lines = nr_header_lines;
2085
Jiri Olsac75540e2016-09-22 17:36:41 +02002086 return hpp_list__parse(&hists->list, NULL, sort);
2087}
2088
Jiri Olsac75540e2016-09-22 17:36:41 +02002089static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
2090 const char *output,
2091 const char *sort)
2092{
2093 perf_hpp__reset_output_field(&c2c_hists->list);
2094 return hpp_list__parse(&c2c_hists->list, output, sort);
2095}
2096
Jiri Olsac4a75bb2018-12-28 11:18:20 +01002097#define DISPLAY_LINE_LIMIT 0.001
Jiri Olsa9857b712016-08-17 14:55:23 +02002098
Leo Yan69a95bf2021-01-14 23:46:43 +08002099static u8 filter_display(u32 val, u32 sum)
2100{
2101 if (sum == 0 || ((double)val / sum) < DISPLAY_LINE_LIMIT)
2102 return HIST_FILTER__C2C;
2103
2104 return 0;
2105}
2106
Jiri Olsa9857b712016-08-17 14:55:23 +02002107static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
2108{
2109 struct c2c_hist_entry *c2c_he;
Jiri Olsa9857b712016-08-17 14:55:23 +02002110
Jiri Olsaaf09b2d2016-10-11 13:52:05 +02002111 if (c2c.show_all)
2112 return true;
Jiri Olsa9857b712016-08-17 14:55:23 +02002113
2114 c2c_he = container_of(he, struct c2c_hist_entry, he);
2115
Jiri Olsa55b95772016-05-29 10:21:45 +02002116 switch (c2c.display) {
Leo Yanc82ccc32022-08-11 14:24:45 +08002117 case DISPLAY_LCL_HITM:
Leo Yan69a95bf2021-01-14 23:46:43 +08002118 he->filtered = filter_display(c2c_he->stats.lcl_hitm,
2119 stats->lcl_hitm);
Jiri Olsa55b95772016-05-29 10:21:45 +02002120 break;
Leo Yanc82ccc32022-08-11 14:24:45 +08002121 case DISPLAY_RMT_HITM:
Leo Yan69a95bf2021-01-14 23:46:43 +08002122 he->filtered = filter_display(c2c_he->stats.rmt_hitm,
2123 stats->rmt_hitm);
Jiri Olsad940bac2016-11-21 22:33:30 +01002124 break;
Leo Yanc82ccc32022-08-11 14:24:45 +08002125 case DISPLAY_TOT_HITM:
Leo Yan69a95bf2021-01-14 23:46:43 +08002126 he->filtered = filter_display(c2c_he->stats.tot_hitm,
2127 stats->tot_hitm);
2128 break;
Leo Yanf37c5d92022-08-11 14:24:49 +08002129 case DISPLAY_SNP_PEER:
2130 he->filtered = filter_display(c2c_he->stats.tot_peer,
2131 stats->tot_peer);
2132 break;
Jiri Olsa55b95772016-05-29 10:21:45 +02002133 default:
2134 break;
Zou Wei2cca5122020-04-28 16:58:56 +08002135 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002136
Jiri Olsa9857b712016-08-17 14:55:23 +02002137 return he->filtered == 0;
2138}
2139
Leo Yan2290e1d2021-01-14 23:46:42 +08002140static inline bool is_valid_hist_entry(struct hist_entry *he)
Jiri Olsa9857b712016-08-17 14:55:23 +02002141{
2142 struct c2c_hist_entry *c2c_he;
Leo Yan2290e1d2021-01-14 23:46:42 +08002143 bool has_record = false;
Jiri Olsa9857b712016-08-17 14:55:23 +02002144
2145 c2c_he = container_of(he, struct c2c_hist_entry, he);
Leo Yan2290e1d2021-01-14 23:46:42 +08002146
2147 /* It's a valid entry if contains stores */
2148 if (c2c_he->stats.store)
2149 return true;
2150
2151 switch (c2c.display) {
Leo Yanc82ccc32022-08-11 14:24:45 +08002152 case DISPLAY_LCL_HITM:
Leo Yan2290e1d2021-01-14 23:46:42 +08002153 has_record = !!c2c_he->stats.lcl_hitm;
2154 break;
Leo Yanc82ccc32022-08-11 14:24:45 +08002155 case DISPLAY_RMT_HITM:
Leo Yan2290e1d2021-01-14 23:46:42 +08002156 has_record = !!c2c_he->stats.rmt_hitm;
2157 break;
Leo Yanc82ccc32022-08-11 14:24:45 +08002158 case DISPLAY_TOT_HITM:
Leo Yan2290e1d2021-01-14 23:46:42 +08002159 has_record = !!c2c_he->stats.tot_hitm;
2160 break;
Leo Yanf37c5d92022-08-11 14:24:49 +08002161 case DISPLAY_SNP_PEER:
2162 has_record = !!c2c_he->stats.tot_peer;
Leo Yan2290e1d2021-01-14 23:46:42 +08002163 default:
2164 break;
2165 }
2166
2167 return has_record;
Jiri Olsa9857b712016-08-17 14:55:23 +02002168}
2169
Jiri Olsa7f834c22018-03-09 11:14:40 +01002170static void set_node_width(struct c2c_hist_entry *c2c_he, int len)
2171{
2172 struct c2c_dimension *dim;
2173
2174 dim = &c2c.hists == c2c_he->hists ?
2175 &dim_dcacheline_node : &dim_offset_node;
2176
2177 if (len > dim->width)
2178 dim->width = len;
2179}
2180
2181static int set_nodestr(struct c2c_hist_entry *c2c_he)
2182{
2183 char buf[30];
2184 int len;
2185
2186 if (c2c_he->nodestr)
2187 return 0;
2188
Yury Norov1006c5c2022-01-23 10:38:43 -08002189 if (!bitmap_empty(c2c_he->nodeset, c2c.nodes_cnt)) {
Jiri Olsa7f834c22018-03-09 11:14:40 +01002190 len = bitmap_scnprintf(c2c_he->nodeset, c2c.nodes_cnt,
2191 buf, sizeof(buf));
2192 } else {
2193 len = scnprintf(buf, sizeof(buf), "N/A");
2194 }
2195
2196 set_node_width(c2c_he, len);
2197 c2c_he->nodestr = strdup(buf);
2198 return c2c_he->nodestr ? 0 : -ENOMEM;
2199}
2200
Jiri Olsa37731382018-03-09 11:14:38 +01002201static void calc_width(struct c2c_hist_entry *c2c_he)
Jiri Olsa25aa84e2016-06-07 19:02:43 +02002202{
2203 struct c2c_hists *c2c_hists;
2204
Jiri Olsa37731382018-03-09 11:14:38 +01002205 c2c_hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
2206 hists__calc_col_len(&c2c_hists->hists, &c2c_he->he);
Jiri Olsa7f834c22018-03-09 11:14:40 +01002207 set_nodestr(c2c_he);
Jiri Olsa25aa84e2016-06-07 19:02:43 +02002208}
2209
Jiri Olsae4c38fd2019-02-04 15:18:06 +01002210static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
Jiri Olsaec06f9b2016-09-22 17:36:45 +02002211{
Jiri Olsa37731382018-03-09 11:14:38 +01002212 struct c2c_hist_entry *c2c_he;
2213
2214 c2c_he = container_of(he, struct c2c_hist_entry, he);
2215
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02002216 if (c2c.show_src && !he->srcline)
Arnaldo Carvalho de Melo6a53da02018-05-28 11:06:58 -03002217 he->srcline = hist_entry__srcline(he);
Jiri Olsa89d9ba8f2016-07-10 15:47:40 +02002218
Jiri Olsa37731382018-03-09 11:14:38 +01002219 calc_width(c2c_he);
Jiri Olsa25aa84e2016-06-07 19:02:43 +02002220
Leo Yan2290e1d2021-01-14 23:46:42 +08002221 if (!is_valid_hist_entry(he))
Jiri Olsa9857b712016-08-17 14:55:23 +02002222 he->filtered = HIST_FILTER__C2C;
2223
Jiri Olsaec06f9b2016-09-22 17:36:45 +02002224 return 0;
2225}
2226
Jiri Olsae4c38fd2019-02-04 15:18:06 +01002227static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
Jiri Olsaec06f9b2016-09-22 17:36:45 +02002228{
2229 struct c2c_hist_entry *c2c_he;
2230 struct c2c_hists *c2c_hists;
Leo Yan18344362021-01-14 23:46:41 +08002231 bool display = he__display(he, &c2c.shared_clines_stats);
Jiri Olsaec06f9b2016-09-22 17:36:45 +02002232
2233 c2c_he = container_of(he, struct c2c_hist_entry, he);
2234 c2c_hists = c2c_he->hists;
2235
Jiri Olsa9857b712016-08-17 14:55:23 +02002236 if (display && c2c_hists) {
Jiri Olsabb342dae2016-07-06 15:40:09 +02002237 static unsigned int idx;
2238
2239 c2c_he->cacheline_idx = idx++;
Jiri Olsabc229c22018-03-09 11:14:39 +01002240 calc_width(c2c_he);
Jiri Olsabb342dae2016-07-06 15:40:09 +02002241
Jiri Olsafc9c6302016-05-24 14:14:38 +02002242 c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort);
Jiri Olsa22dd59d2016-05-10 14:08:29 +02002243
Jiri Olsaec06f9b2016-09-22 17:36:45 +02002244 hists__collapse_resort(&c2c_hists->hists, NULL);
2245 hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb);
2246 }
2247
2248 return 0;
2249}
2250
Leo Yan7c10b652022-08-11 14:24:47 +08002251static struct c2c_header header_node_0 = HEADER_LOW("Node");
Leo Yanf37c5d92022-08-11 14:24:49 +08002252static struct c2c_header header_node_1_hitms_stores =
2253 HEADER_LOW("Node{cpus %hitms %stores}");
2254static struct c2c_header header_node_1_peers_stores =
2255 HEADER_LOW("Node{cpus %peers %stores}");
Leo Yan7c10b652022-08-11 14:24:47 +08002256static struct c2c_header header_node_2 = HEADER_LOW("Node{cpu list}");
2257
Jiri Olsa1e181b92016-06-03 15:40:28 +02002258static void setup_nodes_header(void)
2259{
Leo Yan7c10b652022-08-11 14:24:47 +08002260 switch (c2c.node_info) {
2261 case 0:
2262 dim_node.header = header_node_0;
2263 break;
2264 case 1:
Leo Yanf37c5d92022-08-11 14:24:49 +08002265 if (c2c.display == DISPLAY_SNP_PEER)
2266 dim_node.header = header_node_1_peers_stores;
2267 else
2268 dim_node.header = header_node_1_hitms_stores;
Leo Yan7c10b652022-08-11 14:24:47 +08002269 break;
2270 case 2:
2271 dim_node.header = header_node_2;
2272 break;
2273 default:
2274 break;
2275 }
2276
2277 return;
Jiri Olsa1e181b92016-06-03 15:40:28 +02002278}
2279
2280static int setup_nodes(struct perf_session *session)
2281{
2282 struct numa_node *n;
2283 unsigned long **nodes;
Ian Rogers6d188042022-01-04 22:13:51 -08002284 int node, idx;
2285 struct perf_cpu cpu;
Jiri Olsa1e181b92016-06-03 15:40:28 +02002286 int *cpu2node;
2287
2288 if (c2c.node_info > 2)
2289 c2c.node_info = 2;
2290
2291 c2c.nodes_cnt = session->header.env.nr_numa_nodes;
Ravi Bangoria1ea770f2019-08-22 14:20:45 +05302292 c2c.cpus_cnt = session->header.env.nr_cpus_avail;
Jiri Olsa1e181b92016-06-03 15:40:28 +02002293
2294 n = session->header.env.numa_nodes;
2295 if (!n)
2296 return -EINVAL;
2297
2298 nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt);
2299 if (!nodes)
2300 return -ENOMEM;
2301
2302 c2c.nodes = nodes;
2303
2304 cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt);
2305 if (!cpu2node)
2306 return -ENOMEM;
2307
Ian Rogers6d188042022-01-04 22:13:51 -08002308 for (idx = 0; idx < c2c.cpus_cnt; idx++)
2309 cpu2node[idx] = -1;
Jiri Olsa1e181b92016-06-03 15:40:28 +02002310
2311 c2c.cpu2node = cpu2node;
2312
2313 for (node = 0; node < c2c.nodes_cnt; node++) {
Jiri Olsaf8548392019-07-21 13:23:49 +02002314 struct perf_cpu_map *map = n[node].map;
Jiri Olsa1e181b92016-06-03 15:40:28 +02002315 unsigned long *set;
2316
Andy Shevchenko7fc5b572021-09-07 19:59:35 -07002317 set = bitmap_zalloc(c2c.cpus_cnt);
Jiri Olsa1e181b92016-06-03 15:40:28 +02002318 if (!set)
2319 return -ENOMEM;
2320
Jiri Olsae34c9402019-03-05 16:25:29 +01002321 nodes[node] = set;
2322
Ian Rogers3e5deb72024-02-02 15:40:54 -08002323 perf_cpu_map__for_each_cpu_skip_any(cpu, idx, map) {
Sean Christopherson75d7ba32022-11-19 01:34:46 +00002324 __set_bit(cpu.cpu, set);
Jiri Olsa1e181b92016-06-03 15:40:28 +02002325
Ian Rogers6d188042022-01-04 22:13:51 -08002326 if (WARN_ONCE(cpu2node[cpu.cpu] != -1, "node/cpu topology bug"))
Jiri Olsa1e181b92016-06-03 15:40:28 +02002327 return -EINVAL;
2328
Ian Rogers6d188042022-01-04 22:13:51 -08002329 cpu2node[cpu.cpu] = node;
Jiri Olsa1e181b92016-06-03 15:40:28 +02002330 }
Jiri Olsa1e181b92016-06-03 15:40:28 +02002331 }
2332
2333 setup_nodes_header();
2334 return 0;
2335}
2336
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002337#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
Leo Yanf37c5d92022-08-11 14:24:49 +08002338#define HAS_PEER(__h) ((__h)->stats.lcl_peer || (__h)->stats.rmt_peer)
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002339
Leo Yan18344362021-01-14 23:46:41 +08002340static int resort_shared_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002341{
2342 struct c2c_hist_entry *c2c_he;
2343 c2c_he = container_of(he, struct c2c_hist_entry, he);
2344
Leo Yanf37c5d92022-08-11 14:24:49 +08002345 if (HAS_HITMS(c2c_he) || HAS_PEER(c2c_he)) {
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002346 c2c.shared_clines++;
Leo Yan18344362021-01-14 23:46:41 +08002347 c2c_add_stats(&c2c.shared_clines_stats, &c2c_he->stats);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002348 }
2349
2350 return 0;
2351}
2352
2353static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
2354{
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08002355 struct rb_node *next = rb_first_cached(&hists->entries);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002356 int ret = 0;
2357
2358 while (next) {
2359 struct hist_entry *he;
2360
2361 he = rb_entry(next, struct hist_entry, rb_node);
Jiri Olsae4c38fd2019-02-04 15:18:06 +01002362 ret = cb(he, NULL);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002363 if (ret)
2364 break;
2365 next = rb_next(&he->rb_node);
2366 }
2367
2368 return ret;
2369}
2370
Jiri Olsa74c63a22016-05-02 20:01:59 +02002371static void print_c2c__display_stats(FILE *out)
2372{
2373 int llc_misses;
2374 struct c2c_stats *stats = &c2c.hists.stats;
2375
Shang XiaoJingcf874a02022-09-06 11:29:05 +08002376 llc_misses = get_load_llc_misses(stats);
Jiri Olsa74c63a22016-05-02 20:01:59 +02002377
2378 fprintf(out, "=================================================\n");
2379 fprintf(out, " Trace Event Information \n");
2380 fprintf(out, "=================================================\n");
2381 fprintf(out, " Total records : %10d\n", stats->nr_entries);
2382 fprintf(out, " Locked Load/Store Operations : %10d\n", stats->locks);
2383 fprintf(out, " Load Operations : %10d\n", stats->load);
2384 fprintf(out, " Loads - uncacheable : %10d\n", stats->ld_uncache);
2385 fprintf(out, " Loads - IO : %10d\n", stats->ld_io);
2386 fprintf(out, " Loads - Miss : %10d\n", stats->ld_miss);
2387 fprintf(out, " Loads - no mapping : %10d\n", stats->ld_noadrs);
2388 fprintf(out, " Load Fill Buffer Hit : %10d\n", stats->ld_fbhit);
2389 fprintf(out, " Load L1D hit : %10d\n", stats->ld_l1hit);
2390 fprintf(out, " Load L2D hit : %10d\n", stats->ld_l2hit);
2391 fprintf(out, " Load LLC hit : %10d\n", stats->ld_llchit + stats->lcl_hitm);
2392 fprintf(out, " Load Local HITM : %10d\n", stats->lcl_hitm);
2393 fprintf(out, " Load Remote HITM : %10d\n", stats->rmt_hitm);
2394 fprintf(out, " Load Remote HIT : %10d\n", stats->rmt_hit);
2395 fprintf(out, " Load Local DRAM : %10d\n", stats->lcl_dram);
2396 fprintf(out, " Load Remote DRAM : %10d\n", stats->rmt_dram);
2397 fprintf(out, " Load MESI State Exclusive : %10d\n", stats->ld_excl);
2398 fprintf(out, " Load MESI State Shared : %10d\n", stats->ld_shared);
2399 fprintf(out, " Load LLC Misses : %10d\n", llc_misses);
Kan Liangd9d5d7672021-02-02 12:09:08 -08002400 fprintf(out, " Load access blocked by data : %10d\n", stats->blk_data);
2401 fprintf(out, " Load access blocked by address : %10d\n", stats->blk_addr);
Leo Yan3ef1fc12022-08-11 14:24:41 +08002402 fprintf(out, " Load HIT Local Peer : %10d\n", stats->lcl_peer);
2403 fprintf(out, " Load HIT Remote Peer : %10d\n", stats->rmt_peer);
Jiri Olsa74c63a22016-05-02 20:01:59 +02002404 fprintf(out, " LLC Misses to Local DRAM : %10.1f%%\n", ((double)stats->lcl_dram/(double)llc_misses) * 100.);
2405 fprintf(out, " LLC Misses to Remote DRAM : %10.1f%%\n", ((double)stats->rmt_dram/(double)llc_misses) * 100.);
2406 fprintf(out, " LLC Misses to Remote cache (HIT) : %10.1f%%\n", ((double)stats->rmt_hit /(double)llc_misses) * 100.);
2407 fprintf(out, " LLC Misses to Remote cache (HITM) : %10.1f%%\n", ((double)stats->rmt_hitm/(double)llc_misses) * 100.);
2408 fprintf(out, " Store Operations : %10d\n", stats->store);
2409 fprintf(out, " Store - uncacheable : %10d\n", stats->st_uncache);
2410 fprintf(out, " Store - no mapping : %10d\n", stats->st_noadrs);
2411 fprintf(out, " Store L1D Hit : %10d\n", stats->st_l1hit);
2412 fprintf(out, " Store L1D Miss : %10d\n", stats->st_l1miss);
Leo Yan550b4d62022-05-18 13:57:20 +08002413 fprintf(out, " Store No available memory level : %10d\n", stats->st_na);
Jiri Olsa74c63a22016-05-02 20:01:59 +02002414 fprintf(out, " No Page Map Rejects : %10d\n", stats->nomap);
2415 fprintf(out, " Unable to parse data source : %10d\n", stats->noparse);
2416}
2417
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002418static void print_shared_cacheline_info(FILE *out)
2419{
Leo Yan18344362021-01-14 23:46:41 +08002420 struct c2c_stats *stats = &c2c.shared_clines_stats;
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002421 int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
2422
2423 fprintf(out, "=================================================\n");
2424 fprintf(out, " Global Shared Cache Line Event Information \n");
2425 fprintf(out, "=================================================\n");
2426 fprintf(out, " Total Shared Cache Lines : %10d\n", c2c.shared_clines);
2427 fprintf(out, " Load HITs on shared lines : %10d\n", stats->load);
2428 fprintf(out, " Fill Buffer Hits on shared lines : %10d\n", stats->ld_fbhit);
2429 fprintf(out, " L1D hits on shared lines : %10d\n", stats->ld_l1hit);
2430 fprintf(out, " L2D hits on shared lines : %10d\n", stats->ld_l2hit);
2431 fprintf(out, " LLC hits on shared lines : %10d\n", stats->ld_llchit + stats->lcl_hitm);
Leo Yan3ef1fc12022-08-11 14:24:41 +08002432 fprintf(out, " Load hits on peer cache or nodes : %10d\n", stats->lcl_peer + stats->rmt_peer);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002433 fprintf(out, " Locked Access on shared lines : %10d\n", stats->locks);
Kan Liangd9d5d7672021-02-02 12:09:08 -08002434 fprintf(out, " Blocked Access on shared lines : %10d\n", stats->blk_data + stats->blk_addr);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002435 fprintf(out, " Store HITs on shared lines : %10d\n", stats->store);
2436 fprintf(out, " Store L1D hits on shared lines : %10d\n", stats->st_l1hit);
Leo Yan550b4d62022-05-18 13:57:20 +08002437 fprintf(out, " Store No available memory level : %10d\n", stats->st_na);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002438 fprintf(out, " Total Merged records : %10d\n", hitm_cnt + stats->store);
2439}
2440
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002441static void print_cacheline(struct c2c_hists *c2c_hists,
2442 struct hist_entry *he_cl,
2443 struct perf_hpp_list *hpp_list,
2444 FILE *out)
2445{
2446 char bf[1000];
2447 struct perf_hpp hpp = {
2448 .buf = bf,
2449 .size = 1000,
2450 };
2451 static bool once;
2452
2453 if (!once) {
2454 hists__fprintf_headers(&c2c_hists->hists, out);
2455 once = true;
2456 } else {
2457 fprintf(out, "\n");
2458 }
2459
Leo Yan550b4d62022-05-18 13:57:20 +08002460 fprintf(out, " ----------------------------------------------------------------------\n");
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002461 __hist_entry__snprintf(he_cl, &hpp, hpp_list);
2462 fprintf(out, "%s\n", bf);
Leo Yan550b4d62022-05-18 13:57:20 +08002463 fprintf(out, " ----------------------------------------------------------------------\n");
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002464
Arnaldo Carvalho de Meloe9de7e22018-06-20 15:58:20 -03002465 hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, false);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002466}
2467
2468static void print_pareto(FILE *out)
2469{
2470 struct perf_hpp_list hpp_list;
2471 struct rb_node *nd;
2472 int ret;
Leo Yan0998d962021-01-14 23:46:46 +08002473 const char *cl_output;
2474
Leo Yanf37c5d92022-08-11 14:24:49 +08002475 if (c2c.display != DISPLAY_SNP_PEER)
2476 cl_output = "cl_num,"
2477 "cl_rmt_hitm,"
2478 "cl_lcl_hitm,"
2479 "cl_stores_l1hit,"
2480 "cl_stores_l1miss,"
2481 "cl_stores_na,"
2482 "dcacheline";
2483 else
2484 cl_output = "cl_num,"
2485 "cl_rmt_peer,"
2486 "cl_lcl_peer,"
2487 "cl_stores_l1hit,"
2488 "cl_stores_l1miss,"
2489 "cl_stores_na,"
2490 "dcacheline";
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002491
2492 perf_hpp_list__init(&hpp_list);
Leo Yan0998d962021-01-14 23:46:46 +08002493 ret = hpp_list__parse(&hpp_list, cl_output, NULL);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002494
2495 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
2496 return;
2497
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08002498 nd = rb_first_cached(&c2c.hists.hists.entries);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002499
2500 for (; nd; nd = rb_next(nd)) {
2501 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2502 struct c2c_hist_entry *c2c_he;
2503
2504 if (he->filtered)
2505 continue;
2506
2507 c2c_he = container_of(he, struct c2c_hist_entry, he);
2508 print_cacheline(c2c_he->hists, he, &hpp_list, out);
2509 }
2510}
2511
Jiri Olsa2709b972016-08-27 11:40:23 +02002512static void print_c2c_info(FILE *out, struct perf_session *session)
2513{
Jiri Olsa63503db2019-07-21 13:23:52 +02002514 struct evlist *evlist = session->evlist;
Jiri Olsa32dcd022019-07-21 13:23:51 +02002515 struct evsel *evsel;
Jiri Olsa2709b972016-08-27 11:40:23 +02002516 bool first = true;
2517
2518 fprintf(out, "=================================================\n");
2519 fprintf(out, " c2c details \n");
2520 fprintf(out, "=================================================\n");
2521
2522 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo8ab2e962020-04-29 16:07:09 -03002523 fprintf(out, "%-36s: %s\n", first ? " Events" : "", evsel__name(evsel));
Jiri Olsa2709b972016-08-27 11:40:23 +02002524 first = false;
2525 }
Leo Yanfaa30df2022-08-11 14:24:48 +08002526 fprintf(out, " Cachelines sort on : %s\n",
Jiri Olsad940bac2016-11-21 22:33:30 +01002527 display_str[c2c.display]);
Jiri Olsafc9c6302016-05-24 14:14:38 +02002528 fprintf(out, " Cacheline data grouping : %s\n", c2c.cl_sort);
Jiri Olsa2709b972016-08-27 11:40:23 +02002529}
2530
2531static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002532{
2533 setup_pager();
2534
Jiri Olsa74c63a22016-05-02 20:01:59 +02002535 print_c2c__display_stats(out);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02002536 fprintf(out, "\n");
2537 print_shared_cacheline_info(out);
Jiri Olsa2709b972016-08-27 11:40:23 +02002538 fprintf(out, "\n");
2539 print_c2c_info(out, session);
Jiri Olsa74c63a22016-05-02 20:01:59 +02002540
2541 if (c2c.stats_only)
2542 return;
2543
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002544 fprintf(out, "\n");
2545 fprintf(out, "=================================================\n");
2546 fprintf(out, " Shared Data Cache Line Table \n");
2547 fprintf(out, "=================================================\n");
2548 fprintf(out, "#\n");
2549
Arnaldo Carvalho de Meloe9de7e22018-06-20 15:58:20 -03002550 hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, true);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02002551
2552 fprintf(out, "\n");
2553 fprintf(out, "=================================================\n");
2554 fprintf(out, " Shared Cache Line Distribution Pareto \n");
2555 fprintf(out, "=================================================\n");
2556 fprintf(out, "#\n");
2557
2558 print_pareto(out);
2559}
Jiri Olsa1e181b92016-06-03 15:40:28 +02002560
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002561#ifdef HAVE_SLANG_SUPPORT
2562static void c2c_browser__update_nr_entries(struct hist_browser *hb)
2563{
2564 u64 nr_entries = 0;
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08002565 struct rb_node *nd = rb_first_cached(&hb->hists->entries);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002566
2567 while (nd) {
2568 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
2569
2570 if (!he->filtered)
2571 nr_entries++;
2572
2573 nd = rb_next(nd);
2574 }
2575
2576 hb->nr_non_filtered_entries = nr_entries;
2577}
2578
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002579struct c2c_cacheline_browser {
2580 struct hist_browser hb;
2581 struct hist_entry *he;
2582};
2583
2584static int
2585perf_c2c_cacheline_browser__title(struct hist_browser *browser,
2586 char *bf, size_t size)
2587{
2588 struct c2c_cacheline_browser *cl_browser;
2589 struct hist_entry *he;
2590 uint64_t addr = 0;
2591
2592 cl_browser = container_of(browser, struct c2c_cacheline_browser, hb);
2593 he = cl_browser->he;
2594
2595 if (he->mem_info)
Ian Rogers1a8c2e02024-05-07 11:35:44 -07002596 addr = cl_address(mem_info__daddr(he->mem_info)->addr, chk_double_cl);
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002597
2598 scnprintf(bf, size, "Cacheline 0x%lx", addr);
2599 return 0;
2600}
2601
2602static struct c2c_cacheline_browser*
2603c2c_cacheline_browser__new(struct hists *hists, struct hist_entry *he)
2604{
2605 struct c2c_cacheline_browser *browser;
2606
2607 browser = zalloc(sizeof(*browser));
2608 if (browser) {
2609 hist_browser__init(&browser->hb, hists);
2610 browser->hb.c2c_filter = true;
2611 browser->hb.title = perf_c2c_cacheline_browser__title;
2612 browser->he = he;
2613 }
2614
2615 return browser;
2616}
2617
2618static int perf_c2c__browse_cacheline(struct hist_entry *he)
2619{
2620 struct c2c_hist_entry *c2c_he;
2621 struct c2c_hists *c2c_hists;
2622 struct c2c_cacheline_browser *cl_browser;
2623 struct hist_browser *browser;
2624 int key = -1;
Rasmus Villemoes49b8e2b2018-11-03 00:06:23 +01002625 static const char help[] =
Kim Phillips239fb4f2017-11-14 15:04:47 -06002626 " ENTER Toggle callchains (if present) \n"
2627 " n Toggle Node details info \n"
2628 " s Toggle full length of symbol and source line columns \n"
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002629 " q Return back to cacheline list \n";
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002630
Jiri Olsa73978332018-07-24 08:20:08 +02002631 if (!he)
2632 return 0;
2633
Jiri Olsa590b6a32016-07-10 16:25:15 +02002634 /* Display compact version first. */
2635 c2c.symbol_full = false;
2636
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002637 c2c_he = container_of(he, struct c2c_hist_entry, he);
2638 c2c_hists = c2c_he->hists;
2639
2640 cl_browser = c2c_cacheline_browser__new(&c2c_hists->hists, he);
2641 if (cl_browser == NULL)
2642 return -1;
2643
2644 browser = &cl_browser->hb;
2645
2646 /* reset abort key so that it can get Ctrl-C as a key */
2647 SLang_reset_tty();
2648 SLang_init_tty(0, 0, 0);
2649
2650 c2c_browser__update_nr_entries(browser);
2651
2652 while (1) {
Arnaldo Carvalho de Melod10ec002019-12-12 15:31:40 -03002653 key = hist_browser__run(browser, "? - help", true, 0);
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002654
2655 switch (key) {
Jiri Olsa590b6a32016-07-10 16:25:15 +02002656 case 's':
2657 c2c.symbol_full = !c2c.symbol_full;
2658 break;
Jiri Olsa1a56a422016-07-10 16:30:27 +02002659 case 'n':
2660 c2c.node_info = (c2c.node_info + 1) % 3;
2661 setup_nodes_header();
2662 break;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002663 case 'q':
2664 goto out;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002665 case '?':
2666 ui_browser__help_window(&browser->b, help);
2667 break;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002668 default:
2669 break;
2670 }
2671 }
2672
2673out:
2674 free(cl_browser);
2675 return 0;
2676}
2677
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002678static int perf_c2c_browser__title(struct hist_browser *browser,
2679 char *bf, size_t size)
2680{
2681 scnprintf(bf, size,
Jiri Olsa55b95772016-05-29 10:21:45 +02002682 "Shared Data Cache Line Table "
Leo Yanfaa30df2022-08-11 14:24:48 +08002683 "(%lu entries, sorted on %s)",
Jiri Olsa55b95772016-05-29 10:21:45 +02002684 browser->nr_non_filtered_entries,
Jiri Olsad940bac2016-11-21 22:33:30 +01002685 display_str[c2c.display]);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002686 return 0;
2687}
2688
2689static struct hist_browser*
2690perf_c2c_browser__new(struct hists *hists)
2691{
2692 struct hist_browser *browser = hist_browser__new(hists);
2693
2694 if (browser) {
2695 browser->title = perf_c2c_browser__title;
2696 browser->c2c_filter = true;
2697 }
2698
2699 return browser;
2700}
2701
2702static int perf_c2c__hists_browse(struct hists *hists)
2703{
2704 struct hist_browser *browser;
2705 int key = -1;
Rasmus Villemoes49b8e2b2018-11-03 00:06:23 +01002706 static const char help[] =
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002707 " d Display cacheline details \n"
Kim Phillips239fb4f2017-11-14 15:04:47 -06002708 " ENTER Toggle callchains (if present) \n"
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002709 " q Quit \n";
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002710
2711 browser = perf_c2c_browser__new(hists);
2712 if (browser == NULL)
2713 return -1;
2714
2715 /* reset abort key so that it can get Ctrl-C as a key */
2716 SLang_reset_tty();
2717 SLang_init_tty(0, 0, 0);
2718
2719 c2c_browser__update_nr_entries(browser);
2720
2721 while (1) {
Arnaldo Carvalho de Melod10ec002019-12-12 15:31:40 -03002722 key = hist_browser__run(browser, "? - help", true, 0);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002723
2724 switch (key) {
2725 case 'q':
2726 goto out;
Jiri Olsaf1c5fd42016-05-02 18:30:44 +02002727 case 'd':
2728 perf_c2c__browse_cacheline(browser->he_selection);
2729 break;
Jiri Olsa9a406eb2016-08-17 15:54:58 +02002730 case '?':
2731 ui_browser__help_window(&browser->b, help);
2732 break;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002733 default:
2734 break;
2735 }
2736 }
2737
2738out:
2739 hist_browser__delete(browser);
2740 return 0;
2741}
2742
Jiri Olsa2709b972016-08-27 11:40:23 +02002743static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002744{
Namhyung Kim1936fea2017-03-08 00:08:33 +09002745 if (use_browser == 0)
Jiri Olsa2709b972016-08-27 11:40:23 +02002746 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002747 else
2748 perf_c2c__hists_browse(&c2c.hists.hists);
2749}
2750#else
Jiri Olsa2709b972016-08-27 11:40:23 +02002751static void perf_c2c_display(struct perf_session *session)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002752{
2753 use_browser = 0;
Jiri Olsa2709b972016-08-27 11:40:23 +02002754 perf_c2c__hists_fprintf(stdout, session);
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002755}
2756#endif /* HAVE_SLANG_SUPPORT */
2757
Jiri Olsad0802b12018-03-09 11:14:41 +01002758static char *fill_line(const char *orig, int len)
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002759{
Jiri Olsad0802b12018-03-09 11:14:41 +01002760 int i, j, olen = strlen(orig);
2761 char *buf;
2762
2763 buf = zalloc(len + 1);
2764 if (!buf)
2765 return NULL;
2766
2767 j = len / 2 - olen / 2;
2768
2769 for (i = 0; i < j - 1; i++)
2770 buf[i] = '-';
2771
2772 buf[i++] = ' ';
2773
2774 strcpy(buf + i, orig);
2775
2776 i += olen;
2777
2778 buf[i++] = ' ';
2779
2780 for (; i < len; i++)
2781 buf[i] = '-';
2782
2783 return buf;
2784}
2785
2786static int ui_quirks(void)
2787{
2788 const char *nodestr = "Data address";
2789 char *buf;
2790
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002791 if (!c2c.use_stdio) {
2792 dim_offset.width = 5;
2793 dim_offset.header = header_offset_tui;
Feng Tang1470a102023-02-14 15:58:23 +08002794 nodestr = chk_double_cl ? "Double-CL" : "CL";
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002795 }
Jiri Olsa55b95772016-05-29 10:21:45 +02002796
Leo Yan2be0bc72022-08-11 14:24:46 +08002797 dim_percent_costly_snoop.header = percent_costly_snoop_header[c2c.display];
Jiri Olsad0802b12018-03-09 11:14:41 +01002798
2799 /* Fix the zero line for dcacheline column. */
Feng Tang1470a102023-02-14 15:58:23 +08002800 buf = fill_line(chk_double_cl ? "Double-Cacheline" : "Cacheline",
2801 dim_dcacheline.width +
2802 dim_dcacheline_node.width +
2803 dim_dcacheline_count.width + 4);
Jiri Olsad0802b12018-03-09 11:14:41 +01002804 if (!buf)
2805 return -ENOMEM;
2806
2807 dim_dcacheline.header.line[0].text = buf;
2808
2809 /* Fix the zero line for offset column. */
2810 buf = fill_line(nodestr, dim_offset.width +
Jiri Olsa03d9fcb2018-03-09 11:14:42 +01002811 dim_offset_node.width +
2812 dim_dcacheline_count.width + 4);
Jiri Olsad0802b12018-03-09 11:14:41 +01002813 if (!buf)
2814 return -ENOMEM;
2815
2816 dim_offset.header.line[0].text = buf;
2817
2818 return 0;
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01002819}
2820
Jiri Olsadd805762016-05-11 18:23:48 +02002821#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
2822
2823const char callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
2824 CALLCHAIN_REPORT_HELP
2825 "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
2826
2827static int
2828parse_callchain_opt(const struct option *opt, const char *arg, int unset)
2829{
2830 struct callchain_param *callchain = opt->value;
2831
2832 callchain->enabled = !unset;
2833 /*
2834 * --no-call-graph
2835 */
2836 if (unset) {
2837 symbol_conf.use_callchain = false;
2838 callchain->mode = CHAIN_NONE;
2839 return 0;
2840 }
2841
2842 return parse_callchain_report_opt(arg);
2843}
2844
Jiri Olsa63503db2019-07-21 13:23:52 +02002845static int setup_callchain(struct evlist *evlist)
Jiri Olsadd805762016-05-11 18:23:48 +02002846{
Arnaldo Carvalho de Melob3c2cc22020-06-17 09:24:21 -03002847 u64 sample_type = evlist__combined_sample_type(evlist);
Jiri Olsadd805762016-05-11 18:23:48 +02002848 enum perf_call_graph_mode mode = CALLCHAIN_NONE;
2849
2850 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
Arnaldo Carvalho de Meloeabad8c2018-01-15 16:48:46 -03002851 (sample_type & PERF_SAMPLE_STACK_USER)) {
Jiri Olsadd805762016-05-11 18:23:48 +02002852 mode = CALLCHAIN_DWARF;
Arnaldo Carvalho de Meloeabad8c2018-01-15 16:48:46 -03002853 dwarf_callchain_users = true;
2854 } else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
Jiri Olsadd805762016-05-11 18:23:48 +02002855 mode = CALLCHAIN_LBR;
2856 else if (sample_type & PERF_SAMPLE_CALLCHAIN)
2857 mode = CALLCHAIN_FP;
2858
2859 if (!callchain_param.enabled &&
2860 callchain_param.mode != CHAIN_NONE &&
2861 mode != CALLCHAIN_NONE) {
2862 symbol_conf.use_callchain = true;
2863 if (callchain_register_param(&callchain_param) < 0) {
2864 ui__error("Can't register callchain params.\n");
2865 return -EINVAL;
2866 }
2867 }
2868
Kan Liangd80da762020-03-19 13:25:16 -07002869 if (c2c.stitch_lbr && (mode != CALLCHAIN_LBR)) {
2870 ui__warning("Can't find LBR callchain. Switch off --stitch-lbr.\n"
2871 "Please apply --call-graph lbr when recording.\n");
2872 c2c.stitch_lbr = false;
2873 }
2874
Jiri Olsadd805762016-05-11 18:23:48 +02002875 callchain_param.record_mode = mode;
2876 callchain_param.min_percent = 0;
2877 return 0;
2878}
2879
Jiri Olsa55b95772016-05-29 10:21:45 +02002880static int setup_display(const char *str)
2881{
Leo Yanead42a02022-08-11 14:24:50 +08002882 const char *display = str;
Jiri Olsa55b95772016-05-29 10:21:45 +02002883
Jiri Olsad940bac2016-11-21 22:33:30 +01002884 if (!strcmp(display, "tot"))
Leo Yanc82ccc32022-08-11 14:24:45 +08002885 c2c.display = DISPLAY_TOT_HITM;
Jiri Olsad940bac2016-11-21 22:33:30 +01002886 else if (!strcmp(display, "rmt"))
Leo Yanc82ccc32022-08-11 14:24:45 +08002887 c2c.display = DISPLAY_RMT_HITM;
Jiri Olsa55b95772016-05-29 10:21:45 +02002888 else if (!strcmp(display, "lcl"))
Leo Yanc82ccc32022-08-11 14:24:45 +08002889 c2c.display = DISPLAY_LCL_HITM;
Leo Yanf37c5d92022-08-11 14:24:49 +08002890 else if (!strcmp(display, "peer"))
2891 c2c.display = DISPLAY_SNP_PEER;
Jiri Olsa55b95772016-05-29 10:21:45 +02002892 else {
2893 pr_err("failed: unknown display type: %s\n", str);
2894 return -1;
2895 }
2896
2897 return 0;
2898}
2899
Jiri Olsafc9c6302016-05-24 14:14:38 +02002900#define for_each_token(__tok, __buf, __sep, __tmp) \
2901 for (__tok = strtok_r(__buf, __sep, &__tmp); __tok; \
2902 __tok = strtok_r(NULL, __sep, &__tmp))
2903
Jiri Olsa18f278d2016-10-11 13:39:47 +02002904static int build_cl_output(char *cl_sort, bool no_source)
Jiri Olsafc9c6302016-05-24 14:14:38 +02002905{
2906 char *tok, *tmp, *buf = strdup(cl_sort);
2907 bool add_pid = false;
2908 bool add_tid = false;
2909 bool add_iaddr = false;
2910 bool add_sym = false;
2911 bool add_dso = false;
2912 bool add_src = false;
Yunfeng Yeae199c52019-10-15 10:54:14 +08002913 int ret = 0;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002914
2915 if (!buf)
2916 return -ENOMEM;
2917
2918 for_each_token(tok, buf, ",", tmp) {
2919 if (!strcmp(tok, "tid")) {
2920 add_tid = true;
2921 } else if (!strcmp(tok, "pid")) {
2922 add_pid = true;
2923 } else if (!strcmp(tok, "iaddr")) {
2924 add_iaddr = true;
2925 add_sym = true;
2926 add_dso = true;
Jiri Olsa18f278d2016-10-11 13:39:47 +02002927 add_src = no_source ? false : true;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002928 } else if (!strcmp(tok, "dso")) {
2929 add_dso = true;
2930 } else if (strcmp(tok, "offset")) {
2931 pr_err("unrecognized sort token: %s\n", tok);
Yunfeng Yeae199c52019-10-15 10:54:14 +08002932 ret = -EINVAL;
2933 goto err;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002934 }
2935 }
2936
2937 if (asprintf(&c2c.cl_output,
Leo Yanf37c5d92022-08-11 14:24:49 +08002938 "%s%s%s%s%s%s%s%s%s%s%s%s",
Jiri Olsabb342dae2016-07-06 15:40:09 +02002939 c2c.use_stdio ? "cl_num_empty," : "",
Leo Yanf37c5d92022-08-11 14:24:49 +08002940 c2c.display == DISPLAY_SNP_PEER ? "percent_rmt_peer,"
2941 "percent_lcl_peer," :
2942 "percent_rmt_hitm,"
2943 "percent_lcl_hitm,",
Jiri Olsafc9c6302016-05-24 14:14:38 +02002944 "percent_stores_l1hit,"
2945 "percent_stores_l1miss,"
Leo Yan550b4d62022-05-18 13:57:20 +08002946 "percent_stores_na,"
Jiri Olsa03d9fcb2018-03-09 11:14:42 +01002947 "offset,offset_node,dcacheline_count,",
Jiri Olsafc9c6302016-05-24 14:14:38 +02002948 add_pid ? "pid," : "",
2949 add_tid ? "tid," : "",
2950 add_iaddr ? "iaddr," : "",
Leo Yanf37c5d92022-08-11 14:24:49 +08002951 c2c.display == DISPLAY_SNP_PEER ? "mean_rmt_peer,"
2952 "mean_lcl_peer," :
2953 "mean_rmt,"
2954 "mean_lcl,",
Jiri Olsafc9c6302016-05-24 14:14:38 +02002955 "mean_load,"
Jiri Olsa8763e6a2017-01-20 10:20:31 +01002956 "tot_recs,"
Jiri Olsafc9c6302016-05-24 14:14:38 +02002957 "cpucnt,",
2958 add_sym ? "symbol," : "",
2959 add_dso ? "dso," : "",
2960 add_src ? "cl_srcline," : "",
Yunfeng Yeae199c52019-10-15 10:54:14 +08002961 "node") < 0) {
2962 ret = -ENOMEM;
2963 goto err;
2964 }
Jiri Olsafc9c6302016-05-24 14:14:38 +02002965
2966 c2c.show_src = add_src;
Yunfeng Yeae199c52019-10-15 10:54:14 +08002967err:
Jiri Olsafc9c6302016-05-24 14:14:38 +02002968 free(buf);
Yunfeng Yeae199c52019-10-15 10:54:14 +08002969 return ret;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002970}
2971
Jiri Olsa18f278d2016-10-11 13:39:47 +02002972static int setup_coalesce(const char *coalesce, bool no_source)
Jiri Olsafc9c6302016-05-24 14:14:38 +02002973{
2974 const char *c = coalesce ?: coalesce_default;
Leo Yanf37c5d92022-08-11 14:24:49 +08002975 const char *sort_str = NULL;
Jiri Olsafc9c6302016-05-24 14:14:38 +02002976
2977 if (asprintf(&c2c.cl_sort, "offset,%s", c) < 0)
2978 return -ENOMEM;
2979
Jiri Olsa18f278d2016-10-11 13:39:47 +02002980 if (build_cl_output(c2c.cl_sort, no_source))
Jiri Olsafc9c6302016-05-24 14:14:38 +02002981 return -1;
2982
Leo Yanf37c5d92022-08-11 14:24:49 +08002983 if (c2c.display == DISPLAY_TOT_HITM)
2984 sort_str = "tot_hitm";
2985 else if (c2c.display == DISPLAY_RMT_HITM)
2986 sort_str = "rmt_hitm,lcl_hitm";
2987 else if (c2c.display == DISPLAY_LCL_HITM)
2988 sort_str = "lcl_hitm,rmt_hitm";
2989 else if (c2c.display == DISPLAY_SNP_PEER)
2990 sort_str = "tot_peer";
2991
2992 if (asprintf(&c2c.cl_resort, "offset,%s", sort_str) < 0)
Jiri Olsafc9c6302016-05-24 14:14:38 +02002993 return -ENOMEM;
2994
2995 pr_debug("coalesce sort fields: %s\n", c2c.cl_sort);
2996 pr_debug("coalesce resort fields: %s\n", c2c.cl_resort);
2997 pr_debug("coalesce output fields: %s\n", c2c.cl_output);
2998 return 0;
2999}
3000
Jiri Olsa903a6f12016-09-22 17:36:40 +02003001static int perf_c2c__report(int argc, const char **argv)
3002{
Leo Yanc825f782020-11-06 17:48:52 +08003003 struct itrace_synth_opts itrace_synth_opts = {
3004 .set = true,
3005 .mem = true, /* Only enable memory event */
3006 .default_no_sample = true,
3007 };
3008
Jiri Olsa903a6f12016-09-22 17:36:40 +02003009 struct perf_session *session;
Jiri Olsa78b27542016-09-22 17:36:44 +02003010 struct ui_progress prog;
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01003011 struct perf_data data = {
Jiri Olsa903a6f12016-09-22 17:36:40 +02003012 .mode = PERF_DATA_MODE_READ,
3013 };
Jiri Olsadd805762016-05-11 18:23:48 +02003014 char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
Jiri Olsa55b95772016-05-29 10:21:45 +02003015 const char *display = NULL;
Jiri Olsafc9c6302016-05-24 14:14:38 +02003016 const char *coalesce = NULL;
Jiri Olsa18f278d2016-10-11 13:39:47 +02003017 bool no_source = false;
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01003018 const struct option options[] = {
Jiri Olsa903a6f12016-09-22 17:36:40 +02003019 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
3020 "file", "vmlinux pathname"),
Jiri Olsa903a6f12016-09-22 17:36:40 +02003021 OPT_STRING('i', "input", &input_name, "file",
3022 "the input file to process"),
Jiri Olsa1e181b92016-06-03 15:40:28 +02003023 OPT_INCR('N', "node-info", &c2c.node_info,
3024 "show extra node info in report (repeat for more info)"),
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01003025 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
Jiri Olsa74c63a22016-05-02 20:01:59 +02003026 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
Namhyung Kimf75d2892017-03-08 00:08:32 +09003027 "Display only statistic tables (implies --stdio)"),
Jiri Olsa590b6a32016-07-10 16:25:15 +02003028 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
3029 "Display full length of symbols"),
Jiri Olsa18f278d2016-10-11 13:39:47 +02003030 OPT_BOOLEAN(0, "no-source", &no_source,
3031 "Do not display Source Line column"),
Jiri Olsaaf09b2d2016-10-11 13:52:05 +02003032 OPT_BOOLEAN(0, "show-all", &c2c.show_all,
3033 "Show all captured HITM lines."),
Jiri Olsadd805762016-05-11 18:23:48 +02003034 OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
3035 "print_type,threshold[,print_limit],order,sort_key[,branch],value",
3036 callchain_help, &parse_callchain_opt,
3037 callchain_default_opt),
Leo Yanf37c5d92022-08-11 14:24:49 +08003038 OPT_STRING('d', "display", &display, "Switch HITM output type", "tot,lcl,rmt,peer"),
Jiri Olsafc9c6302016-05-24 14:14:38 +02003039 OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
3040 "coalesce fields: pid,tid,iaddr,dso"),
Jiri Olsab7ac4f92016-11-21 22:33:28 +01003041 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
Kan Liangd80da762020-03-19 13:25:16 -07003042 OPT_BOOLEAN(0, "stitch-lbr", &c2c.stitch_lbr,
3043 "Enable LBR callgraph stitching approach"),
Feng Tang1470a102023-02-14 15:58:23 +08003044 OPT_BOOLEAN(0, "double-cl", &chk_double_cl, "Detect adjacent cacheline false sharing"),
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01003045 OPT_PARENT(c2c_options),
Jiri Olsa903a6f12016-09-22 17:36:40 +02003046 OPT_END()
3047 };
3048 int err = 0;
Leo Yan0998d962021-01-14 23:46:46 +08003049 const char *output_str, *sort_str = NULL;
Jiri Olsa903a6f12016-09-22 17:36:40 +02003050
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01003051 argc = parse_options(argc, argv, options, report_c2c_usage,
Jiri Olsa903a6f12016-09-22 17:36:40 +02003052 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa78b27542016-09-22 17:36:44 +02003053 if (argc)
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01003054 usage_with_options(report_c2c_usage, options);
Jiri Olsa903a6f12016-09-22 17:36:40 +02003055
Leo Yanc4040212022-05-26 22:54:00 +08003056#ifndef HAVE_SLANG_SUPPORT
3057 c2c.use_stdio = true;
3058#endif
3059
Jiri Olsa74c63a22016-05-02 20:01:59 +02003060 if (c2c.stats_only)
3061 c2c.use_stdio = true;
3062
James Clark7cc72552021-10-18 14:48:42 +01003063 err = symbol__validate_sym_arguments();
3064 if (err)
3065 goto out;
3066
Jiri Olsa78b27542016-09-22 17:36:44 +02003067 if (!input_name || !strlen(input_name))
3068 input_name = "perf.data";
3069
Jiri Olsa2d4f2792019-02-21 10:41:30 +01003070 data.path = input_name;
3071 data.force = symbol_conf.force;
Jiri Olsa903a6f12016-09-22 17:36:40 +02003072
Namhyung Kim2681bd82021-07-19 15:31:49 -07003073 session = perf_session__new(&data, &c2c.tool);
Mamatha Inamdar6ef81c52019-08-22 12:50:49 +05303074 if (IS_ERR(session)) {
3075 err = PTR_ERR(session);
3076 pr_debug("Error creating perf session\n");
Jiri Olsa903a6f12016-09-22 17:36:40 +02003077 goto out;
3078 }
Jiri Olsae8c5fe12016-11-21 22:33:27 +01003079
Leo Yanead42a02022-08-11 14:24:50 +08003080 /*
3081 * Use the 'tot' as default display type if user doesn't specify it;
3082 * since Arm64 platform doesn't support HITMs flag, use 'peer' as the
3083 * default display type.
3084 */
3085 if (!display) {
3086 if (!strcmp(perf_env__arch(&session->header.env), "arm64"))
3087 display = "peer";
3088 else
3089 display = "tot";
3090 }
3091
3092 err = setup_display(display);
3093 if (err)
3094 goto out_session;
3095
3096 err = setup_coalesce(coalesce, no_source);
3097 if (err) {
3098 pr_debug("Failed to initialize hists\n");
3099 goto out_session;
3100 }
3101
3102 err = c2c_hists__init(&c2c.hists, "dcacheline", 2);
3103 if (err) {
3104 pr_debug("Failed to initialize hists\n");
3105 goto out_session;
3106 }
3107
Leo Yanc825f782020-11-06 17:48:52 +08003108 session->itrace_synth_opts = &itrace_synth_opts;
3109
Jiri Olsa1e181b92016-06-03 15:40:28 +02003110 err = setup_nodes(session);
3111 if (err) {
3112 pr_err("Failed setup nodes\n");
Leo Yanead42a02022-08-11 14:24:50 +08003113 goto out_session;
Jiri Olsa1e181b92016-06-03 15:40:28 +02003114 }
Jiri Olsa903a6f12016-09-22 17:36:40 +02003115
Jiri Olsa7f834c22018-03-09 11:14:40 +01003116 err = mem2node__init(&c2c.mem2node, &session->header.env);
Jiri Olsadd805762016-05-11 18:23:48 +02003117 if (err)
3118 goto out_session;
3119
Jiri Olsa7f834c22018-03-09 11:14:40 +01003120 err = setup_callchain(session->evlist);
3121 if (err)
3122 goto out_mem2node;
3123
Jiri Olsa903a6f12016-09-22 17:36:40 +02003124 if (symbol__init(&session->header.env) < 0)
Jiri Olsa7f834c22018-03-09 11:14:40 +01003125 goto out_mem2node;
Jiri Olsa903a6f12016-09-22 17:36:40 +02003126
3127 /* No pipe support at the moment. */
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01003128 if (perf_data__is_pipe(session->data)) {
Jiri Olsa903a6f12016-09-22 17:36:40 +02003129 pr_debug("No pipe support at the moment.\n");
Jiri Olsa7f834c22018-03-09 11:14:40 +01003130 goto out_mem2node;
Jiri Olsa903a6f12016-09-22 17:36:40 +02003131 }
3132
Jiri Olsae8c5fe12016-11-21 22:33:27 +01003133 if (c2c.use_stdio)
3134 use_browser = 0;
3135 else
3136 use_browser = 1;
3137
3138 setup_browser(false);
3139
Jiri Olsa78b27542016-09-22 17:36:44 +02003140 err = perf_session__process_events(session);
3141 if (err) {
3142 pr_err("failed to process sample\n");
Jiri Olsa7f834c22018-03-09 11:14:40 +01003143 goto out_mem2node;
Jiri Olsa78b27542016-09-22 17:36:44 +02003144 }
3145
Leo Yanf37c5d92022-08-11 14:24:49 +08003146 if (c2c.display != DISPLAY_SNP_PEER)
3147 output_str = "cl_idx,"
3148 "dcacheline,"
3149 "dcacheline_node,"
3150 "dcacheline_count,"
3151 "percent_costly_snoop,"
3152 "tot_hitm,lcl_hitm,rmt_hitm,"
3153 "tot_recs,"
3154 "tot_loads,"
3155 "tot_stores,"
3156 "stores_l1hit,stores_l1miss,stores_na,"
3157 "ld_fbhit,ld_l1hit,ld_l2hit,"
3158 "ld_lclhit,lcl_hitm,"
3159 "ld_rmthit,rmt_hitm,"
3160 "dram_lcl,dram_rmt";
3161 else
3162 output_str = "cl_idx,"
3163 "dcacheline,"
3164 "dcacheline_node,"
3165 "dcacheline_count,"
3166 "percent_costly_snoop,"
3167 "tot_peer,lcl_peer,rmt_peer,"
3168 "tot_recs,"
3169 "tot_loads,"
3170 "tot_stores,"
3171 "stores_l1hit,stores_l1miss,stores_na,"
3172 "ld_fbhit,ld_l1hit,ld_l2hit,"
3173 "ld_lclhit,lcl_hitm,"
3174 "ld_rmthit,rmt_hitm,"
3175 "dram_lcl,dram_rmt";
Leo Yan0998d962021-01-14 23:46:46 +08003176
Leo Yanc82ccc32022-08-11 14:24:45 +08003177 if (c2c.display == DISPLAY_TOT_HITM)
Leo Yan0998d962021-01-14 23:46:46 +08003178 sort_str = "tot_hitm";
Leo Yanc82ccc32022-08-11 14:24:45 +08003179 else if (c2c.display == DISPLAY_RMT_HITM)
Leo Yan0998d962021-01-14 23:46:46 +08003180 sort_str = "rmt_hitm";
Leo Yanc82ccc32022-08-11 14:24:45 +08003181 else if (c2c.display == DISPLAY_LCL_HITM)
Leo Yan0998d962021-01-14 23:46:46 +08003182 sort_str = "lcl_hitm";
Leo Yanf37c5d92022-08-11 14:24:49 +08003183 else if (c2c.display == DISPLAY_SNP_PEER)
3184 sort_str = "tot_peer";
Leo Yan0998d962021-01-14 23:46:46 +08003185
3186 c2c_hists__reinit(&c2c.hists, output_str, sort_str);
Jiri Olsa22dd59d2016-05-10 14:08:29 +02003187
Jiri Olsa78b27542016-09-22 17:36:44 +02003188 ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
3189
3190 hists__collapse_resort(&c2c.hists.hists, NULL);
Leo Yan18344362021-01-14 23:46:41 +08003191 hists__output_resort_cb(&c2c.hists.hists, &prog, resort_shared_cl_cb);
Jiri Olsa7ef2efa2016-07-01 11:12:11 +02003192 hists__iterate_cb(&c2c.hists.hists, resort_cl_cb);
Jiri Olsa78b27542016-09-22 17:36:44 +02003193
3194 ui_progress__finish();
3195
Jiri Olsad0802b12018-03-09 11:14:41 +01003196 if (ui_quirks()) {
3197 pr_err("failed to setup UI\n");
3198 goto out_mem2node;
3199 }
Jiri Olsa5a1a99c2016-01-06 16:59:02 +01003200
Jiri Olsa2709b972016-08-27 11:40:23 +02003201 perf_c2c_display(session);
Jiri Olsa2d388bd2016-05-03 14:32:56 +02003202
Jiri Olsa7f834c22018-03-09 11:14:40 +01003203out_mem2node:
3204 mem2node__exit(&c2c.mem2node);
Jiri Olsa903a6f12016-09-22 17:36:40 +02003205out_session:
3206 perf_session__delete(session);
3207out:
3208 return err;
3209}
3210
Arnaldo Carvalho de Melo7e6a7992016-12-12 10:52:10 -03003211static int parse_record_events(const struct option *opt,
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003212 const char *str, int unset __maybe_unused)
3213{
3214 bool *event_set = (bool *) opt->value;
Kan Lianga30450e2024-01-23 10:50:31 -08003215 struct perf_pmu *pmu;
3216
3217 pmu = perf_mem_events_find_pmu();
3218 if (!pmu) {
3219 pr_err("failed: there is no PMU that supports perf c2c\n");
3220 exit(-1);
3221 }
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003222
Ian Rogersb027cc62020-05-07 15:06:04 -07003223 if (!strcmp(str, "list")) {
Kan Lianga30450e2024-01-23 10:50:31 -08003224 perf_pmu__mem_events_list(pmu);
Ian Rogersb027cc62020-05-07 15:06:04 -07003225 exit(0);
3226 }
Kan Lianga30450e2024-01-23 10:50:31 -08003227 if (perf_pmu__mem_events_parse(pmu, str))
Ian Rogersb027cc62020-05-07 15:06:04 -07003228 exit(-1);
3229
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003230 *event_set = true;
Ian Rogersb027cc62020-05-07 15:06:04 -07003231 return 0;
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003232}
3233
3234
3235static const char * const __usage_record[] = {
3236 "perf c2c record [<options>] [<command>]",
3237 "perf c2c record [<options>] -- <command> [<options>]",
3238 NULL
3239};
3240
3241static const char * const *record_mem_usage = __usage_record;
3242
3243static int perf_c2c__record(int argc, const char **argv)
3244{
Kan Liang70f4b202024-01-23 10:50:35 -08003245 int rec_argc, i = 0, j;
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003246 const char **rec_argv;
3247 int ret;
3248 bool all_user = false, all_kernel = false;
3249 bool event_set = false;
Leo Yaneaf6aae2020-11-06 17:48:46 +08003250 struct perf_mem_event *e;
Kan Lianga30450e2024-01-23 10:50:31 -08003251 struct perf_pmu *pmu;
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003252 struct option options[] = {
3253 OPT_CALLBACK('e', "event", &event_set, "event",
Leo Yanedac75a2020-10-11 20:10:22 +08003254 "event selector. Use 'perf c2c record -e list' to list available events",
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003255 parse_record_events),
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003256 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
3257 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
3258 OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
Jiri Olsa3a5bfab2016-11-21 22:33:31 +01003259 OPT_PARENT(c2c_options),
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003260 OPT_END()
3261 };
3262
Kan Lianga30450e2024-01-23 10:50:31 -08003263 pmu = perf_mem_events_find_pmu();
3264 if (!pmu) {
3265 pr_err("failed: no PMU supports the memory events\n");
3266 return -1;
3267 }
3268
3269 if (perf_pmu__mem_events_init(pmu)) {
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003270 pr_err("failed: memory events not supported\n");
3271 return -1;
3272 }
3273
3274 argc = parse_options(argc, argv, options, record_mem_usage,
3275 PARSE_OPT_KEEP_UNKNOWN);
3276
Ian Rogersabe95442023-05-27 00:21:59 -07003277 /* Max number of arguments multiplied by number of PMUs that can support them. */
Kan Liang821aca22024-01-23 10:50:36 -08003278 rec_argc = argc + 11 * (perf_pmu__mem_events_num_mem_pmus(pmu) + 1);
Jin Yao79e157b2021-05-27 08:16:10 +08003279
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003280 rec_argv = calloc(rec_argc + 1, sizeof(char *));
3281 if (!rec_argv)
3282 return -1;
3283
3284 rec_argv[i++] = "record";
3285
3286 if (!event_set) {
Kan Lianga30450e2024-01-23 10:50:31 -08003287 e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD_STORE);
Leo Yan8b8173b2020-11-06 17:48:48 +08003288 /*
3289 * The load and store operations are required, use the event
3290 * PERF_MEM_EVENTS__LOAD_STORE if it is supported.
3291 */
3292 if (e->tag) {
3293 e->record = true;
Ravi Bangoria4173cc02022-10-06 21:09:42 +05303294 rec_argv[i++] = "-W";
Leo Yan8b8173b2020-11-06 17:48:48 +08003295 } else {
Kan Lianga30450e2024-01-23 10:50:31 -08003296 e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD);
Leo Yan8b8173b2020-11-06 17:48:48 +08003297 e->record = true;
Leo Yaneaf6aae2020-11-06 17:48:46 +08003298
Kan Lianga30450e2024-01-23 10:50:31 -08003299 e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__STORE);
Leo Yan8b8173b2020-11-06 17:48:48 +08003300 e->record = true;
3301 }
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003302 }
3303
Kan Lianga30450e2024-01-23 10:50:31 -08003304 e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD);
Leo Yaneaf6aae2020-11-06 17:48:46 +08003305 if (e->record)
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003306 rec_argv[i++] = "-W";
3307
3308 rec_argv[i++] = "-d";
Jiri Olsa8fab7842018-03-09 11:14:37 +01003309 rec_argv[i++] = "--phys-data";
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003310 rec_argv[i++] = "--sample-cpu";
3311
Kan Liang70f4b202024-01-23 10:50:35 -08003312 ret = perf_mem_events__record_args(rec_argv, &i);
Jin Yao79e157b2021-05-27 08:16:10 +08003313 if (ret)
3314 goto out;
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003315
3316 if (all_user)
3317 rec_argv[i++] = "--all-user";
3318
3319 if (all_kernel)
3320 rec_argv[i++] = "--all-kernel";
3321
3322 for (j = 0; j < argc; j++, i++)
3323 rec_argv[i] = argv[j];
3324
3325 if (verbose > 0) {
3326 pr_debug("calling: ");
3327
3328 j = 0;
3329
3330 while (rec_argv[j]) {
3331 pr_debug("%s ", rec_argv[j]);
3332 j++;
3333 }
3334 pr_debug("\n");
3335 }
3336
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003337 ret = cmd_record(i, rec_argv);
Jin Yao79e157b2021-05-27 08:16:10 +08003338out:
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003339 free(rec_argv);
3340 return ret;
3341}
3342
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003343int cmd_c2c(int argc, const char **argv)
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02003344{
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02003345 argc = parse_options(argc, argv, c2c_options, c2c_usage,
3346 PARSE_OPT_STOP_AT_NON_OPTION);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003347
3348 if (!argc)
3349 usage_with_options(c2c_usage, c2c_options);
3350
Wei Liae0f4eb2022-03-25 17:20:32 +08003351 if (strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003352 return perf_c2c__record(argc, argv);
Wei Liae0f4eb2022-03-25 17:20:32 +08003353 } else if (strlen(argv[0]) > 2 && strstarts("report", argv[0])) {
Jiri Olsa903a6f12016-09-22 17:36:40 +02003354 return perf_c2c__report(argc, argv);
Jiri Olsa39bcd4a2016-09-22 17:36:39 +02003355 } else {
3356 usage_with_options(c2c_usage, c2c_options);
3357 }
3358
Jiri Olsa7aef3bf2016-09-22 17:36:38 +02003359 return 0;
3360}