]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - tools/perf/util/mem-events.c
Merge tag 'sound-fix-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[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 <linux/kernel.h>
10 #include "mem-events.h"
11 #include "debug.h"
12 #include "symbol.h"
13 #include "sort.h"
14
15 unsigned int perf_mem_events__loads_ldlat = 30;
16
17 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
18
19 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
20 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
21 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
22 };
23 #undef E
24
25 #undef E
26
27 static char mem_loads_name[100];
28 static bool mem_loads_name__init;
29
30 char *perf_mem_events__name(int i)
31 {
32 if (i == PERF_MEM_EVENTS__LOAD) {
33 if (!mem_loads_name__init) {
34 mem_loads_name__init = true;
35 scnprintf(mem_loads_name, sizeof(mem_loads_name),
36 perf_mem_events[i].name,
37 perf_mem_events__loads_ldlat);
38 }
39 return mem_loads_name;
40 }
41
42 return (char *)perf_mem_events[i].name;
43 }
44
45 int perf_mem_events__parse(const char *str)
46 {
47 char *tok, *saveptr = NULL;
48 bool found = false;
49 char *buf;
50 int j;
51
52 /* We need buffer that we know we can write to. */
53 buf = malloc(strlen(str) + 1);
54 if (!buf)
55 return -ENOMEM;
56
57 strcpy(buf, str);
58
59 tok = strtok_r((char *)buf, ",", &saveptr);
60
61 while (tok) {
62 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
63 struct perf_mem_event *e = &perf_mem_events[j];
64
65 if (strstr(e->tag, tok))
66 e->record = found = true;
67 }
68
69 tok = strtok_r(NULL, ",", &saveptr);
70 }
71
72 free(buf);
73
74 if (found)
75 return 0;
76
77 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
78 return -1;
79 }
80
81 int perf_mem_events__init(void)
82 {
83 const char *mnt = sysfs__mount();
84 bool found = false;
85 int j;
86
87 if (!mnt)
88 return -ENOENT;
89
90 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
91 char path[PATH_MAX];
92 struct perf_mem_event *e = &perf_mem_events[j];
93 struct stat st;
94
95 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
96 mnt, e->sysfs_name);
97
98 if (!stat(path, &st))
99 e->supported = found = true;
100 }
101
102 return found ? 0 : -ENOENT;
103 }
104
105 static const char * const tlb_access[] = {
106 "N/A",
107 "HIT",
108 "MISS",
109 "L1",
110 "L2",
111 "Walker",
112 "Fault",
113 };
114
115 int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
116 {
117 size_t l = 0, i;
118 u64 m = PERF_MEM_TLB_NA;
119 u64 hit, miss;
120
121 sz -= 1; /* -1 for null termination */
122 out[0] = '\0';
123
124 if (mem_info)
125 m = mem_info->data_src.mem_dtlb;
126
127 hit = m & PERF_MEM_TLB_HIT;
128 miss = m & PERF_MEM_TLB_MISS;
129
130 /* already taken care of */
131 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
132
133 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
134 if (!(m & 0x1))
135 continue;
136 if (l) {
137 strcat(out, " or ");
138 l += 4;
139 }
140 l += scnprintf(out + l, sz - l, tlb_access[i]);
141 }
142 if (*out == '\0')
143 l += scnprintf(out, sz - l, "N/A");
144 if (hit)
145 l += scnprintf(out + l, sz - l, " hit");
146 if (miss)
147 l += scnprintf(out + l, sz - l, " miss");
148
149 return l;
150 }
151
152 static const char * const mem_lvl[] = {
153 "N/A",
154 "HIT",
155 "MISS",
156 "L1",
157 "LFB",
158 "L2",
159 "L3",
160 "Local RAM",
161 "Remote RAM (1 hop)",
162 "Remote RAM (2 hops)",
163 "Remote Cache (1 hop)",
164 "Remote Cache (2 hops)",
165 "I/O",
166 "Uncached",
167 };
168
169 int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
170 {
171 size_t i, l = 0;
172 u64 m = PERF_MEM_LVL_NA;
173 u64 hit, miss;
174
175 if (mem_info)
176 m = mem_info->data_src.mem_lvl;
177
178 sz -= 1; /* -1 for null termination */
179 out[0] = '\0';
180
181 hit = m & PERF_MEM_LVL_HIT;
182 miss = m & PERF_MEM_LVL_MISS;
183
184 /* already taken care of */
185 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
186
187 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
188 if (!(m & 0x1))
189 continue;
190 if (l) {
191 strcat(out, " or ");
192 l += 4;
193 }
194 l += scnprintf(out + l, sz - l, mem_lvl[i]);
195 }
196 if (*out == '\0')
197 l += scnprintf(out, sz - l, "N/A");
198 if (hit)
199 l += scnprintf(out + l, sz - l, " hit");
200 if (miss)
201 l += scnprintf(out + l, sz - l, " miss");
202
203 return l;
204 }
205
206 static const char * const snoop_access[] = {
207 "N/A",
208 "None",
209 "Hit",
210 "Miss",
211 "HitM",
212 };
213
214 int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
215 {
216 size_t i, l = 0;
217 u64 m = PERF_MEM_SNOOP_NA;
218
219 sz -= 1; /* -1 for null termination */
220 out[0] = '\0';
221
222 if (mem_info)
223 m = mem_info->data_src.mem_snoop;
224
225 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
226 if (!(m & 0x1))
227 continue;
228 if (l) {
229 strcat(out, " or ");
230 l += 4;
231 }
232 l += scnprintf(out + l, sz - l, snoop_access[i]);
233 }
234
235 if (*out == '\0')
236 l += scnprintf(out, sz - l, "N/A");
237
238 return l;
239 }
240
241 int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
242 {
243 u64 mask = PERF_MEM_LOCK_NA;
244 int l;
245
246 if (mem_info)
247 mask = mem_info->data_src.mem_lock;
248
249 if (mask & PERF_MEM_LOCK_NA)
250 l = scnprintf(out, sz, "N/A");
251 else if (mask & PERF_MEM_LOCK_LOCKED)
252 l = scnprintf(out, sz, "Yes");
253 else
254 l = scnprintf(out, sz, "No");
255
256 return l;
257 }
258
259 int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
260 {
261 int i = 0;
262
263 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
264 i += scnprintf(out + i, sz - i, "|SNP ");
265 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
266 i += scnprintf(out + i, sz - i, "|TLB ");
267 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
268 i += scnprintf(out + i, sz - i, "|LCK ");
269 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
270
271 return i;
272 }
273
274 int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
275 {
276 union perf_mem_data_src *data_src = &mi->data_src;
277 u64 daddr = mi->daddr.addr;
278 u64 op = data_src->mem_op;
279 u64 lvl = data_src->mem_lvl;
280 u64 snoop = data_src->mem_snoop;
281 u64 lock = data_src->mem_lock;
282 int err = 0;
283
284 #define HITM_INC(__f) \
285 do { \
286 stats->__f++; \
287 stats->tot_hitm++; \
288 } while (0)
289
290 #define P(a, b) PERF_MEM_##a##_##b
291
292 stats->nr_entries++;
293
294 if (lock & P(LOCK, LOCKED)) stats->locks++;
295
296 if (op & P(OP, LOAD)) {
297 /* load */
298 stats->load++;
299
300 if (!daddr) {
301 stats->ld_noadrs++;
302 return -1;
303 }
304
305 if (lvl & P(LVL, HIT)) {
306 if (lvl & P(LVL, UNC)) stats->ld_uncache++;
307 if (lvl & P(LVL, IO)) stats->ld_io++;
308 if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
309 if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
310 if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
311 if (lvl & P(LVL, L3 )) {
312 if (snoop & P(SNOOP, HITM))
313 HITM_INC(lcl_hitm);
314 else
315 stats->ld_llchit++;
316 }
317
318 if (lvl & P(LVL, LOC_RAM)) {
319 stats->lcl_dram++;
320 if (snoop & P(SNOOP, HIT))
321 stats->ld_shared++;
322 else
323 stats->ld_excl++;
324 }
325
326 if ((lvl & P(LVL, REM_RAM1)) ||
327 (lvl & P(LVL, REM_RAM2))) {
328 stats->rmt_dram++;
329 if (snoop & P(SNOOP, HIT))
330 stats->ld_shared++;
331 else
332 stats->ld_excl++;
333 }
334 }
335
336 if ((lvl & P(LVL, REM_CCE1)) ||
337 (lvl & P(LVL, REM_CCE2))) {
338 if (snoop & P(SNOOP, HIT))
339 stats->rmt_hit++;
340 else if (snoop & P(SNOOP, HITM))
341 HITM_INC(rmt_hitm);
342 }
343
344 if ((lvl & P(LVL, MISS)))
345 stats->ld_miss++;
346
347 } else if (op & P(OP, STORE)) {
348 /* store */
349 stats->store++;
350
351 if (!daddr) {
352 stats->st_noadrs++;
353 return -1;
354 }
355
356 if (lvl & P(LVL, HIT)) {
357 if (lvl & P(LVL, UNC)) stats->st_uncache++;
358 if (lvl & P(LVL, L1 )) stats->st_l1hit++;
359 }
360 if (lvl & P(LVL, MISS))
361 if (lvl & P(LVL, L1)) stats->st_l1miss++;
362 } else {
363 /* unparsable data_src? */
364 stats->noparse++;
365 return -1;
366 }
367
368 if (!mi->daddr.map || !mi->iaddr.map) {
369 stats->nomap++;
370 return -1;
371 }
372
373 #undef P
374 #undef HITM_INC
375 return err;
376 }
377
378 void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
379 {
380 stats->nr_entries += add->nr_entries;
381
382 stats->locks += add->locks;
383 stats->store += add->store;
384 stats->st_uncache += add->st_uncache;
385 stats->st_noadrs += add->st_noadrs;
386 stats->st_l1hit += add->st_l1hit;
387 stats->st_l1miss += add->st_l1miss;
388 stats->load += add->load;
389 stats->ld_excl += add->ld_excl;
390 stats->ld_shared += add->ld_shared;
391 stats->ld_uncache += add->ld_uncache;
392 stats->ld_io += add->ld_io;
393 stats->ld_miss += add->ld_miss;
394 stats->ld_noadrs += add->ld_noadrs;
395 stats->ld_fbhit += add->ld_fbhit;
396 stats->ld_l1hit += add->ld_l1hit;
397 stats->ld_l2hit += add->ld_l2hit;
398 stats->ld_llchit += add->ld_llchit;
399 stats->lcl_hitm += add->lcl_hitm;
400 stats->rmt_hitm += add->rmt_hitm;
401 stats->tot_hitm += add->tot_hitm;
402 stats->rmt_hit += add->rmt_hit;
403 stats->lcl_dram += add->lcl_dram;
404 stats->rmt_dram += add->rmt_dram;
405 stats->nomap += add->nomap;
406 stats->noparse += add->noparse;
407 }