xref: /openbmc/linux/tools/perf/util/mem-events.c (revision 98450637)
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"
16e7ce8d11SJin Yao #include "pmu-hybrid.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 
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 
40d2f327acSJin Yao char * __weak perf_mem_events__name(int i, 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 
56eaf6aaeeSLeo Yan 	return (char *)e->name;
572ba7ac58SJiri Olsa }
582ba7ac58SJiri Olsa 
592a57d408SKan Liang __weak bool is_mem_loads_aux_event(struct evsel *leader __maybe_unused)
602a57d408SKan Liang {
612a57d408SKan Liang 	return false;
622a57d408SKan Liang }
632a57d408SKan Liang 
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 
103e7ce8d11SJin Yao static bool perf_mem_event__supported(const char *mnt, char *sysfs_name)
104e7ce8d11SJin Yao {
105e7ce8d11SJin Yao 	char path[PATH_MAX];
106e7ce8d11SJin Yao 	struct stat st;
107e7ce8d11SJin Yao 
108e7ce8d11SJin Yao 	scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name);
109e7ce8d11SJin Yao 	return !stat(path, &st);
110e7ce8d11SJin Yao }
111e7ce8d11SJin Yao 
11254fbad54SJiri Olsa int perf_mem_events__init(void)
11354fbad54SJiri Olsa {
11454fbad54SJiri Olsa 	const char *mnt = sysfs__mount();
11554fbad54SJiri Olsa 	bool found = false;
11654fbad54SJiri Olsa 	int j;
11754fbad54SJiri Olsa 
11854fbad54SJiri Olsa 	if (!mnt)
11954fbad54SJiri Olsa 		return -ENOENT;
12054fbad54SJiri Olsa 
12154fbad54SJiri Olsa 	for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
122eaf6aaeeSLeo Yan 		struct perf_mem_event *e = perf_mem_events__ptr(j);
123e7ce8d11SJin Yao 		struct perf_pmu *pmu;
124e7ce8d11SJin Yao 		char sysfs_name[100];
12554fbad54SJiri Olsa 
1264ba2452cSLeo Yan 		/*
1274ba2452cSLeo Yan 		 * If the event entry isn't valid, skip initialization
1284ba2452cSLeo Yan 		 * and "e->supported" will keep false.
1294ba2452cSLeo Yan 		 */
1304ba2452cSLeo Yan 		if (!e->tag)
1314ba2452cSLeo Yan 			continue;
1324ba2452cSLeo Yan 
133e7ce8d11SJin Yao 		if (!perf_pmu__has_hybrid()) {
134e7ce8d11SJin Yao 			scnprintf(sysfs_name, sizeof(sysfs_name),
135e7ce8d11SJin Yao 				  e->sysfs_name, "cpu");
136e7ce8d11SJin Yao 			e->supported = perf_mem_event__supported(mnt, sysfs_name);
137e7ce8d11SJin Yao 		} else {
138e7ce8d11SJin Yao 			perf_pmu__for_each_hybrid_pmu(pmu) {
139e7ce8d11SJin Yao 				scnprintf(sysfs_name, sizeof(sysfs_name),
140e7ce8d11SJin Yao 					  e->sysfs_name, pmu->name);
141e7ce8d11SJin Yao 				e->supported |= perf_mem_event__supported(mnt, sysfs_name);
142e7ce8d11SJin Yao 			}
143e7ce8d11SJin Yao 		}
14454fbad54SJiri Olsa 
145e7ce8d11SJin Yao 		if (e->supported)
146e7ce8d11SJin Yao 			found = true;
14754fbad54SJiri Olsa 	}
14854fbad54SJiri Olsa 
14954fbad54SJiri Olsa 	return found ? 0 : -ENOENT;
15054fbad54SJiri Olsa }
1510c877d75SJiri Olsa 
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 
159b027cc6fSIan Rogers 		fprintf(stderr, "%-13s%-*s%s\n",
1604ba2452cSLeo Yan 			e->tag ?: "",
161b027cc6fSIan Rogers 			verbose > 0 ? 25 : 0,
162d2f327acSJin Yao 			verbose > 0 ? perf_mem_events__name(j, NULL) : "",
163b027cc6fSIan Rogers 			e->supported ? ": available" : "");
164b027cc6fSIan Rogers 	}
165b027cc6fSIan Rogers }
166b027cc6fSIan Rogers 
1674a9086adSJin Yao static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e,
1684a9086adSJin Yao 						    int idx)
1694a9086adSJin Yao {
1704a9086adSJin Yao 	const char *mnt = sysfs__mount();
1714a9086adSJin Yao 	char sysfs_name[100];
1724a9086adSJin Yao 	struct perf_pmu *pmu;
1734a9086adSJin Yao 
1744a9086adSJin Yao 	perf_pmu__for_each_hybrid_pmu(pmu) {
1754a9086adSJin Yao 		scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name,
1764a9086adSJin Yao 			  pmu->name);
1774a9086adSJin Yao 		if (!perf_mem_event__supported(mnt, sysfs_name)) {
1784a9086adSJin Yao 			pr_err("failed: event '%s' not supported\n",
1794a9086adSJin Yao 			       perf_mem_events__name(idx, pmu->name));
1804a9086adSJin Yao 		}
1814a9086adSJin Yao 	}
1824a9086adSJin Yao }
1834a9086adSJin Yao 
1844a9086adSJin Yao int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
1854a9086adSJin Yao 				 char **rec_tmp, int *tmp_nr)
1864a9086adSJin Yao {
1874a9086adSJin Yao 	int i = *argv_nr, k = 0;
1884a9086adSJin Yao 	struct perf_mem_event *e;
1894a9086adSJin Yao 	struct perf_pmu *pmu;
1904a9086adSJin Yao 	char *s;
1914a9086adSJin Yao 
1924a9086adSJin Yao 	for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
1934a9086adSJin Yao 		e = perf_mem_events__ptr(j);
1944a9086adSJin Yao 		if (!e->record)
1954a9086adSJin Yao 			continue;
1964a9086adSJin Yao 
1974a9086adSJin Yao 		if (!perf_pmu__has_hybrid()) {
1984a9086adSJin Yao 			if (!e->supported) {
1994a9086adSJin Yao 				pr_err("failed: event '%s' not supported\n",
2004a9086adSJin Yao 				       perf_mem_events__name(j, NULL));
2014a9086adSJin Yao 				return -1;
2024a9086adSJin Yao 			}
2034a9086adSJin Yao 
2044a9086adSJin Yao 			rec_argv[i++] = "-e";
2054a9086adSJin Yao 			rec_argv[i++] = perf_mem_events__name(j, NULL);
2064a9086adSJin Yao 		} else {
2074a9086adSJin Yao 			if (!e->supported) {
2084a9086adSJin Yao 				perf_mem_events__print_unsupport_hybrid(e, j);
2094a9086adSJin Yao 				return -1;
2104a9086adSJin Yao 			}
2114a9086adSJin Yao 
2124a9086adSJin Yao 			perf_pmu__for_each_hybrid_pmu(pmu) {
2134a9086adSJin Yao 				rec_argv[i++] = "-e";
2144a9086adSJin Yao 				s = perf_mem_events__name(j, pmu->name);
2154a9086adSJin Yao 				if (s) {
2164a9086adSJin Yao 					s = strdup(s);
2174a9086adSJin Yao 					if (!s)
2184a9086adSJin Yao 						return -1;
2194a9086adSJin Yao 
2204a9086adSJin Yao 					rec_argv[i++] = s;
2214a9086adSJin Yao 					rec_tmp[k++] = s;
2224a9086adSJin Yao 				}
2234a9086adSJin Yao 			}
2244a9086adSJin Yao 		}
2254a9086adSJin Yao 	}
2264a9086adSJin Yao 
2274a9086adSJin Yao 	*argv_nr = i;
2284a9086adSJin Yao 	*tmp_nr = k;
2294a9086adSJin Yao 	return 0;
2304a9086adSJin Yao }
2314a9086adSJin Yao 
2320c877d75SJiri Olsa static const char * const tlb_access[] = {
2330c877d75SJiri Olsa 	"N/A",
2340c877d75SJiri Olsa 	"HIT",
2350c877d75SJiri Olsa 	"MISS",
2360c877d75SJiri Olsa 	"L1",
2370c877d75SJiri Olsa 	"L2",
2380c877d75SJiri Olsa 	"Walker",
2390c877d75SJiri Olsa 	"Fault",
2400c877d75SJiri Olsa };
2410c877d75SJiri Olsa 
242b1a5fbeaSJiri Olsa int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
2430c877d75SJiri Olsa {
2440c877d75SJiri Olsa 	size_t l = 0, i;
2450c877d75SJiri Olsa 	u64 m = PERF_MEM_TLB_NA;
2460c877d75SJiri Olsa 	u64 hit, miss;
2470c877d75SJiri Olsa 
2480c877d75SJiri Olsa 	sz -= 1; /* -1 for null termination */
2490c877d75SJiri Olsa 	out[0] = '\0';
2500c877d75SJiri Olsa 
2510c877d75SJiri Olsa 	if (mem_info)
2520c877d75SJiri Olsa 		m = mem_info->data_src.mem_dtlb;
2530c877d75SJiri Olsa 
2540c877d75SJiri Olsa 	hit = m & PERF_MEM_TLB_HIT;
2550c877d75SJiri Olsa 	miss = m & PERF_MEM_TLB_MISS;
2560c877d75SJiri Olsa 
2570c877d75SJiri Olsa 	/* already taken care of */
2580c877d75SJiri Olsa 	m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
2590c877d75SJiri Olsa 
2600c877d75SJiri Olsa 	for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
2610c877d75SJiri Olsa 		if (!(m & 0x1))
2620c877d75SJiri Olsa 			continue;
2630c877d75SJiri Olsa 		if (l) {
2640c877d75SJiri Olsa 			strcat(out, " or ");
2650c877d75SJiri Olsa 			l += 4;
2660c877d75SJiri Olsa 		}
267b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, tlb_access[i]);
2680c877d75SJiri Olsa 	}
2690c877d75SJiri Olsa 	if (*out == '\0')
270b1a5fbeaSJiri Olsa 		l += scnprintf(out, sz - l, "N/A");
2710c877d75SJiri Olsa 	if (hit)
272b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, " hit");
2730c877d75SJiri Olsa 	if (miss)
274b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, " miss");
275b1a5fbeaSJiri Olsa 
276b1a5fbeaSJiri Olsa 	return l;
2770c877d75SJiri Olsa }
278071e9a1eSJiri Olsa 
279071e9a1eSJiri Olsa static const char * const mem_lvl[] = {
280071e9a1eSJiri Olsa 	"N/A",
281071e9a1eSJiri Olsa 	"HIT",
282071e9a1eSJiri Olsa 	"MISS",
283071e9a1eSJiri Olsa 	"L1",
284071e9a1eSJiri Olsa 	"LFB",
285071e9a1eSJiri Olsa 	"L2",
286071e9a1eSJiri Olsa 	"L3",
287071e9a1eSJiri Olsa 	"Local RAM",
288071e9a1eSJiri Olsa 	"Remote RAM (1 hop)",
289071e9a1eSJiri Olsa 	"Remote RAM (2 hops)",
290071e9a1eSJiri Olsa 	"Remote Cache (1 hop)",
291071e9a1eSJiri Olsa 	"Remote Cache (2 hops)",
292071e9a1eSJiri Olsa 	"I/O",
293071e9a1eSJiri Olsa 	"Uncached",
294071e9a1eSJiri Olsa };
295071e9a1eSJiri Olsa 
29652839e65SAndi Kleen static const char * const mem_lvlnum[] = {
29752839e65SAndi Kleen 	[PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
29852839e65SAndi Kleen 	[PERF_MEM_LVLNUM_LFB] = "LFB",
29952839e65SAndi Kleen 	[PERF_MEM_LVLNUM_RAM] = "RAM",
30052839e65SAndi Kleen 	[PERF_MEM_LVLNUM_PMEM] = "PMEM",
30152839e65SAndi Kleen 	[PERF_MEM_LVLNUM_NA] = "N/A",
30252839e65SAndi Kleen };
30352839e65SAndi Kleen 
304cae1d759SKajol Jain static const char * const mem_hops[] = {
305cae1d759SKajol Jain 	"N/A",
306cae1d759SKajol Jain 	/*
307cae1d759SKajol Jain 	 * While printing, 'Remote' will be added to represent
308cae1d759SKajol Jain 	 * 'Remote core, same node' accesses as remote field need
309cae1d759SKajol Jain 	 * to be set with mem_hops field.
310cae1d759SKajol Jain 	 */
311cae1d759SKajol Jain 	"core, same node",
3127fbddf40SKajol Jain 	"node, same socket",
3137fbddf40SKajol Jain 	"socket, same board",
3147fbddf40SKajol Jain 	"board",
315cae1d759SKajol Jain };
316cae1d759SKajol Jain 
317fdefc375SLeo Yan static int perf_mem__op_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
318fdefc375SLeo Yan {
319fdefc375SLeo Yan 	u64 op = PERF_MEM_LOCK_NA;
320fdefc375SLeo Yan 	int l;
321fdefc375SLeo Yan 
322fdefc375SLeo Yan 	if (mem_info)
323fdefc375SLeo Yan 		op = mem_info->data_src.mem_op;
324fdefc375SLeo Yan 
325fdefc375SLeo Yan 	if (op & PERF_MEM_OP_NA)
326fdefc375SLeo Yan 		l = scnprintf(out, sz, "N/A");
327fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_LOAD)
328fdefc375SLeo Yan 		l = scnprintf(out, sz, "LOAD");
329fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_STORE)
330fdefc375SLeo Yan 		l = scnprintf(out, sz, "STORE");
331fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_PFETCH)
332fdefc375SLeo Yan 		l = scnprintf(out, sz, "PFETCH");
333fdefc375SLeo Yan 	else if (op & PERF_MEM_OP_EXEC)
334fdefc375SLeo Yan 		l = scnprintf(out, sz, "EXEC");
335fdefc375SLeo Yan 	else
336fdefc375SLeo Yan 		l = scnprintf(out, sz, "No");
337fdefc375SLeo Yan 
338fdefc375SLeo Yan 	return l;
339fdefc375SLeo Yan }
340fdefc375SLeo Yan 
34196907563SJiri Olsa int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
342071e9a1eSJiri Olsa {
343071e9a1eSJiri Olsa 	size_t i, l = 0;
344071e9a1eSJiri Olsa 	u64 m =  PERF_MEM_LVL_NA;
345071e9a1eSJiri Olsa 	u64 hit, miss;
3467fbddf40SKajol Jain 	int printed = 0;
347071e9a1eSJiri Olsa 
348071e9a1eSJiri Olsa 	if (mem_info)
349071e9a1eSJiri Olsa 		m  = mem_info->data_src.mem_lvl;
350071e9a1eSJiri Olsa 
351071e9a1eSJiri Olsa 	sz -= 1; /* -1 for null termination */
352071e9a1eSJiri Olsa 	out[0] = '\0';
353071e9a1eSJiri Olsa 
354071e9a1eSJiri Olsa 	hit = m & PERF_MEM_LVL_HIT;
355071e9a1eSJiri Olsa 	miss = m & PERF_MEM_LVL_MISS;
356071e9a1eSJiri Olsa 
357071e9a1eSJiri Olsa 	/* already taken care of */
358071e9a1eSJiri Olsa 	m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
359071e9a1eSJiri Olsa 
36052839e65SAndi Kleen 	if (mem_info && mem_info->data_src.mem_remote) {
36152839e65SAndi Kleen 		strcat(out, "Remote ");
36252839e65SAndi Kleen 		l += 7;
36352839e65SAndi Kleen 	}
36452839e65SAndi Kleen 
3657fbddf40SKajol Jain 	/*
3667fbddf40SKajol Jain 	 * Incase mem_hops field is set, we can skip printing data source via
3677fbddf40SKajol Jain 	 * PERF_MEM_LVL namespace.
3687fbddf40SKajol Jain 	 */
3697fbddf40SKajol Jain 	if (mem_info && mem_info->data_src.mem_hops) {
370cae1d759SKajol Jain 		l += scnprintf(out + l, sz - l, "%s ", mem_hops[mem_info->data_src.mem_hops]);
3717fbddf40SKajol Jain 	} else {
372071e9a1eSJiri Olsa 		for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
373071e9a1eSJiri Olsa 			if (!(m & 0x1))
374071e9a1eSJiri Olsa 				continue;
37552839e65SAndi Kleen 			if (printed++) {
376071e9a1eSJiri Olsa 				strcat(out, " or ");
377071e9a1eSJiri Olsa 				l += 4;
378071e9a1eSJiri Olsa 			}
37996907563SJiri Olsa 			l += scnprintf(out + l, sz - l, mem_lvl[i]);
380071e9a1eSJiri Olsa 		}
3817fbddf40SKajol Jain 	}
38252839e65SAndi Kleen 
38352839e65SAndi Kleen 	if (mem_info && mem_info->data_src.mem_lvl_num) {
38452839e65SAndi Kleen 		int lvl = mem_info->data_src.mem_lvl_num;
38552839e65SAndi Kleen 		if (printed++) {
38652839e65SAndi Kleen 			strcat(out, " or ");
38752839e65SAndi Kleen 			l += 4;
38852839e65SAndi Kleen 		}
38952839e65SAndi Kleen 		if (mem_lvlnum[lvl])
39052839e65SAndi Kleen 			l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
39152839e65SAndi Kleen 		else
39252839e65SAndi Kleen 			l += scnprintf(out + l, sz - l, "L%d", lvl);
39352839e65SAndi Kleen 	}
39452839e65SAndi Kleen 
39552839e65SAndi Kleen 	if (l == 0)
39652839e65SAndi Kleen 		l += scnprintf(out + l, sz - l, "N/A");
397071e9a1eSJiri Olsa 	if (hit)
39896907563SJiri Olsa 		l += scnprintf(out + l, sz - l, " hit");
399071e9a1eSJiri Olsa 	if (miss)
40096907563SJiri Olsa 		l += scnprintf(out + l, sz - l, " miss");
40196907563SJiri Olsa 
40296907563SJiri Olsa 	return l;
403071e9a1eSJiri Olsa }
4042c07af13SJiri Olsa 
4052c07af13SJiri Olsa static const char * const snoop_access[] = {
4062c07af13SJiri Olsa 	"N/A",
4072c07af13SJiri Olsa 	"None",
4082c07af13SJiri Olsa 	"Hit",
409166ebdd2SAndi Kleen 	"Miss",
4102c07af13SJiri Olsa 	"HitM",
4112c07af13SJiri Olsa };
4122c07af13SJiri Olsa 
413149d7507SJiri Olsa int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
4142c07af13SJiri Olsa {
4152c07af13SJiri Olsa 	size_t i, l = 0;
4162c07af13SJiri Olsa 	u64 m = PERF_MEM_SNOOP_NA;
4172c07af13SJiri Olsa 
4182c07af13SJiri Olsa 	sz -= 1; /* -1 for null termination */
4192c07af13SJiri Olsa 	out[0] = '\0';
4202c07af13SJiri Olsa 
4212c07af13SJiri Olsa 	if (mem_info)
4222c07af13SJiri Olsa 		m = mem_info->data_src.mem_snoop;
4232c07af13SJiri Olsa 
4242c07af13SJiri Olsa 	for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
4252c07af13SJiri Olsa 		if (!(m & 0x1))
4262c07af13SJiri Olsa 			continue;
4272c07af13SJiri Olsa 		if (l) {
4282c07af13SJiri Olsa 			strcat(out, " or ");
4292c07af13SJiri Olsa 			l += 4;
4302c07af13SJiri Olsa 		}
431149d7507SJiri Olsa 		l += scnprintf(out + l, sz - l, snoop_access[i]);
4322c07af13SJiri Olsa 	}
43352839e65SAndi Kleen 	if (mem_info &&
43452839e65SAndi Kleen 	     (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) {
43552839e65SAndi Kleen 		if (l) {
43652839e65SAndi Kleen 			strcat(out, " or ");
43752839e65SAndi Kleen 			l += 4;
43852839e65SAndi Kleen 		}
43952839e65SAndi Kleen 		l += scnprintf(out + l, sz - l, "Fwd");
44052839e65SAndi Kleen 	}
4412c07af13SJiri Olsa 
4422c07af13SJiri Olsa 	if (*out == '\0')
443149d7507SJiri Olsa 		l += scnprintf(out, sz - l, "N/A");
444149d7507SJiri Olsa 
445149d7507SJiri Olsa 	return l;
4462c07af13SJiri Olsa }
44769a77275SJiri Olsa 
4488b0819c8SJiri Olsa int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
44969a77275SJiri Olsa {
45069a77275SJiri Olsa 	u64 mask = PERF_MEM_LOCK_NA;
4518b0819c8SJiri Olsa 	int l;
45269a77275SJiri Olsa 
45369a77275SJiri Olsa 	if (mem_info)
45469a77275SJiri Olsa 		mask = mem_info->data_src.mem_lock;
45569a77275SJiri Olsa 
45669a77275SJiri Olsa 	if (mask & PERF_MEM_LOCK_NA)
4578b0819c8SJiri Olsa 		l = scnprintf(out, sz, "N/A");
45869a77275SJiri Olsa 	else if (mask & PERF_MEM_LOCK_LOCKED)
4598b0819c8SJiri Olsa 		l = scnprintf(out, sz, "Yes");
46069a77275SJiri Olsa 	else
4618b0819c8SJiri Olsa 		l = scnprintf(out, sz, "No");
4628b0819c8SJiri Olsa 
4638b0819c8SJiri Olsa 	return l;
46469a77275SJiri Olsa }
465c19ac912SJiri Olsa 
466a054c298SKan Liang int perf_mem__blk_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
467a054c298SKan Liang {
468a054c298SKan Liang 	size_t l = 0;
469a054c298SKan Liang 	u64 mask = PERF_MEM_BLK_NA;
470a054c298SKan Liang 
471a054c298SKan Liang 	sz -= 1; /* -1 for null termination */
472a054c298SKan Liang 	out[0] = '\0';
473a054c298SKan Liang 
474a054c298SKan Liang 	if (mem_info)
475a054c298SKan Liang 		mask = mem_info->data_src.mem_blk;
476a054c298SKan Liang 
477a054c298SKan Liang 	if (!mask || (mask & PERF_MEM_BLK_NA)) {
478a054c298SKan Liang 		l += scnprintf(out + l, sz - l, " N/A");
479a054c298SKan Liang 		return l;
480a054c298SKan Liang 	}
481a054c298SKan Liang 	if (mask & PERF_MEM_BLK_DATA)
482a054c298SKan Liang 		l += scnprintf(out + l, sz - l, " Data");
483a054c298SKan Liang 	if (mask & PERF_MEM_BLK_ADDR)
484a054c298SKan Liang 		l += scnprintf(out + l, sz - l, " Addr");
485a054c298SKan Liang 
486a054c298SKan Liang 	return l;
487a054c298SKan Liang }
488a054c298SKan Liang 
489c19ac912SJiri Olsa int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
490c19ac912SJiri Olsa {
491c19ac912SJiri Olsa 	int i = 0;
492c19ac912SJiri Olsa 
493fdefc375SLeo Yan 	i += scnprintf(out, sz, "|OP ");
494fdefc375SLeo Yan 	i += perf_mem__op_scnprintf(out + i, sz - i, mem_info);
495fdefc375SLeo Yan 	i += scnprintf(out + i, sz - i, "|LVL ");
496fdefc375SLeo Yan 	i += perf_mem__lvl_scnprintf(out + i, sz, mem_info);
497c19ac912SJiri Olsa 	i += scnprintf(out + i, sz - i, "|SNP ");
498c19ac912SJiri Olsa 	i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
499c19ac912SJiri Olsa 	i += scnprintf(out + i, sz - i, "|TLB ");
500c19ac912SJiri Olsa 	i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
501c19ac912SJiri Olsa 	i += scnprintf(out + i, sz - i, "|LCK ");
502c19ac912SJiri Olsa 	i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
503a054c298SKan Liang 	i += scnprintf(out + i, sz - i, "|BLK ");
504a054c298SKan Liang 	i += perf_mem__blk_scnprintf(out + i, sz - i, mem_info);
505c19ac912SJiri Olsa 
506c19ac912SJiri Olsa 	return i;
507c19ac912SJiri Olsa }
508aadddd68SJiri Olsa 
509aadddd68SJiri Olsa int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
510aadddd68SJiri Olsa {
511aadddd68SJiri Olsa 	union perf_mem_data_src *data_src = &mi->data_src;
512aadddd68SJiri Olsa 	u64 daddr  = mi->daddr.addr;
513aadddd68SJiri Olsa 	u64 op     = data_src->mem_op;
514aadddd68SJiri Olsa 	u64 lvl    = data_src->mem_lvl;
515aadddd68SJiri Olsa 	u64 snoop  = data_src->mem_snoop;
516aadddd68SJiri Olsa 	u64 lock   = data_src->mem_lock;
517d9d5d767SKan Liang 	u64 blk    = data_src->mem_blk;
51812c15302SJiri Olsa 	/*
51912c15302SJiri Olsa 	 * Skylake might report unknown remote level via this
52012c15302SJiri Olsa 	 * bit, consider it when evaluating remote HITMs.
521cae1d759SKajol Jain 	 *
522cae1d759SKajol Jain 	 * Incase of power, remote field can also be used to denote cache
523cae1d759SKajol Jain 	 * accesses from the another core of same node. Hence, setting
524cae1d759SKajol Jain 	 * mrem only when HOPS is zero along with set remote field.
52512c15302SJiri Olsa 	 */
526cae1d759SKajol Jain 	bool mrem  = (data_src->mem_remote && !data_src->mem_hops);
527aadddd68SJiri Olsa 	int err = 0;
528aadddd68SJiri Olsa 
529dba8ab93SJiri Olsa #define HITM_INC(__f)		\
530dba8ab93SJiri Olsa do {				\
531dba8ab93SJiri Olsa 	stats->__f++;		\
532dba8ab93SJiri Olsa 	stats->tot_hitm++;	\
533dba8ab93SJiri Olsa } while (0)
534dba8ab93SJiri Olsa 
535aadddd68SJiri Olsa #define P(a, b) PERF_MEM_##a##_##b
536aadddd68SJiri Olsa 
537aadddd68SJiri Olsa 	stats->nr_entries++;
538aadddd68SJiri Olsa 
539aadddd68SJiri Olsa 	if (lock & P(LOCK, LOCKED)) stats->locks++;
540aadddd68SJiri Olsa 
541d9d5d767SKan Liang 	if (blk & P(BLK, DATA)) stats->blk_data++;
542d9d5d767SKan Liang 	if (blk & P(BLK, ADDR)) stats->blk_addr++;
543d9d5d767SKan Liang 
544aadddd68SJiri Olsa 	if (op & P(OP, LOAD)) {
545aadddd68SJiri Olsa 		/* load */
546aadddd68SJiri Olsa 		stats->load++;
547aadddd68SJiri Olsa 
548aadddd68SJiri Olsa 		if (!daddr) {
549aadddd68SJiri Olsa 			stats->ld_noadrs++;
550aadddd68SJiri Olsa 			return -1;
551aadddd68SJiri Olsa 		}
552aadddd68SJiri Olsa 
553aadddd68SJiri Olsa 		if (lvl & P(LVL, HIT)) {
554aadddd68SJiri Olsa 			if (lvl & P(LVL, UNC)) stats->ld_uncache++;
555aadddd68SJiri Olsa 			if (lvl & P(LVL, IO))  stats->ld_io++;
556aadddd68SJiri Olsa 			if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
557aadddd68SJiri Olsa 			if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
558aadddd68SJiri Olsa 			if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
559aadddd68SJiri Olsa 			if (lvl & P(LVL, L3 )) {
560aadddd68SJiri Olsa 				if (snoop & P(SNOOP, HITM))
561dba8ab93SJiri Olsa 					HITM_INC(lcl_hitm);
562aadddd68SJiri Olsa 				else
563aadddd68SJiri Olsa 					stats->ld_llchit++;
564aadddd68SJiri Olsa 			}
565aadddd68SJiri Olsa 
566aadddd68SJiri Olsa 			if (lvl & P(LVL, LOC_RAM)) {
567aadddd68SJiri Olsa 				stats->lcl_dram++;
568aadddd68SJiri Olsa 				if (snoop & P(SNOOP, HIT))
569aadddd68SJiri Olsa 					stats->ld_shared++;
570aadddd68SJiri Olsa 				else
571aadddd68SJiri Olsa 					stats->ld_excl++;
572aadddd68SJiri Olsa 			}
573aadddd68SJiri Olsa 
574aadddd68SJiri Olsa 			if ((lvl & P(LVL, REM_RAM1)) ||
57512c15302SJiri Olsa 			    (lvl & P(LVL, REM_RAM2)) ||
57612c15302SJiri Olsa 			     mrem) {
577aadddd68SJiri Olsa 				stats->rmt_dram++;
578aadddd68SJiri Olsa 				if (snoop & P(SNOOP, HIT))
579aadddd68SJiri Olsa 					stats->ld_shared++;
580aadddd68SJiri Olsa 				else
581aadddd68SJiri Olsa 					stats->ld_excl++;
582aadddd68SJiri Olsa 			}
583aadddd68SJiri Olsa 		}
584aadddd68SJiri Olsa 
585aadddd68SJiri Olsa 		if ((lvl & P(LVL, REM_CCE1)) ||
58612c15302SJiri Olsa 		    (lvl & P(LVL, REM_CCE2)) ||
58712c15302SJiri Olsa 		     mrem) {
588aadddd68SJiri Olsa 			if (snoop & P(SNOOP, HIT))
589aadddd68SJiri Olsa 				stats->rmt_hit++;
590aadddd68SJiri Olsa 			else if (snoop & P(SNOOP, HITM))
591dba8ab93SJiri Olsa 				HITM_INC(rmt_hitm);
592aadddd68SJiri Olsa 		}
593aadddd68SJiri Olsa 
594aadddd68SJiri Olsa 		if ((lvl & P(LVL, MISS)))
595aadddd68SJiri Olsa 			stats->ld_miss++;
596aadddd68SJiri Olsa 
597aadddd68SJiri Olsa 	} else if (op & P(OP, STORE)) {
598aadddd68SJiri Olsa 		/* store */
599aadddd68SJiri Olsa 		stats->store++;
600aadddd68SJiri Olsa 
601aadddd68SJiri Olsa 		if (!daddr) {
602aadddd68SJiri Olsa 			stats->st_noadrs++;
603aadddd68SJiri Olsa 			return -1;
604aadddd68SJiri Olsa 		}
605aadddd68SJiri Olsa 
606aadddd68SJiri Olsa 		if (lvl & P(LVL, HIT)) {
607aadddd68SJiri Olsa 			if (lvl & P(LVL, UNC)) stats->st_uncache++;
608aadddd68SJiri Olsa 			if (lvl & P(LVL, L1 )) stats->st_l1hit++;
609aadddd68SJiri Olsa 		}
610aadddd68SJiri Olsa 		if (lvl & P(LVL, MISS))
611aadddd68SJiri Olsa 			if (lvl & P(LVL, L1)) stats->st_l1miss++;
612*98450637SLeo Yan 		if (lvl & P(LVL, NA))
613*98450637SLeo Yan 			stats->st_na++;
614aadddd68SJiri Olsa 	} else {
615aadddd68SJiri Olsa 		/* unparsable data_src? */
616aadddd68SJiri Olsa 		stats->noparse++;
617aadddd68SJiri Olsa 		return -1;
618aadddd68SJiri Olsa 	}
619aadddd68SJiri Olsa 
620d46a4cdfSArnaldo Carvalho de Melo 	if (!mi->daddr.ms.map || !mi->iaddr.ms.map) {
621aadddd68SJiri Olsa 		stats->nomap++;
622aadddd68SJiri Olsa 		return -1;
623aadddd68SJiri Olsa 	}
624aadddd68SJiri Olsa 
625aadddd68SJiri Olsa #undef P
626dba8ab93SJiri Olsa #undef HITM_INC
627aadddd68SJiri Olsa 	return err;
628aadddd68SJiri Olsa }
6290a9a24ccSJiri Olsa 
6300a9a24ccSJiri Olsa void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
6310a9a24ccSJiri Olsa {
6320a9a24ccSJiri Olsa 	stats->nr_entries	+= add->nr_entries;
6330a9a24ccSJiri Olsa 
6340a9a24ccSJiri Olsa 	stats->locks		+= add->locks;
6350a9a24ccSJiri Olsa 	stats->store		+= add->store;
6360a9a24ccSJiri Olsa 	stats->st_uncache	+= add->st_uncache;
6370a9a24ccSJiri Olsa 	stats->st_noadrs	+= add->st_noadrs;
6380a9a24ccSJiri Olsa 	stats->st_l1hit		+= add->st_l1hit;
6390a9a24ccSJiri Olsa 	stats->st_l1miss	+= add->st_l1miss;
640*98450637SLeo Yan 	stats->st_na		+= add->st_na;
6410a9a24ccSJiri Olsa 	stats->load		+= add->load;
6420a9a24ccSJiri Olsa 	stats->ld_excl		+= add->ld_excl;
6430a9a24ccSJiri Olsa 	stats->ld_shared	+= add->ld_shared;
6440a9a24ccSJiri Olsa 	stats->ld_uncache	+= add->ld_uncache;
6450a9a24ccSJiri Olsa 	stats->ld_io		+= add->ld_io;
6460a9a24ccSJiri Olsa 	stats->ld_miss		+= add->ld_miss;
6470a9a24ccSJiri Olsa 	stats->ld_noadrs	+= add->ld_noadrs;
6480a9a24ccSJiri Olsa 	stats->ld_fbhit		+= add->ld_fbhit;
6490a9a24ccSJiri Olsa 	stats->ld_l1hit		+= add->ld_l1hit;
6500a9a24ccSJiri Olsa 	stats->ld_l2hit		+= add->ld_l2hit;
6510a9a24ccSJiri Olsa 	stats->ld_llchit	+= add->ld_llchit;
6520a9a24ccSJiri Olsa 	stats->lcl_hitm		+= add->lcl_hitm;
6530a9a24ccSJiri Olsa 	stats->rmt_hitm		+= add->rmt_hitm;
654dba8ab93SJiri Olsa 	stats->tot_hitm		+= add->tot_hitm;
6550a9a24ccSJiri Olsa 	stats->rmt_hit		+= add->rmt_hit;
6560a9a24ccSJiri Olsa 	stats->lcl_dram		+= add->lcl_dram;
6570a9a24ccSJiri Olsa 	stats->rmt_dram		+= add->rmt_dram;
658d9d5d767SKan Liang 	stats->blk_data		+= add->blk_data;
659d9d5d767SKan Liang 	stats->blk_addr		+= add->blk_addr;
6600a9a24ccSJiri Olsa 	stats->nomap		+= add->nomap;
6610a9a24ccSJiri Olsa 	stats->noparse		+= add->noparse;
6620a9a24ccSJiri Olsa }
663