]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - tools/perf/util/mem-events.c
Merge tag 'drm/atmel-hlcdc/4.8-fixes' of github.com:bbrezillon/linux-at91 into drm...
[mirror_ubuntu-artful-kernel.git] / tools / perf / util / mem-events.c
1 #include <stddef.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include <api/fs/fs.h>
9 #include "mem-events.h"
10 #include "debug.h"
11 #include "symbol.h"
12
13 unsigned int perf_mem_events__loads_ldlat = 30;
14
15 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
16
17 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
18 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
19 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
20 };
21 #undef E
22
23 #undef E
24
25 static char mem_loads_name[100];
26 static bool mem_loads_name__init;
27
28 char *perf_mem_events__name(int i)
29 {
30 if (i == PERF_MEM_EVENTS__LOAD) {
31 if (!mem_loads_name__init) {
32 mem_loads_name__init = true;
33 scnprintf(mem_loads_name, sizeof(mem_loads_name),
34 perf_mem_events[i].name,
35 perf_mem_events__loads_ldlat);
36 }
37 return mem_loads_name;
38 }
39
40 return (char *)perf_mem_events[i].name;
41 }
42
43 int perf_mem_events__parse(const char *str)
44 {
45 char *tok, *saveptr = NULL;
46 bool found = false;
47 char *buf;
48 int j;
49
50 /* We need buffer that we know we can write to. */
51 buf = malloc(strlen(str) + 1);
52 if (!buf)
53 return -ENOMEM;
54
55 strcpy(buf, str);
56
57 tok = strtok_r((char *)buf, ",", &saveptr);
58
59 while (tok) {
60 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
61 struct perf_mem_event *e = &perf_mem_events[j];
62
63 if (strstr(e->tag, tok))
64 e->record = found = true;
65 }
66
67 tok = strtok_r(NULL, ",", &saveptr);
68 }
69
70 free(buf);
71
72 if (found)
73 return 0;
74
75 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
76 return -1;
77 }
78
79 int perf_mem_events__init(void)
80 {
81 const char *mnt = sysfs__mount();
82 bool found = false;
83 int j;
84
85 if (!mnt)
86 return -ENOENT;
87
88 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
89 char path[PATH_MAX];
90 struct perf_mem_event *e = &perf_mem_events[j];
91 struct stat st;
92
93 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
94 mnt, e->sysfs_name);
95
96 if (!stat(path, &st))
97 e->supported = found = true;
98 }
99
100 return found ? 0 : -ENOENT;
101 }
102
103 static const char * const tlb_access[] = {
104 "N/A",
105 "HIT",
106 "MISS",
107 "L1",
108 "L2",
109 "Walker",
110 "Fault",
111 };
112
113 int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
114 {
115 size_t l = 0, i;
116 u64 m = PERF_MEM_TLB_NA;
117 u64 hit, miss;
118
119 sz -= 1; /* -1 for null termination */
120 out[0] = '\0';
121
122 if (mem_info)
123 m = mem_info->data_src.mem_dtlb;
124
125 hit = m & PERF_MEM_TLB_HIT;
126 miss = m & PERF_MEM_TLB_MISS;
127
128 /* already taken care of */
129 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
130
131 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
132 if (!(m & 0x1))
133 continue;
134 if (l) {
135 strcat(out, " or ");
136 l += 4;
137 }
138 l += scnprintf(out + l, sz - l, tlb_access[i]);
139 }
140 if (*out == '\0')
141 l += scnprintf(out, sz - l, "N/A");
142 if (hit)
143 l += scnprintf(out + l, sz - l, " hit");
144 if (miss)
145 l += scnprintf(out + l, sz - l, " miss");
146
147 return l;
148 }
149
150 static const char * const mem_lvl[] = {
151 "N/A",
152 "HIT",
153 "MISS",
154 "L1",
155 "LFB",
156 "L2",
157 "L3",
158 "Local RAM",
159 "Remote RAM (1 hop)",
160 "Remote RAM (2 hops)",
161 "Remote Cache (1 hop)",
162 "Remote Cache (2 hops)",
163 "I/O",
164 "Uncached",
165 };
166
167 int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
168 {
169 size_t i, l = 0;
170 u64 m = PERF_MEM_LVL_NA;
171 u64 hit, miss;
172
173 if (mem_info)
174 m = mem_info->data_src.mem_lvl;
175
176 sz -= 1; /* -1 for null termination */
177 out[0] = '\0';
178
179 hit = m & PERF_MEM_LVL_HIT;
180 miss = m & PERF_MEM_LVL_MISS;
181
182 /* already taken care of */
183 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
184
185 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
186 if (!(m & 0x1))
187 continue;
188 if (l) {
189 strcat(out, " or ");
190 l += 4;
191 }
192 l += scnprintf(out + l, sz - l, mem_lvl[i]);
193 }
194 if (*out == '\0')
195 l += scnprintf(out, sz - l, "N/A");
196 if (hit)
197 l += scnprintf(out + l, sz - l, " hit");
198 if (miss)
199 l += scnprintf(out + l, sz - l, " miss");
200
201 return l;
202 }
203
204 static const char * const snoop_access[] = {
205 "N/A",
206 "None",
207 "Miss",
208 "Hit",
209 "HitM",
210 };
211
212 int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
213 {
214 size_t i, l = 0;
215 u64 m = PERF_MEM_SNOOP_NA;
216
217 sz -= 1; /* -1 for null termination */
218 out[0] = '\0';
219
220 if (mem_info)
221 m = mem_info->data_src.mem_snoop;
222
223 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
224 if (!(m & 0x1))
225 continue;
226 if (l) {
227 strcat(out, " or ");
228 l += 4;
229 }
230 l += scnprintf(out + l, sz - l, snoop_access[i]);
231 }
232
233 if (*out == '\0')
234 l += scnprintf(out, sz - l, "N/A");
235
236 return l;
237 }
238
239 int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
240 {
241 u64 mask = PERF_MEM_LOCK_NA;
242 int l;
243
244 if (mem_info)
245 mask = mem_info->data_src.mem_lock;
246
247 if (mask & PERF_MEM_LOCK_NA)
248 l = scnprintf(out, sz, "N/A");
249 else if (mask & PERF_MEM_LOCK_LOCKED)
250 l = scnprintf(out, sz, "Yes");
251 else
252 l = scnprintf(out, sz, "No");
253
254 return l;
255 }
256
257 int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
258 {
259 int i = 0;
260
261 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
262 i += scnprintf(out + i, sz - i, "|SNP ");
263 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
264 i += scnprintf(out + i, sz - i, "|TLB ");
265 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
266 i += scnprintf(out + i, sz - i, "|LCK ");
267 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
268
269 return i;
270 }