blob: de981ddcd1d3ec6aafd7767af73f5d625200d159 [file] [log] [blame]
Jiri Olsace1e22b2016-02-15 09:34:35 +01001#include <stddef.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
Jiri Olsa54fbad52016-02-24 09:46:42 +01005#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <api/fs/fs.h>
Jiri Olsaacbe6132016-02-15 09:34:34 +01009#include "mem-events.h"
Jiri Olsace1e22b2016-02-15 09:34:35 +010010#include "debug.h"
Jiri Olsa0c877d72016-02-24 09:46:46 +010011#include "symbol.h"
Jiri Olsaacbe6132016-02-15 09:34:34 +010012
Jiri Olsa54fbad52016-02-24 09:46:42 +010013#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
Jiri Olsaacbe6132016-02-15 09:34:34 +010014
15struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
Jiri Olsa54fbad52016-02-24 09:46:42 +010016 E("ldlat-loads", "cpu/mem-loads,ldlat=30/P", "mem-loads"),
17 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
Jiri Olsaacbe6132016-02-15 09:34:34 +010018};
Jiri Olsa54fbad52016-02-24 09:46:42 +010019#undef E
Jiri Olsaacbe6132016-02-15 09:34:34 +010020
21#undef E
Jiri Olsace1e22b2016-02-15 09:34:35 +010022
Jiri Olsa2ba7ac52016-02-24 09:46:43 +010023char *perf_mem_events__name(int i)
24{
25 return (char *)perf_mem_events[i].name;
26}
27
Jiri Olsace1e22b2016-02-15 09:34:35 +010028int perf_mem_events__parse(const char *str)
29{
30 char *tok, *saveptr = NULL;
31 bool found = false;
32 char *buf;
33 int j;
34
35 /* We need buffer that we know we can write to. */
36 buf = malloc(strlen(str) + 1);
37 if (!buf)
38 return -ENOMEM;
39
40 strcpy(buf, str);
41
42 tok = strtok_r((char *)buf, ",", &saveptr);
43
44 while (tok) {
45 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
46 struct perf_mem_event *e = &perf_mem_events[j];
47
48 if (strstr(e->tag, tok))
49 e->record = found = true;
50 }
51
52 tok = strtok_r(NULL, ",", &saveptr);
53 }
54
55 free(buf);
56
57 if (found)
58 return 0;
59
60 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
61 return -1;
62}
Jiri Olsa54fbad52016-02-24 09:46:42 +010063
64int perf_mem_events__init(void)
65{
66 const char *mnt = sysfs__mount();
67 bool found = false;
68 int j;
69
70 if (!mnt)
71 return -ENOENT;
72
73 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
74 char path[PATH_MAX];
75 struct perf_mem_event *e = &perf_mem_events[j];
76 struct stat st;
77
78 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
79 mnt, e->sysfs_name);
80
81 if (!stat(path, &st))
82 e->supported = found = true;
83 }
84
85 return found ? 0 : -ENOENT;
86}
Jiri Olsa0c877d72016-02-24 09:46:46 +010087
88static const char * const tlb_access[] = {
89 "N/A",
90 "HIT",
91 "MISS",
92 "L1",
93 "L2",
94 "Walker",
95 "Fault",
96};
97
Jiri Olsab1a5fbea2016-02-24 09:46:50 +010098int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa0c877d72016-02-24 09:46:46 +010099{
100 size_t l = 0, i;
101 u64 m = PERF_MEM_TLB_NA;
102 u64 hit, miss;
103
104 sz -= 1; /* -1 for null termination */
105 out[0] = '\0';
106
107 if (mem_info)
108 m = mem_info->data_src.mem_dtlb;
109
110 hit = m & PERF_MEM_TLB_HIT;
111 miss = m & PERF_MEM_TLB_MISS;
112
113 /* already taken care of */
114 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
115
116 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
117 if (!(m & 0x1))
118 continue;
119 if (l) {
120 strcat(out, " or ");
121 l += 4;
122 }
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100123 l += scnprintf(out + l, sz - l, tlb_access[i]);
Jiri Olsa0c877d72016-02-24 09:46:46 +0100124 }
125 if (*out == '\0')
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100126 l += scnprintf(out, sz - l, "N/A");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100127 if (hit)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100128 l += scnprintf(out + l, sz - l, " hit");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100129 if (miss)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100130 l += scnprintf(out + l, sz - l, " miss");
131
132 return l;
Jiri Olsa0c877d72016-02-24 09:46:46 +0100133}
Jiri Olsa071e9a12016-02-24 09:46:47 +0100134
135static const char * const mem_lvl[] = {
136 "N/A",
137 "HIT",
138 "MISS",
139 "L1",
140 "LFB",
141 "L2",
142 "L3",
143 "Local RAM",
144 "Remote RAM (1 hop)",
145 "Remote RAM (2 hops)",
146 "Remote Cache (1 hop)",
147 "Remote Cache (2 hops)",
148 "I/O",
149 "Uncached",
150};
151
Jiri Olsa96907562016-02-24 09:46:51 +0100152int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa071e9a12016-02-24 09:46:47 +0100153{
154 size_t i, l = 0;
155 u64 m = PERF_MEM_LVL_NA;
156 u64 hit, miss;
157
158 if (mem_info)
159 m = mem_info->data_src.mem_lvl;
160
161 sz -= 1; /* -1 for null termination */
162 out[0] = '\0';
163
164 hit = m & PERF_MEM_LVL_HIT;
165 miss = m & PERF_MEM_LVL_MISS;
166
167 /* already taken care of */
168 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
169
170 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
171 if (!(m & 0x1))
172 continue;
173 if (l) {
174 strcat(out, " or ");
175 l += 4;
176 }
Jiri Olsa96907562016-02-24 09:46:51 +0100177 l += scnprintf(out + l, sz - l, mem_lvl[i]);
Jiri Olsa071e9a12016-02-24 09:46:47 +0100178 }
179 if (*out == '\0')
Jiri Olsa96907562016-02-24 09:46:51 +0100180 l += scnprintf(out, sz - l, "N/A");
Jiri Olsa071e9a12016-02-24 09:46:47 +0100181 if (hit)
Jiri Olsa96907562016-02-24 09:46:51 +0100182 l += scnprintf(out + l, sz - l, " hit");
Jiri Olsa071e9a12016-02-24 09:46:47 +0100183 if (miss)
Jiri Olsa96907562016-02-24 09:46:51 +0100184 l += scnprintf(out + l, sz - l, " miss");
185
186 return l;
Jiri Olsa071e9a12016-02-24 09:46:47 +0100187}
Jiri Olsa2c07af12016-02-24 09:46:48 +0100188
189static const char * const snoop_access[] = {
190 "N/A",
191 "None",
192 "Miss",
193 "Hit",
194 "HitM",
195};
196
Jiri Olsa149d7502016-02-24 09:46:52 +0100197int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa2c07af12016-02-24 09:46:48 +0100198{
199 size_t i, l = 0;
200 u64 m = PERF_MEM_SNOOP_NA;
201
202 sz -= 1; /* -1 for null termination */
203 out[0] = '\0';
204
205 if (mem_info)
206 m = mem_info->data_src.mem_snoop;
207
208 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
209 if (!(m & 0x1))
210 continue;
211 if (l) {
212 strcat(out, " or ");
213 l += 4;
214 }
Jiri Olsa149d7502016-02-24 09:46:52 +0100215 l += scnprintf(out + l, sz - l, snoop_access[i]);
Jiri Olsa2c07af12016-02-24 09:46:48 +0100216 }
217
218 if (*out == '\0')
Jiri Olsa149d7502016-02-24 09:46:52 +0100219 l += scnprintf(out, sz - l, "N/A");
220
221 return l;
Jiri Olsa2c07af12016-02-24 09:46:48 +0100222}
Jiri Olsa69a77272016-02-24 09:46:49 +0100223
224void perf_mem__lck_scnprintf(char *out, size_t sz __maybe_unused,
225 struct mem_info *mem_info)
226{
227 u64 mask = PERF_MEM_LOCK_NA;
228
229 if (mem_info)
230 mask = mem_info->data_src.mem_lock;
231
232 if (mask & PERF_MEM_LOCK_NA)
233 strncat(out, "N/A", 3);
234 else if (mask & PERF_MEM_LOCK_LOCKED)
235 strncat(out, "Yes", 3);
236 else
237 strncat(out, "No", 2);
238}