xref: /openbmc/linux/tools/perf/util/mem-events.c (revision 9cc93a61)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2ce1e22b0SJiri Olsa #include <stddef.h>
3ce1e22b0SJiri Olsa #include <stdlib.h>
4ce1e22b0SJiri Olsa #include <string.h>
5ce1e22b0SJiri Olsa #include <errno.h>
654fbad54SJiri Olsa #include <sys/types.h>
754fbad54SJiri Olsa #include <sys/stat.h>
854fbad54SJiri Olsa #include <unistd.h>
954fbad54SJiri Olsa #include <api/fs/fs.h>
10877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
11d3300a3cSArnaldo Carvalho de Melo #include "map_symbol.h"
12acbe613eSJiri Olsa #include "mem-events.h"
13ce1e22b0SJiri Olsa #include "debug.h"
140c877d75SJiri Olsa #include "symbol.h"
15e7ce8d11SJin Yao #include "pmu.h"
161eaf496eSIan Rogers #include "pmus.h"
17acbe613eSJiri Olsa 
18b0d745b3SJiri Olsa unsigned int perf_mem_events__loads_ldlat = 30;
19b0d745b3SJiri Olsa 
2054fbad54SJiri Olsa #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
21acbe613eSJiri Olsa 
22eaf6aaeeSLeo Yan static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
23f9f16dfbSLeo Yan 	E("ldlat-loads",	"cpu/mem-loads,ldlat=%u/P",	"cpu/events/mem-loads"),
24f9f16dfbSLeo Yan 	E("ldlat-stores",	"cpu/mem-stores/P",		"cpu/events/mem-stores"),
254ba2452cSLeo Yan 	E(NULL,			NULL,				NULL),
26acbe613eSJiri Olsa };
2754fbad54SJiri Olsa #undef E
28acbe613eSJiri Olsa 
29b0d745b3SJiri Olsa static char mem_loads_name[100];
30b0d745b3SJiri Olsa static bool mem_loads_name__init;
31b0d745b3SJiri Olsa 
perf_mem_events__ptr(int i)32eaf6aaeeSLeo Yan struct perf_mem_event * __weak perf_mem_events__ptr(int i)
33eaf6aaeeSLeo Yan {
34eaf6aaeeSLeo Yan 	if (i >= PERF_MEM_EVENTS__MAX)
35eaf6aaeeSLeo Yan 		return NULL;
36eaf6aaeeSLeo Yan 
37eaf6aaeeSLeo Yan 	return &perf_mem_events[i];
38eaf6aaeeSLeo Yan }
39eaf6aaeeSLeo Yan 
perf_mem_events__name(int i,const char * pmu_name __maybe_unused)40c091ee90SIan Rogers const char * __weak perf_mem_events__name(int i, const char *pmu_name  __maybe_unused)
412ba7ac58SJiri Olsa {
42eaf6aaeeSLeo Yan 	struct perf_mem_event *e = perf_mem_events__ptr(i);
43eaf6aaeeSLeo Yan 
44eaf6aaeeSLeo Yan 	if (!e)
45eaf6aaeeSLeo Yan 		return NULL;
46eaf6aaeeSLeo Yan 
47b0d745b3SJiri Olsa 	if (i == PERF_MEM_EVENTS__LOAD) {
48b0d745b3SJiri Olsa 		if (!mem_loads_name__init) {
49b0d745b3SJiri Olsa 			mem_loads_name__init = true;
50b0d745b3SJiri Olsa 			scnprintf(mem_loads_name, sizeof(mem_loads_name),
51eaf6aaeeSLeo Yan 				  e->name, perf_mem_events__loads_ldlat);
52b0d745b3SJiri Olsa 		}
53b0d745b3SJiri Olsa 		return mem_loads_name;
54b0d745b3SJiri Olsa 	}
55b0d745b3SJiri Olsa 
56c091ee90SIan Rogers 	return e->name;
572ba7ac58SJiri Olsa }
582ba7ac58SJiri Olsa 
is_mem_loads_aux_event(struct evsel * leader __maybe_unused)592a57d408SKan Liang __weak bool is_mem_loads_aux_event(struct evsel *leader __maybe_unused)
602a57d408SKan Liang {
612a57d408SKan Liang 	return false;
622a57d408SKan Liang }
632a57d408SKan Liang 
perf_mem_events__parse(const char * str)64ce1e22b0SJiri Olsa int perf_mem_events__parse(const char *str)
65ce1e22b0SJiri Olsa {
66ce1e22b0SJiri Olsa 	char *tok, *saveptr = NULL;
67ce1e22b0SJiri Olsa 	bool found = false;
68ce1e22b0SJiri Olsa 	char *buf;
69ce1e22b0SJiri Olsa 	int j;
70ce1e22b0SJiri Olsa 
71ce1e22b0SJiri Olsa 	/* We need buffer that we know we can write to. */
72ce1e22b0SJiri Olsa 	buf = malloc(strlen(str) + 1);
73ce1e22b0SJiri Olsa 	if (!buf)
74ce1e22b0SJiri Olsa 		return -ENOMEM;
75ce1e22b0SJiri Olsa 
76ce1e22b0SJiri Olsa 	strcpy(buf, str);
77ce1e22b0SJiri Olsa 
78ce1e22b0SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
79ce1e22b0SJiri Olsa 
80ce1e22b0SJiri Olsa 	while (tok) {
81ce1e22b0SJiri Olsa 		for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
82eaf6aaeeSLeo Yan 			struct perf_mem_event *e = perf_mem_events__ptr(j);
83ce1e22b0SJiri Olsa 
844ba2452cSLeo Yan 			if (!e->tag)
854ba2452cSLeo Yan 				continue;
864ba2452cSLeo Yan 
87ce1e22b0SJiri Olsa 			if (strstr(e->tag, tok))
88ce1e22b0SJiri Olsa 				e->record = found = true;
89ce1e22b0SJiri Olsa 		}
90ce1e22b0SJiri Olsa 
91ce1e22b0SJiri Olsa 		tok = strtok_r(NULL, ",", &saveptr);
92ce1e22b0SJiri Olsa 	}
93ce1e22b0SJiri Olsa 
94ce1e22b0SJiri Olsa 	free(buf);
95ce1e22b0SJiri Olsa 
96ce1e22b0SJiri Olsa 	if (found)
97ce1e22b0SJiri Olsa 		return 0;
98ce1e22b0SJiri Olsa 
99ce1e22b0SJiri Olsa 	pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
100ce1e22b0SJiri Olsa 	return -1;
101ce1e22b0SJiri Olsa }
10254fbad54SJiri Olsa 
perf_mem_event__supported(const char * mnt,struct perf_pmu * pmu,struct perf_mem_event * e)103*9cc93a61SKan Liang static bool perf_mem_event__supported(const char *mnt, struct perf_pmu *pmu,
104*9cc93a61SKan Liang 				      struct perf_mem_event *e)
105e7ce8d11SJin Yao {
106*9cc93a61SKan Liang 	char sysfs_name[100];
107e7ce8d11SJin Yao 	char path[PATH_MAX];
108e7ce8d11SJin Yao 	struct stat st;
109e7ce8d11SJin Yao 
110*9cc93a61SKan Liang 	scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name);
111e7ce8d11SJin Yao 	scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name);
112e7ce8d11SJin Yao 	return !stat(path, &st);
113e7ce8d11SJin Yao }
114e7ce8d11SJin Yao 
perf_mem_events__init(void)11554fbad54SJiri Olsa int perf_mem_events__init(void)
11654fbad54SJiri Olsa {
11754fbad54SJiri Olsa 	const char *mnt = sysfs__mount();
11854fbad54SJiri Olsa 	bool found = false;
11954fbad54SJiri Olsa 	int j;
12054fbad54SJiri Olsa 
12154fbad54SJiri Olsa 	if (!mnt)
12254fbad54SJiri Olsa 		return -ENOENT;
12354fbad54SJiri Olsa 
12454fbad54SJiri Olsa 	for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
125eaf6aaeeSLeo Yan 		struct perf_mem_event *e = perf_mem_events__ptr(j);
12694f9eb95SIan Rogers 		struct perf_pmu *pmu = NULL;
12754fbad54SJiri Olsa 
1284ba2452cSLeo Yan 		/*
1294ba2452cSLeo Yan 		 * If the event entry isn't valid, skip initialization
1304ba2452cSLeo Yan 		 * and "e->supported" will keep false.
1314ba2452cSLeo Yan 		 */
1324ba2452cSLeo Yan 		if (!e->tag)
1334ba2452cSLeo Yan 			continue;
1344ba2452cSLeo Yan 
1355752c20fSRavi Bangoria 		/*
1365752c20fSRavi Bangoria 		 * Scan all PMUs not just core ones, since perf mem/c2c on
1375752c20fSRavi Bangoria 		 * platforms like AMD uses IBS OP PMU which is independent
1385752c20fSRavi Bangoria 		 * of core PMU.
1395752c20fSRavi Bangoria 		 */
1405752c20fSRavi Bangoria 		while ((pmu = perf_pmus__scan(pmu)) != NULL) {
141*9cc93a61SKan Liang 			e->supported |= perf_mem_event__supported(mnt, pmu, e);
142*9cc93a61SKan Liang 			if (e->supported) {
143e7ce8d11SJin Yao 				found = true;
144*9cc93a61SKan Liang 				break;
145*9cc93a61SKan Liang 			}
146*9cc93a61SKan Liang 		}
14754fbad54SJiri Olsa 	}
14854fbad54SJiri Olsa 
14954fbad54SJiri Olsa 	return found ? 0 : -ENOENT;
15054fbad54SJiri Olsa }
1510c877d75SJiri Olsa 
perf_mem_events__list(void)152b027cc6fSIan Rogers void perf_mem_events__list(void)
153b027cc6fSIan Rogers {
154b027cc6fSIan Rogers 	int j;
155b027cc6fSIan Rogers 
156b027cc6fSIan Rogers 	for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
157eaf6aaeeSLeo Yan 		struct perf_mem_event *e = perf_mem_events__ptr(j);
158b027cc6fSIan Rogers 
1592c5f652cSRavi Bangoria 		fprintf(stderr, "%-*s%-*s%s",
1602c5f652cSRavi Bangoria 			e->tag ? 13 : 0,
1614ba2452cSLeo Yan 			e->tag ? : "",
1622c5f652cSRavi Bangoria 			e->tag && verbose > 0 ? 25 : 0,
1632c5f652cSRavi Bangoria 			e->tag && verbose > 0 ? perf_mem_events__name(j, NULL) : "",
1642c5f652cSRavi Bangoria 			e->supported ? ": available\n" : "");
165b027cc6fSIan Rogers 	}
166b027cc6fSIan Rogers }
167b027cc6fSIan Rogers 
perf_mem_events__print_unsupport_hybrid(struct perf_mem_event * e,int idx)1684a9086adSJin Yao static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e,
1694a9086adSJin Yao 						    int idx)
1704a9086adSJin Yao {
1714a9086adSJin Yao 	const char *mnt = sysfs__mount();
172abe9544eSIan Rogers 	struct perf_pmu *pmu = NULL;
1734a9086adSJin Yao 
1745752c20fSRavi Bangoria 	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
175*9cc93a61SKan Liang 		if (!perf_mem_event__supported(mnt, pmu, e)) {
1764a9086adSJin Yao 			pr_err("failed: event '%s' not supported\n",
1774a9086adSJin Yao 			       perf_mem_events__name(idx, pmu->name));
1784a9086adSJin Yao 		}
1794a9086adSJin Yao 	}
1804a9086adSJin Yao }
1814a9086adSJin Yao 
perf_mem_events__record_args(const char ** rec_argv,int * argv_nr,char ** rec_tmp,int * tmp_nr)1824a9086adSJin Yao int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
1834a9086adSJin Yao 				 char **rec_tmp, int *tmp_nr)
1844a9086adSJin Yao {
185*9cc93a61SKan Liang 	const char *mnt = sysfs__mount();
1864a9086adSJin Yao 	int i = *argv_nr, k = 0;
1874a9086adSJin Yao 	struct perf_mem_event *e;
1884a9086adSJin Yao 
1894a9086adSJin Yao 	for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
1904a9086adSJin Yao 		e = perf_mem_events__ptr(j);
1914a9086adSJin Yao 		if (!e->record)
1924a9086adSJin Yao 			continue;
1934a9086adSJin Yao 
1945752c20fSRavi Bangoria 		if (perf_pmus__num_mem_pmus() == 1) {
1954a9086adSJin Yao 			if (!e->supported) {
1964a9086adSJin Yao 				pr_err("failed: event '%s' not supported\n",
1974a9086adSJin Yao 				       perf_mem_events__name(j, NULL));
1984a9086adSJin Yao 				return -1;
1994a9086adSJin Yao 			}
2004a9086adSJin Yao 
2014a9086adSJin Yao 			rec_argv[i++] = "-e";
2024a9086adSJin Yao 			rec_argv[i++] = perf_mem_events__name(j, NULL);
2034a9086adSJin Yao 		} else {
204650b4198SIan Rogers 			struct perf_pmu *pmu = NULL;
205650b4198SIan Rogers 
2064a9086adSJin Yao 			if (!e->supported) {
2074a9086adSJin Yao 				perf_mem_events__print_unsupport_hybrid(e, j);
2084a9086adSJin Yao 				return -1;
2094a9086adSJin Yao 			}
2104a9086adSJin Yao 
2115752c20fSRavi Bangoria 			while ((pmu = perf_pmus__scan(pmu)) != NULL) {
212c091ee90SIan Rogers 				const char *s = perf_mem_events__name(j, pmu->name);
213c091ee90SIan Rogers 
214*9cc93a61SKan Liang 				if (!perf_mem_event__supported(mnt, pmu, e))
215*9cc93a61SKan Liang 					continue;
216*9cc93a61SKan Liang 
2174a9086adSJin Yao 				rec_argv[i++] = "-e";
2184a9086adSJin Yao 				if (s) {
219c091ee90SIan Rogers 					char *copy = strdup(s);
220c091ee90SIan Rogers 					if (!copy)
2214a9086adSJin Yao 						return -1;
2224a9086adSJin Yao 
223c091ee90SIan Rogers 					rec_argv[i++] = copy;
224c091ee90SIan Rogers 					rec_tmp[k++] = copy;
2254a9086adSJin Yao 				}
2264a9086adSJin Yao 			}
2274a9086adSJin Yao 		}
2284a9086adSJin Yao 	}
2294a9086adSJin Yao 
2304a9086adSJin Yao 	*argv_nr = i;
2314a9086adSJin Yao 	*tmp_nr = k;
2324a9086adSJin Yao 	return 0;
2334a9086adSJin Yao }
2344a9086adSJin Yao 
2350c877d75SJiri Olsa static const char * const tlb_access[] = {
2360c877d75SJiri Olsa 	"N/A",
2370c877d75SJiri Olsa 	"HIT",
2380c877d75SJiri Olsa 	"MISS",
2390c877d75SJiri Olsa 	"L1",
2400c877d75SJiri Olsa 	"L2",
2410c877d75SJiri Olsa 	"Walker",
2420c877d75SJiri Olsa 	"Fault",
2430c877d75SJiri Olsa };
2440c877d75SJiri Olsa 
perf_mem__tlb_scnprintf(char * out,size_t sz,struct mem_info * mem_info)245b1a5fbeaSJiri Olsa int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
2460c877d75SJiri Olsa {
2470c877d75SJiri Olsa 	size_t l = 0, i;
2480c877d75SJiri Olsa 	u64 m = PERF_MEM_TLB_NA;
2490c877d75SJiri Olsa 	u64 hit, miss;
2500c877d75SJiri Olsa 
2510c877d75SJiri Olsa 	sz -= 1; /* -1 for null termination */
2520c877d75SJiri Olsa 	out[0] = '\0';
2530c877d75SJiri Olsa 
2540c877d75SJiri Olsa 	if (mem_info)
2550c877d75SJiri Olsa 		m = mem_info->data_src.mem_dtlb;
2560c877d75SJiri Olsa 
2570c877d75SJiri Olsa 	hit = m & PERF_MEM_TLB_HIT;
2580c877d75SJiri Olsa 	miss = m & PERF_MEM_TLB_MISS;
2590c877d75SJiri Olsa 
2600c877d75SJiri Olsa 	/* already taken care of */
2610c877d75SJiri Olsa 	m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
2620c877d75SJiri Olsa 
2630c877d75SJiri Olsa 	for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
2640c877d75SJiri Olsa 		if (!(m & 0x1))
2650c877d75SJiri Olsa 			continue;
2660c877d75SJiri Olsa 		if (l) {
2670c877d75SJiri Olsa 			strcat(out, " or ");
2680c877d75SJiri Olsa 			l += 4;
2690c877d75SJiri Olsa 		}
270b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, tlb_access[i]);
2710c877d75SJiri Olsa 	}
2720c877d75SJiri Olsa 	if (*out == '\0')
273b1a5fbeaSJiri Olsa 		l += scnprintf(out, sz - l, "N/A");
2740c877d75SJiri Olsa 	if (hit)
275b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, " hit");
2760c877d75SJiri Olsa 	if (miss)
277b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, " miss");
278b1a5fbeaSJiri Olsa 
279b1a5fbeaSJiri Olsa 	return l;
2800c877d75SJiri Olsa }
281071e9a1eSJiri Olsa 
282071e9a1eSJiri Olsa static const char * const mem_lvl[] = {
283071e9a1eSJiri Olsa 	"N/A",
284071e9a1eSJiri Olsa 	"HIT",
285071e9a1eSJiri Olsa 	"MISS",
286071e9a1eSJiri Olsa 	"L1",
287c72de116SRavi Bangoria 	"LFB/MAB",
288071e9a1eSJiri Olsa 	"L2",
289071e9a1eSJiri Olsa 	"L3",
290071e9a1eSJiri Olsa 	"Local RAM",
291071e9a1eSJiri Olsa 	"Remote RAM (1 hop)",
292071e9a1eSJiri Olsa 	"Remote RAM (2 hops)",
293071e9a1eSJiri Olsa 	"Remote Cache (1 hop)",
294071e9a1eSJiri Olsa 	"Remote Cache (2 hops)",
295071e9a1eSJiri Olsa 	"I/O",
296071e9a1eSJiri Olsa 	"Uncached",
297071e9a1eSJiri Olsa };
298071e9a1eSJiri Olsa 
29952839e65SAndi Kleen static const char * const mem_lvlnum[] = {
300d5fa7e9dSRavi Bangoria 	[PERF_MEM_LVLNUM_UNC] = "Uncached",
301923396f6SRavi Bangoria 	[PERF_MEM_LVLNUM_CXL] = "CXL",
302923396f6SRavi Bangoria 	[PERF_MEM_LVLNUM_IO] = "I/O",
30352839e65SAndi Kleen 	[PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
304c72de116SRavi Bangoria 	[PERF_MEM_LVLNUM_LFB] = "LFB/MAB",
30552839e65SAndi Kleen 	[PERF_MEM_LVLNUM_RAM] = "RAM",
30652839e65SAndi Kleen 	[PERF_MEM_LVLNUM_PMEM] = "PMEM",
30752839e65SAndi Kleen 	[PERF_MEM_LVLNUM_NA] = "N/A",
30852839e65SAndi Kleen };
30952839e65SAndi Kleen 
310cae1d759SKajol Jain static const char * const mem_hops[] = {
311cae1d759SKajol Jain 	"N/A",
312cae1d759SKajol Jain 	/*
313cae1d759SKajol Jain 	 * While printing, 'Remote' will be added to represent
314cae1d759SKajol Jain 	 * 'Remote core, same node' accesses as remote field need
315cae1d759SKajol Jain 	 * to be set with mem_hops field.
316cae1d759SKajol Jain 	 */
317cae1d759SKajol Jain 	"core, same node",
3187fbddf40SKajol Jain 	"node, same socket",
3197fbddf40SKajol Jain 	"socket, same board",
3207fbddf40SKajol Jain 	"board",
321cae1d759SKajol Jain };
322cae1d759SKajol Jain 
perf_mem__op_scnprintf(char * out,size_t sz,struct mem_info * mem_info)323fdefc375SLeo Yan static int perf_mem__op_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
324fdefc375SLeo Yan {
325fdefc375SLeo Yan 	u64 op = PERF_MEM_LOCK_NA;
326fdefc375SLeo Yan 	int l;
327fdefc375SLeo Yan 
328fdefc375SLeo Yan 	if (mem_info)
329fdefc375SLeo Yan 		op = mem_info->data_src.mem_op;
330fdefc375SLeo Yan 
331fdefc375SLeo Yan 	if (op & PERF_MEM_OP_NA)
332fdefc375SLeo Yan 		l = scnprintf(out, sz, "N/A");
333fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_LOAD)
334fdefc375SLeo Yan 		l = scnprintf(out, sz, "LOAD");
335fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_STORE)
336fdefc375SLeo Yan 		l = scnprintf(out, sz, "STORE");
337fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_PFETCH)
338fdefc375SLeo Yan 		l = scnprintf(out, sz, "PFETCH");
339fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_EXEC)
340fdefc375SLeo Yan 		l = scnprintf(out, sz, "EXEC");
341fdefc375SLeo Yan 	else
342fdefc375SLeo Yan 		l = scnprintf(out, sz, "No");
343fdefc375SLeo Yan 
344fdefc375SLeo Yan 	return l;
345fdefc375SLeo Yan }
346fdefc375SLeo Yan 
perf_mem__lvl_scnprintf(char * out,size_t sz,struct mem_info * mem_info)34796907563SJiri Olsa int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
348071e9a1eSJiri Olsa {
349ddeac198SRavi Bangoria 	union perf_mem_data_src data_src;
3507fbddf40SKajol Jain 	int printed = 0;
351ddeac198SRavi Bangoria 	size_t l = 0;
352ddeac198SRavi Bangoria 	size_t i;
353ddeac198SRavi Bangoria 	int lvl;
354ddeac198SRavi Bangoria 	char hit_miss[5] = {0};
355071e9a1eSJiri Olsa 
356071e9a1eSJiri Olsa 	sz -= 1; /* -1 for null termination */
357071e9a1eSJiri Olsa 	out[0] = '\0';
358071e9a1eSJiri Olsa 
359ddeac198SRavi Bangoria 	if (!mem_info)
360ddeac198SRavi Bangoria 		goto na;
361071e9a1eSJiri Olsa 
362ddeac198SRavi Bangoria 	data_src = mem_info->data_src;
363071e9a1eSJiri Olsa 
364ddeac198SRavi Bangoria 	if (data_src.mem_lvl & PERF_MEM_LVL_HIT)
365ddeac198SRavi Bangoria 		memcpy(hit_miss, "hit", 3);
366ddeac198SRavi Bangoria 	else if (data_src.mem_lvl & PERF_MEM_LVL_MISS)
367ddeac198SRavi Bangoria 		memcpy(hit_miss, "miss", 4);
368ddeac198SRavi Bangoria 
369ddeac198SRavi Bangoria 	lvl = data_src.mem_lvl_num;
370ddeac198SRavi Bangoria 	if (lvl && lvl != PERF_MEM_LVLNUM_NA) {
371ddeac198SRavi Bangoria 		if (data_src.mem_remote) {
37252839e65SAndi Kleen 			strcat(out, "Remote ");
37352839e65SAndi Kleen 			l += 7;
37452839e65SAndi Kleen 		}
37552839e65SAndi Kleen 
376ddeac198SRavi Bangoria 		if (data_src.mem_hops)
377ddeac198SRavi Bangoria 			l += scnprintf(out + l, sz - l, "%s ", mem_hops[data_src.mem_hops]);
378ddeac198SRavi Bangoria 
379ddeac198SRavi Bangoria 		if (mem_lvlnum[lvl])
380ddeac198SRavi Bangoria 			l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
381ddeac198SRavi Bangoria 		else
382ddeac198SRavi Bangoria 			l += scnprintf(out + l, sz - l, "L%d", lvl);
383ddeac198SRavi Bangoria 
384ddeac198SRavi Bangoria 		l += scnprintf(out + l, sz - l, " %s", hit_miss);
385ddeac198SRavi Bangoria 		return l;
386ddeac198SRavi Bangoria 	}
387ddeac198SRavi Bangoria 
388ddeac198SRavi Bangoria 	lvl = data_src.mem_lvl;
389ddeac198SRavi Bangoria 	if (!lvl)
390ddeac198SRavi Bangoria 		goto na;
391ddeac198SRavi Bangoria 
392ddeac198SRavi Bangoria 	lvl &= ~(PERF_MEM_LVL_NA | PERF_MEM_LVL_HIT | PERF_MEM_LVL_MISS);
393ddeac198SRavi Bangoria 	if (!lvl)
394ddeac198SRavi Bangoria 		goto na;
395ddeac198SRavi Bangoria 
396ddeac198SRavi Bangoria 	for (i = 0; lvl && i < ARRAY_SIZE(mem_lvl); i++, lvl >>= 1) {
397ddeac198SRavi Bangoria 		if (!(lvl & 0x1))
398071e9a1eSJiri Olsa 			continue;
39952839e65SAndi Kleen 		if (printed++) {
400071e9a1eSJiri Olsa 			strcat(out, " or ");
401071e9a1eSJiri Olsa 			l += 4;
402071e9a1eSJiri Olsa 		}
40396907563SJiri Olsa 		l += scnprintf(out + l, sz - l, mem_lvl[i]);
404071e9a1eSJiri Olsa 	}
40552839e65SAndi Kleen 
406ddeac198SRavi Bangoria 	if (printed) {
407ddeac198SRavi Bangoria 		l += scnprintf(out + l, sz - l, " %s", hit_miss);
40896907563SJiri Olsa 		return l;
409071e9a1eSJiri Olsa 	}
4102c07af13SJiri Olsa 
411ddeac198SRavi Bangoria na:
412ddeac198SRavi Bangoria 	strcat(out, "N/A");
413ddeac198SRavi Bangoria 	return 3;
414ddeac198SRavi Bangoria }
415ddeac198SRavi Bangoria 
4162c07af13SJiri Olsa static const char * const snoop_access[] = {
4172c07af13SJiri Olsa 	"N/A",
4182c07af13SJiri Olsa 	"None",
4192c07af13SJiri Olsa 	"Hit",
420166ebdd2SAndi Kleen 	"Miss",
4212c07af13SJiri Olsa 	"HitM",
4222c07af13SJiri Olsa };
4232c07af13SJiri Olsa 
424f78d6250SLeo Yan static const char * const snoopx_access[] = {
425f78d6250SLeo Yan 	"Fwd",
426f78d6250SLeo Yan 	"Peer",
427f78d6250SLeo Yan };
428f78d6250SLeo Yan 
perf_mem__snp_scnprintf(char * out,size_t sz,struct mem_info * mem_info)429149d7507SJiri Olsa int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
4302c07af13SJiri Olsa {
4312c07af13SJiri Olsa 	size_t i, l = 0;
4322c07af13SJiri Olsa 	u64 m = PERF_MEM_SNOOP_NA;
4332c07af13SJiri Olsa 
4342c07af13SJiri Olsa 	sz -= 1; /* -1 for null termination */
4352c07af13SJiri Olsa 	out[0] = '\0';
4362c07af13SJiri Olsa 
4372c07af13SJiri Olsa 	if (mem_info)
4382c07af13SJiri Olsa 		m = mem_info->data_src.mem_snoop;
4392c07af13SJiri Olsa 
4402c07af13SJiri Olsa 	for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
4412c07af13SJiri Olsa 		if (!(m & 0x1))
4422c07af13SJiri Olsa 			continue;
4432c07af13SJiri Olsa 		if (l) {
4442c07af13SJiri Olsa 			strcat(out, " or ");
4452c07af13SJiri Olsa 			l += 4;
4462c07af13SJiri Olsa 		}
447149d7507SJiri Olsa 		l += scnprintf(out + l, sz - l, snoop_access[i]);
4482c07af13SJiri Olsa 	}
449f78d6250SLeo Yan 
450f78d6250SLeo Yan 	m = 0;
451f78d6250SLeo Yan 	if (mem_info)
452f78d6250SLeo Yan 		m = mem_info->data_src.mem_snoopx;
453f78d6250SLeo Yan 
454f78d6250SLeo Yan 	for (i = 0; m && i < ARRAY_SIZE(snoopx_access); i++, m >>= 1) {
455f78d6250SLeo Yan 		if (!(m & 0x1))
456f78d6250SLeo Yan 			continue;
457f78d6250SLeo Yan 
45852839e65SAndi Kleen 		if (l) {
45952839e65SAndi Kleen 			strcat(out, " or ");
46052839e65SAndi Kleen 			l += 4;
46152839e65SAndi Kleen 		}
462f78d6250SLeo Yan 		l += scnprintf(out + l, sz - l, snoopx_access[i]);
46352839e65SAndi Kleen 	}
4642c07af13SJiri Olsa 
4652c07af13SJiri Olsa 	if (*out == '\0')
466149d7507SJiri Olsa 		l += scnprintf(out, sz - l, "N/A");
467149d7507SJiri Olsa 
468149d7507SJiri Olsa 	return l;
4692c07af13SJiri Olsa }
47069a77275SJiri Olsa 
perf_mem__lck_scnprintf(char * out,size_t sz,struct mem_info * mem_info)4718b0819c8SJiri Olsa int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
47269a77275SJiri Olsa {
47369a77275SJiri Olsa 	u64 mask = PERF_MEM_LOCK_NA;
4748b0819c8SJiri Olsa 	int l;
47569a77275SJiri Olsa 
47669a77275SJiri Olsa 	if (mem_info)
47769a77275SJiri Olsa 		mask = mem_info->data_src.mem_lock;
47869a77275SJiri Olsa 
47969a77275SJiri Olsa 	if (mask & PERF_MEM_LOCK_NA)
4808b0819c8SJiri Olsa 		l = scnprintf(out, sz, "N/A");
48169a77275SJiri Olsa 	else if (mask & PERF_MEM_LOCK_LOCKED)
4828b0819c8SJiri Olsa 		l = scnprintf(out, sz, "Yes");
48369a77275SJiri Olsa 	else
4848b0819c8SJiri Olsa 		l = scnprintf(out, sz, "No");
4858b0819c8SJiri Olsa 
4868b0819c8SJiri Olsa 	return l;
48769a77275SJiri Olsa }
488c19ac912SJiri Olsa 
perf_mem__blk_scnprintf(char * out,size_t sz,struct mem_info * mem_info)489a054c298SKan Liang int perf_mem__blk_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
490a054c298SKan Liang {
491a054c298SKan Liang 	size_t l = 0;
492a054c298SKan Liang 	u64 mask = PERF_MEM_BLK_NA;
493a054c298SKan Liang 
494a054c298SKan Liang 	sz -= 1; /* -1 for null termination */
495a054c298SKan Liang 	out[0] = '\0';
496a054c298SKan Liang 
497a054c298SKan Liang 	if (mem_info)
498a054c298SKan Liang 		mask = mem_info->data_src.mem_blk;
499a054c298SKan Liang 
500a054c298SKan Liang 	if (!mask || (mask & PERF_MEM_BLK_NA)) {
501a054c298SKan Liang 		l += scnprintf(out + l, sz - l, " N/A");
502a054c298SKan Liang 		return l;
503a054c298SKan Liang 	}
504a054c298SKan Liang 	if (mask & PERF_MEM_BLK_DATA)
505a054c298SKan Liang 		l += scnprintf(out + l, sz - l, " Data");
506a054c298SKan Liang 	if (mask & PERF_MEM_BLK_ADDR)
507a054c298SKan Liang 		l += scnprintf(out + l, sz - l, " Addr");
508a054c298SKan Liang 
509a054c298SKan Liang 	return l;
510a054c298SKan Liang }
511a054c298SKan Liang 
perf_script__meminfo_scnprintf(char * out,size_t sz,struct mem_info * mem_info)512c19ac912SJiri Olsa int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
513c19ac912SJiri Olsa {
514c19ac912SJiri Olsa 	int i = 0;
515c19ac912SJiri Olsa 
516fdefc375SLeo Yan 	i += scnprintf(out, sz, "|OP ");
517fdefc375SLeo Yan 	i += perf_mem__op_scnprintf(out + i, sz - i, mem_info);
518fdefc375SLeo Yan 	i += scnprintf(out + i, sz - i, "|LVL ");
519fdefc375SLeo Yan 	i += perf_mem__lvl_scnprintf(out + i, sz, mem_info);
520c19ac912SJiri Olsa 	i += scnprintf(out + i, sz - i, "|SNP ");
521c19ac912SJiri Olsa 	i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
522c19ac912SJiri Olsa 	i += scnprintf(out + i, sz - i, "|TLB ");
523c19ac912SJiri Olsa 	i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
524c19ac912SJiri Olsa 	i += scnprintf(out + i, sz - i, "|LCK ");
525c19ac912SJiri Olsa 	i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
526a054c298SKan Liang 	i += scnprintf(out + i, sz - i, "|BLK ");
527a054c298SKan Liang 	i += perf_mem__blk_scnprintf(out + i, sz - i, mem_info);
528c19ac912SJiri Olsa 
529c19ac912SJiri Olsa 	return i;
530c19ac912SJiri Olsa }
531aadddd68SJiri Olsa 
c2c_decode_stats(struct c2c_stats * stats,struct mem_info * mi)532aadddd68SJiri Olsa int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
533aadddd68SJiri Olsa {
534aadddd68SJiri Olsa 	union perf_mem_data_src *data_src = &mi->data_src;
535aadddd68SJiri Olsa 	u64 daddr  = mi->daddr.addr;
536aadddd68SJiri Olsa 	u64 op     = data_src->mem_op;
537aadddd68SJiri Olsa 	u64 lvl    = data_src->mem_lvl;
538aadddd68SJiri Olsa 	u64 snoop  = data_src->mem_snoop;
539e843dec5SLeo Yan 	u64 snoopx = data_src->mem_snoopx;
540aadddd68SJiri Olsa 	u64 lock   = data_src->mem_lock;
541d9d5d767SKan Liang 	u64 blk    = data_src->mem_blk;
54212c15302SJiri Olsa 	/*
54312c15302SJiri Olsa 	 * Skylake might report unknown remote level via this
54412c15302SJiri Olsa 	 * bit, consider it when evaluating remote HITMs.
545cae1d759SKajol Jain 	 *
546cae1d759SKajol Jain 	 * Incase of power, remote field can also be used to denote cache
547cae1d759SKajol Jain 	 * accesses from the another core of same node. Hence, setting
548cae1d759SKajol Jain 	 * mrem only when HOPS is zero along with set remote field.
54912c15302SJiri Olsa 	 */
550cae1d759SKajol Jain 	bool mrem  = (data_src->mem_remote && !data_src->mem_hops);
551aadddd68SJiri Olsa 	int err = 0;
552aadddd68SJiri Olsa 
553dba8ab93SJiri Olsa #define HITM_INC(__f)		\
554dba8ab93SJiri Olsa do {				\
555dba8ab93SJiri Olsa 	stats->__f++;		\
556dba8ab93SJiri Olsa 	stats->tot_hitm++;	\
557dba8ab93SJiri Olsa } while (0)
558dba8ab93SJiri Olsa 
559e843dec5SLeo Yan #define PEER_INC(__f)		\
560e843dec5SLeo Yan do {				\
561e843dec5SLeo Yan 	stats->__f++;		\
562e843dec5SLeo Yan 	stats->tot_peer++;	\
563e843dec5SLeo Yan } while (0)
564e843dec5SLeo Yan 
565aadddd68SJiri Olsa #define P(a, b) PERF_MEM_##a##_##b
566aadddd68SJiri Olsa 
567aadddd68SJiri Olsa 	stats->nr_entries++;
568aadddd68SJiri Olsa 
569aadddd68SJiri Olsa 	if (lock & P(LOCK, LOCKED)) stats->locks++;
570aadddd68SJiri Olsa 
571d9d5d767SKan Liang 	if (blk & P(BLK, DATA)) stats->blk_data++;
572d9d5d767SKan Liang 	if (blk & P(BLK, ADDR)) stats->blk_addr++;
573d9d5d767SKan Liang 
574aadddd68SJiri Olsa 	if (op & P(OP, LOAD)) {
575aadddd68SJiri Olsa 		/* load */
576aadddd68SJiri Olsa 		stats->load++;
577aadddd68SJiri Olsa 
578aadddd68SJiri Olsa 		if (!daddr) {
579aadddd68SJiri Olsa 			stats->ld_noadrs++;
580aadddd68SJiri Olsa 			return -1;
581aadddd68SJiri Olsa 		}
582aadddd68SJiri Olsa 
583aadddd68SJiri Olsa 		if (lvl & P(LVL, HIT)) {
584aadddd68SJiri Olsa 			if (lvl & P(LVL, UNC)) stats->ld_uncache++;
585aadddd68SJiri Olsa 			if (lvl & P(LVL, IO))  stats->ld_io++;
586aadddd68SJiri Olsa 			if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
587aadddd68SJiri Olsa 			if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
588e843dec5SLeo Yan 			if (lvl & P(LVL, L2)) {
589e843dec5SLeo Yan 				stats->ld_l2hit++;
590e843dec5SLeo Yan 
591e843dec5SLeo Yan 				if (snoopx & P(SNOOPX, PEER))
592e843dec5SLeo Yan 					PEER_INC(lcl_peer);
593e843dec5SLeo Yan 			}
594aadddd68SJiri Olsa 			if (lvl & P(LVL, L3 )) {
595aadddd68SJiri Olsa 				if (snoop & P(SNOOP, HITM))
596dba8ab93SJiri Olsa 					HITM_INC(lcl_hitm);
597aadddd68SJiri Olsa 				else
598aadddd68SJiri Olsa 					stats->ld_llchit++;
599e843dec5SLeo Yan 
600e843dec5SLeo Yan 				if (snoopx & P(SNOOPX, PEER))
601e843dec5SLeo Yan 					PEER_INC(lcl_peer);
602aadddd68SJiri Olsa 			}
603aadddd68SJiri Olsa 
604aadddd68SJiri Olsa 			if (lvl & P(LVL, LOC_RAM)) {
605aadddd68SJiri Olsa 				stats->lcl_dram++;
606aadddd68SJiri Olsa 				if (snoop & P(SNOOP, HIT))
607aadddd68SJiri Olsa 					stats->ld_shared++;
608aadddd68SJiri Olsa 				else
609aadddd68SJiri Olsa 					stats->ld_excl++;
610aadddd68SJiri Olsa 			}
611aadddd68SJiri Olsa 
612aadddd68SJiri Olsa 			if ((lvl & P(LVL, REM_RAM1)) ||
61312c15302SJiri Olsa 			    (lvl & P(LVL, REM_RAM2)) ||
61412c15302SJiri Olsa 			     mrem) {
615aadddd68SJiri Olsa 				stats->rmt_dram++;
616aadddd68SJiri Olsa 				if (snoop & P(SNOOP, HIT))
617aadddd68SJiri Olsa 					stats->ld_shared++;
618aadddd68SJiri Olsa 				else
619aadddd68SJiri Olsa 					stats->ld_excl++;
620aadddd68SJiri Olsa 			}
621aadddd68SJiri Olsa 		}
622aadddd68SJiri Olsa 
623aadddd68SJiri Olsa 		if ((lvl & P(LVL, REM_CCE1)) ||
62412c15302SJiri Olsa 		    (lvl & P(LVL, REM_CCE2)) ||
62512c15302SJiri Olsa 		     mrem) {
626e843dec5SLeo Yan 			if (snoop & P(SNOOP, HIT)) {
627aadddd68SJiri Olsa 				stats->rmt_hit++;
628e843dec5SLeo Yan 			} else if (snoop & P(SNOOP, HITM)) {
629dba8ab93SJiri Olsa 				HITM_INC(rmt_hitm);
630e843dec5SLeo Yan 			} else if (snoopx & P(SNOOPX, PEER)) {
631e843dec5SLeo Yan 				stats->rmt_hit++;
632e843dec5SLeo Yan 				PEER_INC(rmt_peer);
633e843dec5SLeo Yan 			}
634aadddd68SJiri Olsa 		}
635aadddd68SJiri Olsa 
636aadddd68SJiri Olsa 		if ((lvl & P(LVL, MISS)))
637aadddd68SJiri Olsa 			stats->ld_miss++;
638aadddd68SJiri Olsa 
639aadddd68SJiri Olsa 	} else if (op & P(OP, STORE)) {
640aadddd68SJiri Olsa 		/* store */
641aadddd68SJiri Olsa 		stats->store++;
642aadddd68SJiri Olsa 
643aadddd68SJiri Olsa 		if (!daddr) {
644aadddd68SJiri Olsa 			stats->st_noadrs++;
645aadddd68SJiri Olsa 			return -1;
646aadddd68SJiri Olsa 		}
647aadddd68SJiri Olsa 
648aadddd68SJiri Olsa 		if (lvl & P(LVL, HIT)) {
649aadddd68SJiri Olsa 			if (lvl & P(LVL, UNC)) stats->st_uncache++;
650aadddd68SJiri Olsa 			if (lvl & P(LVL, L1 )) stats->st_l1hit++;
651aadddd68SJiri Olsa 		}
652aadddd68SJiri Olsa 		if (lvl & P(LVL, MISS))
653aadddd68SJiri Olsa 			if (lvl & P(LVL, L1)) stats->st_l1miss++;
65498450637SLeo Yan 		if (lvl & P(LVL, NA))
65598450637SLeo Yan 			stats->st_na++;
656aadddd68SJiri Olsa 	} else {
657aadddd68SJiri Olsa 		/* unparsable data_src? */
658aadddd68SJiri Olsa 		stats->noparse++;
659aadddd68SJiri Olsa 		return -1;
660aadddd68SJiri Olsa 	}
661aadddd68SJiri Olsa 
662d46a4cdfSArnaldo Carvalho de Melo 	if (!mi->daddr.ms.map || !mi->iaddr.ms.map) {
663aadddd68SJiri Olsa 		stats->nomap++;
664aadddd68SJiri Olsa 		return -1;
665aadddd68SJiri Olsa 	}
666aadddd68SJiri Olsa 
667aadddd68SJiri Olsa #undef P
668dba8ab93SJiri Olsa #undef HITM_INC
669aadddd68SJiri Olsa 	return err;
670aadddd68SJiri Olsa }
6710a9a24ccSJiri Olsa 
c2c_add_stats(struct c2c_stats * stats,struct c2c_stats * add)6720a9a24ccSJiri Olsa void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
6730a9a24ccSJiri Olsa {
6740a9a24ccSJiri Olsa 	stats->nr_entries	+= add->nr_entries;
6750a9a24ccSJiri Olsa 
6760a9a24ccSJiri Olsa 	stats->locks		+= add->locks;
6770a9a24ccSJiri Olsa 	stats->store		+= add->store;
6780a9a24ccSJiri Olsa 	stats->st_uncache	+= add->st_uncache;
6790a9a24ccSJiri Olsa 	stats->st_noadrs	+= add->st_noadrs;
6800a9a24ccSJiri Olsa 	stats->st_l1hit		+= add->st_l1hit;
6810a9a24ccSJiri Olsa 	stats->st_l1miss	+= add->st_l1miss;
68298450637SLeo Yan 	stats->st_na		+= add->st_na;
6830a9a24ccSJiri Olsa 	stats->load		+= add->load;
6840a9a24ccSJiri Olsa 	stats->ld_excl		+= add->ld_excl;
6850a9a24ccSJiri Olsa 	stats->ld_shared	+= add->ld_shared;
6860a9a24ccSJiri Olsa 	stats->ld_uncache	+= add->ld_uncache;
6870a9a24ccSJiri Olsa 	stats->ld_io		+= add->ld_io;
6880a9a24ccSJiri Olsa 	stats->ld_miss		+= add->ld_miss;
6890a9a24ccSJiri Olsa 	stats->ld_noadrs	+= add->ld_noadrs;
6900a9a24ccSJiri Olsa 	stats->ld_fbhit		+= add->ld_fbhit;
6910a9a24ccSJiri Olsa 	stats->ld_l1hit		+= add->ld_l1hit;
6920a9a24ccSJiri Olsa 	stats->ld_l2hit		+= add->ld_l2hit;
6930a9a24ccSJiri Olsa 	stats->ld_llchit	+= add->ld_llchit;
6940a9a24ccSJiri Olsa 	stats->lcl_hitm		+= add->lcl_hitm;
6950a9a24ccSJiri Olsa 	stats->rmt_hitm		+= add->rmt_hitm;
696dba8ab93SJiri Olsa 	stats->tot_hitm		+= add->tot_hitm;
697e843dec5SLeo Yan 	stats->lcl_peer		+= add->lcl_peer;
698e843dec5SLeo Yan 	stats->rmt_peer		+= add->rmt_peer;
699e843dec5SLeo Yan 	stats->tot_peer		+= add->tot_peer;
7000a9a24ccSJiri Olsa 	stats->rmt_hit		+= add->rmt_hit;
7010a9a24ccSJiri Olsa 	stats->lcl_dram		+= add->lcl_dram;
7020a9a24ccSJiri Olsa 	stats->rmt_dram		+= add->rmt_dram;
703d9d5d767SKan Liang 	stats->blk_data		+= add->blk_data;
704d9d5d767SKan Liang 	stats->blk_addr		+= add->blk_addr;
7050a9a24ccSJiri Olsa 	stats->nomap		+= add->nomap;
7060a9a24ccSJiri Olsa 	stats->noparse		+= add->noparse;
7070a9a24ccSJiri Olsa }
708