xref: /openbmc/linux/tools/perf/util/mem-events.c (revision 149d7507)
1ce1e22b0SJiri Olsa #include <stddef.h>
2ce1e22b0SJiri Olsa #include <stdlib.h>
3ce1e22b0SJiri Olsa #include <string.h>
4ce1e22b0SJiri Olsa #include <errno.h>
554fbad54SJiri Olsa #include <sys/types.h>
654fbad54SJiri Olsa #include <sys/stat.h>
754fbad54SJiri Olsa #include <unistd.h>
854fbad54SJiri Olsa #include <api/fs/fs.h>
9acbe613eSJiri Olsa #include "mem-events.h"
10ce1e22b0SJiri Olsa #include "debug.h"
110c877d75SJiri Olsa #include "symbol.h"
12acbe613eSJiri Olsa 
1354fbad54SJiri Olsa #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
14acbe613eSJiri Olsa 
15acbe613eSJiri Olsa struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
1654fbad54SJiri Olsa 	E("ldlat-loads",	"cpu/mem-loads,ldlat=30/P",	"mem-loads"),
1754fbad54SJiri Olsa 	E("ldlat-stores",	"cpu/mem-stores/P",		"mem-stores"),
18acbe613eSJiri Olsa };
1954fbad54SJiri Olsa #undef E
20acbe613eSJiri Olsa 
21acbe613eSJiri Olsa #undef E
22ce1e22b0SJiri Olsa 
232ba7ac58SJiri Olsa char *perf_mem_events__name(int i)
242ba7ac58SJiri Olsa {
252ba7ac58SJiri Olsa 	return (char *)perf_mem_events[i].name;
262ba7ac58SJiri Olsa }
272ba7ac58SJiri Olsa 
28ce1e22b0SJiri Olsa int perf_mem_events__parse(const char *str)
29ce1e22b0SJiri Olsa {
30ce1e22b0SJiri Olsa 	char *tok, *saveptr = NULL;
31ce1e22b0SJiri Olsa 	bool found = false;
32ce1e22b0SJiri Olsa 	char *buf;
33ce1e22b0SJiri Olsa 	int j;
34ce1e22b0SJiri Olsa 
35ce1e22b0SJiri Olsa 	/* We need buffer that we know we can write to. */
36ce1e22b0SJiri Olsa 	buf = malloc(strlen(str) + 1);
37ce1e22b0SJiri Olsa 	if (!buf)
38ce1e22b0SJiri Olsa 		return -ENOMEM;
39ce1e22b0SJiri Olsa 
40ce1e22b0SJiri Olsa 	strcpy(buf, str);
41ce1e22b0SJiri Olsa 
42ce1e22b0SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
43ce1e22b0SJiri Olsa 
44ce1e22b0SJiri Olsa 	while (tok) {
45ce1e22b0SJiri Olsa 		for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
46ce1e22b0SJiri Olsa 			struct perf_mem_event *e = &perf_mem_events[j];
47ce1e22b0SJiri Olsa 
48ce1e22b0SJiri Olsa 			if (strstr(e->tag, tok))
49ce1e22b0SJiri Olsa 				e->record = found = true;
50ce1e22b0SJiri Olsa 		}
51ce1e22b0SJiri Olsa 
52ce1e22b0SJiri Olsa 		tok = strtok_r(NULL, ",", &saveptr);
53ce1e22b0SJiri Olsa 	}
54ce1e22b0SJiri Olsa 
55ce1e22b0SJiri Olsa 	free(buf);
56ce1e22b0SJiri Olsa 
57ce1e22b0SJiri Olsa 	if (found)
58ce1e22b0SJiri Olsa 		return 0;
59ce1e22b0SJiri Olsa 
60ce1e22b0SJiri Olsa 	pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
61ce1e22b0SJiri Olsa 	return -1;
62ce1e22b0SJiri Olsa }
6354fbad54SJiri Olsa 
6454fbad54SJiri Olsa int perf_mem_events__init(void)
6554fbad54SJiri Olsa {
6654fbad54SJiri Olsa 	const char *mnt = sysfs__mount();
6754fbad54SJiri Olsa 	bool found = false;
6854fbad54SJiri Olsa 	int j;
6954fbad54SJiri Olsa 
7054fbad54SJiri Olsa 	if (!mnt)
7154fbad54SJiri Olsa 		return -ENOENT;
7254fbad54SJiri Olsa 
7354fbad54SJiri Olsa 	for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
7454fbad54SJiri Olsa 		char path[PATH_MAX];
7554fbad54SJiri Olsa 		struct perf_mem_event *e = &perf_mem_events[j];
7654fbad54SJiri Olsa 		struct stat st;
7754fbad54SJiri Olsa 
7854fbad54SJiri Olsa 		scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
7954fbad54SJiri Olsa 			  mnt, e->sysfs_name);
8054fbad54SJiri Olsa 
8154fbad54SJiri Olsa 		if (!stat(path, &st))
8254fbad54SJiri Olsa 			e->supported = found = true;
8354fbad54SJiri Olsa 	}
8454fbad54SJiri Olsa 
8554fbad54SJiri Olsa 	return found ? 0 : -ENOENT;
8654fbad54SJiri Olsa }
870c877d75SJiri Olsa 
880c877d75SJiri Olsa static const char * const tlb_access[] = {
890c877d75SJiri Olsa 	"N/A",
900c877d75SJiri Olsa 	"HIT",
910c877d75SJiri Olsa 	"MISS",
920c877d75SJiri Olsa 	"L1",
930c877d75SJiri Olsa 	"L2",
940c877d75SJiri Olsa 	"Walker",
950c877d75SJiri Olsa 	"Fault",
960c877d75SJiri Olsa };
970c877d75SJiri Olsa 
98b1a5fbeaSJiri Olsa int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
990c877d75SJiri Olsa {
1000c877d75SJiri Olsa 	size_t l = 0, i;
1010c877d75SJiri Olsa 	u64 m = PERF_MEM_TLB_NA;
1020c877d75SJiri Olsa 	u64 hit, miss;
1030c877d75SJiri Olsa 
1040c877d75SJiri Olsa 	sz -= 1; /* -1 for null termination */
1050c877d75SJiri Olsa 	out[0] = '\0';
1060c877d75SJiri Olsa 
1070c877d75SJiri Olsa 	if (mem_info)
1080c877d75SJiri Olsa 		m = mem_info->data_src.mem_dtlb;
1090c877d75SJiri Olsa 
1100c877d75SJiri Olsa 	hit = m & PERF_MEM_TLB_HIT;
1110c877d75SJiri Olsa 	miss = m & PERF_MEM_TLB_MISS;
1120c877d75SJiri Olsa 
1130c877d75SJiri Olsa 	/* already taken care of */
1140c877d75SJiri Olsa 	m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
1150c877d75SJiri Olsa 
1160c877d75SJiri Olsa 	for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
1170c877d75SJiri Olsa 		if (!(m & 0x1))
1180c877d75SJiri Olsa 			continue;
1190c877d75SJiri Olsa 		if (l) {
1200c877d75SJiri Olsa 			strcat(out, " or ");
1210c877d75SJiri Olsa 			l += 4;
1220c877d75SJiri Olsa 		}
123b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, tlb_access[i]);
1240c877d75SJiri Olsa 	}
1250c877d75SJiri Olsa 	if (*out == '\0')
126b1a5fbeaSJiri Olsa 		l += scnprintf(out, sz - l, "N/A");
1270c877d75SJiri Olsa 	if (hit)
128b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, " hit");
1290c877d75SJiri Olsa 	if (miss)
130b1a5fbeaSJiri Olsa 		l += scnprintf(out + l, sz - l, " miss");
131b1a5fbeaSJiri Olsa 
132b1a5fbeaSJiri Olsa 	return l;
1330c877d75SJiri Olsa }
134071e9a1eSJiri Olsa 
135071e9a1eSJiri Olsa static const char * const mem_lvl[] = {
136071e9a1eSJiri Olsa 	"N/A",
137071e9a1eSJiri Olsa 	"HIT",
138071e9a1eSJiri Olsa 	"MISS",
139071e9a1eSJiri Olsa 	"L1",
140071e9a1eSJiri Olsa 	"LFB",
141071e9a1eSJiri Olsa 	"L2",
142071e9a1eSJiri Olsa 	"L3",
143071e9a1eSJiri Olsa 	"Local RAM",
144071e9a1eSJiri Olsa 	"Remote RAM (1 hop)",
145071e9a1eSJiri Olsa 	"Remote RAM (2 hops)",
146071e9a1eSJiri Olsa 	"Remote Cache (1 hop)",
147071e9a1eSJiri Olsa 	"Remote Cache (2 hops)",
148071e9a1eSJiri Olsa 	"I/O",
149071e9a1eSJiri Olsa 	"Uncached",
150071e9a1eSJiri Olsa };
151071e9a1eSJiri Olsa 
15296907563SJiri Olsa int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
153071e9a1eSJiri Olsa {
154071e9a1eSJiri Olsa 	size_t i, l = 0;
155071e9a1eSJiri Olsa 	u64 m =  PERF_MEM_LVL_NA;
156071e9a1eSJiri Olsa 	u64 hit, miss;
157071e9a1eSJiri Olsa 
158071e9a1eSJiri Olsa 	if (mem_info)
159071e9a1eSJiri Olsa 		m  = mem_info->data_src.mem_lvl;
160071e9a1eSJiri Olsa 
161071e9a1eSJiri Olsa 	sz -= 1; /* -1 for null termination */
162071e9a1eSJiri Olsa 	out[0] = '\0';
163071e9a1eSJiri Olsa 
164071e9a1eSJiri Olsa 	hit = m & PERF_MEM_LVL_HIT;
165071e9a1eSJiri Olsa 	miss = m & PERF_MEM_LVL_MISS;
166071e9a1eSJiri Olsa 
167071e9a1eSJiri Olsa 	/* already taken care of */
168071e9a1eSJiri Olsa 	m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
169071e9a1eSJiri Olsa 
170071e9a1eSJiri Olsa 	for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
171071e9a1eSJiri Olsa 		if (!(m & 0x1))
172071e9a1eSJiri Olsa 			continue;
173071e9a1eSJiri Olsa 		if (l) {
174071e9a1eSJiri Olsa 			strcat(out, " or ");
175071e9a1eSJiri Olsa 			l += 4;
176071e9a1eSJiri Olsa 		}
17796907563SJiri Olsa 		l += scnprintf(out + l, sz - l, mem_lvl[i]);
178071e9a1eSJiri Olsa 	}
179071e9a1eSJiri Olsa 	if (*out == '\0')
18096907563SJiri Olsa 		l += scnprintf(out, sz - l, "N/A");
181071e9a1eSJiri Olsa 	if (hit)
18296907563SJiri Olsa 		l += scnprintf(out + l, sz - l, " hit");
183071e9a1eSJiri Olsa 	if (miss)
18496907563SJiri Olsa 		l += scnprintf(out + l, sz - l, " miss");
18596907563SJiri Olsa 
18696907563SJiri Olsa 	return l;
187071e9a1eSJiri Olsa }
1882c07af13SJiri Olsa 
1892c07af13SJiri Olsa static const char * const snoop_access[] = {
1902c07af13SJiri Olsa 	"N/A",
1912c07af13SJiri Olsa 	"None",
1922c07af13SJiri Olsa 	"Miss",
1932c07af13SJiri Olsa 	"Hit",
1942c07af13SJiri Olsa 	"HitM",
1952c07af13SJiri Olsa };
1962c07af13SJiri Olsa 
197149d7507SJiri Olsa int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
1982c07af13SJiri Olsa {
1992c07af13SJiri Olsa 	size_t i, l = 0;
2002c07af13SJiri Olsa 	u64 m = PERF_MEM_SNOOP_NA;
2012c07af13SJiri Olsa 
2022c07af13SJiri Olsa 	sz -= 1; /* -1 for null termination */
2032c07af13SJiri Olsa 	out[0] = '\0';
2042c07af13SJiri Olsa 
2052c07af13SJiri Olsa 	if (mem_info)
2062c07af13SJiri Olsa 		m = mem_info->data_src.mem_snoop;
2072c07af13SJiri Olsa 
2082c07af13SJiri Olsa 	for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
2092c07af13SJiri Olsa 		if (!(m & 0x1))
2102c07af13SJiri Olsa 			continue;
2112c07af13SJiri Olsa 		if (l) {
2122c07af13SJiri Olsa 			strcat(out, " or ");
2132c07af13SJiri Olsa 			l += 4;
2142c07af13SJiri Olsa 		}
215149d7507SJiri Olsa 		l += scnprintf(out + l, sz - l, snoop_access[i]);
2162c07af13SJiri Olsa 	}
2172c07af13SJiri Olsa 
2182c07af13SJiri Olsa 	if (*out == '\0')
219149d7507SJiri Olsa 		l += scnprintf(out, sz - l, "N/A");
220149d7507SJiri Olsa 
221149d7507SJiri Olsa 	return l;
2222c07af13SJiri Olsa }
22369a77275SJiri Olsa 
22469a77275SJiri Olsa void perf_mem__lck_scnprintf(char *out, size_t sz __maybe_unused,
22569a77275SJiri Olsa 			     struct mem_info *mem_info)
22669a77275SJiri Olsa {
22769a77275SJiri Olsa 	u64 mask = PERF_MEM_LOCK_NA;
22869a77275SJiri Olsa 
22969a77275SJiri Olsa 	if (mem_info)
23069a77275SJiri Olsa 		mask = mem_info->data_src.mem_lock;
23169a77275SJiri Olsa 
23269a77275SJiri Olsa 	if (mask & PERF_MEM_LOCK_NA)
23369a77275SJiri Olsa 		strncat(out, "N/A", 3);
23469a77275SJiri Olsa 	else if (mask & PERF_MEM_LOCK_LOCKED)
23569a77275SJiri Olsa 		strncat(out, "Yes", 3);
23669a77275SJiri Olsa 	else
23769a77275SJiri Olsa 		strncat(out, "No", 2);
23869a77275SJiri Olsa }
239