blob: e50773286ef62d46495fbc479c76c65ac9bebafb [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 Olsaaadddd62016-09-22 17:36:30 +020012#include "sort.h"
Jiri Olsaacbe6132016-02-15 09:34:34 +010013
Jiri Olsab0d745b2016-06-14 20:19:11 +020014unsigned int perf_mem_events__loads_ldlat = 30;
15
Jiri Olsa54fbad52016-02-24 09:46:42 +010016#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
Jiri Olsaacbe6132016-02-15 09:34:34 +010017
18struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
Jiri Olsab0d745b2016-06-14 20:19:11 +020019 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
Jiri Olsa54fbad52016-02-24 09:46:42 +010020 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
Jiri Olsaacbe6132016-02-15 09:34:34 +010021};
Jiri Olsa54fbad52016-02-24 09:46:42 +010022#undef E
Jiri Olsaacbe6132016-02-15 09:34:34 +010023
24#undef E
Jiri Olsace1e22b2016-02-15 09:34:35 +010025
Jiri Olsab0d745b2016-06-14 20:19:11 +020026static char mem_loads_name[100];
27static bool mem_loads_name__init;
28
Jiri Olsa2ba7ac52016-02-24 09:46:43 +010029char *perf_mem_events__name(int i)
30{
Jiri Olsab0d745b2016-06-14 20:19:11 +020031 if (i == PERF_MEM_EVENTS__LOAD) {
32 if (!mem_loads_name__init) {
33 mem_loads_name__init = true;
34 scnprintf(mem_loads_name, sizeof(mem_loads_name),
35 perf_mem_events[i].name,
36 perf_mem_events__loads_ldlat);
37 }
38 return mem_loads_name;
39 }
40
Jiri Olsa2ba7ac52016-02-24 09:46:43 +010041 return (char *)perf_mem_events[i].name;
42}
43
Jiri Olsace1e22b2016-02-15 09:34:35 +010044int perf_mem_events__parse(const char *str)
45{
46 char *tok, *saveptr = NULL;
47 bool found = false;
48 char *buf;
49 int j;
50
51 /* We need buffer that we know we can write to. */
52 buf = malloc(strlen(str) + 1);
53 if (!buf)
54 return -ENOMEM;
55
56 strcpy(buf, str);
57
58 tok = strtok_r((char *)buf, ",", &saveptr);
59
60 while (tok) {
61 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
62 struct perf_mem_event *e = &perf_mem_events[j];
63
64 if (strstr(e->tag, tok))
65 e->record = found = true;
66 }
67
68 tok = strtok_r(NULL, ",", &saveptr);
69 }
70
71 free(buf);
72
73 if (found)
74 return 0;
75
76 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
77 return -1;
78}
Jiri Olsa54fbad52016-02-24 09:46:42 +010079
80int perf_mem_events__init(void)
81{
82 const char *mnt = sysfs__mount();
83 bool found = false;
84 int j;
85
86 if (!mnt)
87 return -ENOENT;
88
89 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
90 char path[PATH_MAX];
91 struct perf_mem_event *e = &perf_mem_events[j];
92 struct stat st;
93
94 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
95 mnt, e->sysfs_name);
96
97 if (!stat(path, &st))
98 e->supported = found = true;
99 }
100
101 return found ? 0 : -ENOENT;
102}
Jiri Olsa0c877d72016-02-24 09:46:46 +0100103
104static const char * const tlb_access[] = {
105 "N/A",
106 "HIT",
107 "MISS",
108 "L1",
109 "L2",
110 "Walker",
111 "Fault",
112};
113
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100114int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa0c877d72016-02-24 09:46:46 +0100115{
116 size_t l = 0, i;
117 u64 m = PERF_MEM_TLB_NA;
118 u64 hit, miss;
119
120 sz -= 1; /* -1 for null termination */
121 out[0] = '\0';
122
123 if (mem_info)
124 m = mem_info->data_src.mem_dtlb;
125
126 hit = m & PERF_MEM_TLB_HIT;
127 miss = m & PERF_MEM_TLB_MISS;
128
129 /* already taken care of */
130 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
131
132 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
133 if (!(m & 0x1))
134 continue;
135 if (l) {
136 strcat(out, " or ");
137 l += 4;
138 }
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100139 l += scnprintf(out + l, sz - l, tlb_access[i]);
Jiri Olsa0c877d72016-02-24 09:46:46 +0100140 }
141 if (*out == '\0')
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100142 l += scnprintf(out, sz - l, "N/A");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100143 if (hit)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100144 l += scnprintf(out + l, sz - l, " hit");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100145 if (miss)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100146 l += scnprintf(out + l, sz - l, " miss");
147
148 return l;
Jiri Olsa0c877d72016-02-24 09:46:46 +0100149}
Jiri Olsa071e9a12016-02-24 09:46:47 +0100150
151static const char * const mem_lvl[] = {
152 "N/A",
153 "HIT",
154 "MISS",
155 "L1",
156 "LFB",
157 "L2",
158 "L3",
159 "Local RAM",
160 "Remote RAM (1 hop)",
161 "Remote RAM (2 hops)",
162 "Remote Cache (1 hop)",
163 "Remote Cache (2 hops)",
164 "I/O",
165 "Uncached",
166};
167
Jiri Olsa96907562016-02-24 09:46:51 +0100168int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa071e9a12016-02-24 09:46:47 +0100169{
170 size_t i, l = 0;
171 u64 m = PERF_MEM_LVL_NA;
172 u64 hit, miss;
173
174 if (mem_info)
175 m = mem_info->data_src.mem_lvl;
176
177 sz -= 1; /* -1 for null termination */
178 out[0] = '\0';
179
180 hit = m & PERF_MEM_LVL_HIT;
181 miss = m & PERF_MEM_LVL_MISS;
182
183 /* already taken care of */
184 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
185
186 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
187 if (!(m & 0x1))
188 continue;
189 if (l) {
190 strcat(out, " or ");
191 l += 4;
192 }
Jiri Olsa96907562016-02-24 09:46:51 +0100193 l += scnprintf(out + l, sz - l, mem_lvl[i]);
Jiri Olsa071e9a12016-02-24 09:46:47 +0100194 }
195 if (*out == '\0')
Jiri Olsa96907562016-02-24 09:46:51 +0100196 l += scnprintf(out, sz - l, "N/A");
Jiri Olsa071e9a12016-02-24 09:46:47 +0100197 if (hit)
Jiri Olsa96907562016-02-24 09:46:51 +0100198 l += scnprintf(out + l, sz - l, " hit");
Jiri Olsa071e9a12016-02-24 09:46:47 +0100199 if (miss)
Jiri Olsa96907562016-02-24 09:46:51 +0100200 l += scnprintf(out + l, sz - l, " miss");
201
202 return l;
Jiri Olsa071e9a12016-02-24 09:46:47 +0100203}
Jiri Olsa2c07af12016-02-24 09:46:48 +0100204
205static const char * const snoop_access[] = {
206 "N/A",
207 "None",
208 "Miss",
209 "Hit",
210 "HitM",
211};
212
Jiri Olsa149d7502016-02-24 09:46:52 +0100213int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa2c07af12016-02-24 09:46:48 +0100214{
215 size_t i, l = 0;
216 u64 m = PERF_MEM_SNOOP_NA;
217
218 sz -= 1; /* -1 for null termination */
219 out[0] = '\0';
220
221 if (mem_info)
222 m = mem_info->data_src.mem_snoop;
223
224 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
225 if (!(m & 0x1))
226 continue;
227 if (l) {
228 strcat(out, " or ");
229 l += 4;
230 }
Jiri Olsa149d7502016-02-24 09:46:52 +0100231 l += scnprintf(out + l, sz - l, snoop_access[i]);
Jiri Olsa2c07af12016-02-24 09:46:48 +0100232 }
233
234 if (*out == '\0')
Jiri Olsa149d7502016-02-24 09:46:52 +0100235 l += scnprintf(out, sz - l, "N/A");
236
237 return l;
Jiri Olsa2c07af12016-02-24 09:46:48 +0100238}
Jiri Olsa69a77272016-02-24 09:46:49 +0100239
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100240int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa69a77272016-02-24 09:46:49 +0100241{
242 u64 mask = PERF_MEM_LOCK_NA;
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100243 int l;
Jiri Olsa69a77272016-02-24 09:46:49 +0100244
245 if (mem_info)
246 mask = mem_info->data_src.mem_lock;
247
248 if (mask & PERF_MEM_LOCK_NA)
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100249 l = scnprintf(out, sz, "N/A");
Jiri Olsa69a77272016-02-24 09:46:49 +0100250 else if (mask & PERF_MEM_LOCK_LOCKED)
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100251 l = scnprintf(out, sz, "Yes");
Jiri Olsa69a77272016-02-24 09:46:49 +0100252 else
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100253 l = scnprintf(out, sz, "No");
254
255 return l;
Jiri Olsa69a77272016-02-24 09:46:49 +0100256}
Jiri Olsac19ac912016-02-24 09:46:54 +0100257
258int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
259{
260 int i = 0;
261
262 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
263 i += scnprintf(out + i, sz - i, "|SNP ");
264 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
265 i += scnprintf(out + i, sz - i, "|TLB ");
266 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
267 i += scnprintf(out + i, sz - i, "|LCK ");
268 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
269
270 return i;
271}
Jiri Olsaaadddd62016-09-22 17:36:30 +0200272
273int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
274{
275 union perf_mem_data_src *data_src = &mi->data_src;
276 u64 daddr = mi->daddr.addr;
277 u64 op = data_src->mem_op;
278 u64 lvl = data_src->mem_lvl;
279 u64 snoop = data_src->mem_snoop;
280 u64 lock = data_src->mem_lock;
281 int err = 0;
282
283#define P(a, b) PERF_MEM_##a##_##b
284
285 stats->nr_entries++;
286
287 if (lock & P(LOCK, LOCKED)) stats->locks++;
288
289 if (op & P(OP, LOAD)) {
290 /* load */
291 stats->load++;
292
293 if (!daddr) {
294 stats->ld_noadrs++;
295 return -1;
296 }
297
298 if (lvl & P(LVL, HIT)) {
299 if (lvl & P(LVL, UNC)) stats->ld_uncache++;
300 if (lvl & P(LVL, IO)) stats->ld_io++;
301 if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
302 if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
303 if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
304 if (lvl & P(LVL, L3 )) {
305 if (snoop & P(SNOOP, HITM))
306 stats->lcl_hitm++;
307 else
308 stats->ld_llchit++;
309 }
310
311 if (lvl & P(LVL, LOC_RAM)) {
312 stats->lcl_dram++;
313 if (snoop & P(SNOOP, HIT))
314 stats->ld_shared++;
315 else
316 stats->ld_excl++;
317 }
318
319 if ((lvl & P(LVL, REM_RAM1)) ||
320 (lvl & P(LVL, REM_RAM2))) {
321 stats->rmt_dram++;
322 if (snoop & P(SNOOP, HIT))
323 stats->ld_shared++;
324 else
325 stats->ld_excl++;
326 }
327 }
328
329 if ((lvl & P(LVL, REM_CCE1)) ||
330 (lvl & P(LVL, REM_CCE2))) {
331 if (snoop & P(SNOOP, HIT))
332 stats->rmt_hit++;
333 else if (snoop & P(SNOOP, HITM))
334 stats->rmt_hitm++;
335 }
336
337 if ((lvl & P(LVL, MISS)))
338 stats->ld_miss++;
339
340 } else if (op & P(OP, STORE)) {
341 /* store */
342 stats->store++;
343
344 if (!daddr) {
345 stats->st_noadrs++;
346 return -1;
347 }
348
349 if (lvl & P(LVL, HIT)) {
350 if (lvl & P(LVL, UNC)) stats->st_uncache++;
351 if (lvl & P(LVL, L1 )) stats->st_l1hit++;
352 }
353 if (lvl & P(LVL, MISS))
354 if (lvl & P(LVL, L1)) stats->st_l1miss++;
355 } else {
356 /* unparsable data_src? */
357 stats->noparse++;
358 return -1;
359 }
360
361 if (!mi->daddr.map || !mi->iaddr.map) {
362 stats->nomap++;
363 return -1;
364 }
365
366#undef P
367 return err;
368}
Jiri Olsa0a9a24c2016-09-22 17:36:31 +0200369
370void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
371{
372 stats->nr_entries += add->nr_entries;
373
374 stats->locks += add->locks;
375 stats->store += add->store;
376 stats->st_uncache += add->st_uncache;
377 stats->st_noadrs += add->st_noadrs;
378 stats->st_l1hit += add->st_l1hit;
379 stats->st_l1miss += add->st_l1miss;
380 stats->load += add->load;
381 stats->ld_excl += add->ld_excl;
382 stats->ld_shared += add->ld_shared;
383 stats->ld_uncache += add->ld_uncache;
384 stats->ld_io += add->ld_io;
385 stats->ld_miss += add->ld_miss;
386 stats->ld_noadrs += add->ld_noadrs;
387 stats->ld_fbhit += add->ld_fbhit;
388 stats->ld_l1hit += add->ld_l1hit;
389 stats->ld_l2hit += add->ld_l2hit;
390 stats->ld_llchit += add->ld_llchit;
391 stats->lcl_hitm += add->lcl_hitm;
392 stats->rmt_hitm += add->rmt_hitm;
393 stats->rmt_hit += add->rmt_hit;
394 stats->lcl_dram += add->lcl_dram;
395 stats->rmt_dram += add->rmt_dram;
396 stats->nomap += add->nomap;
397 stats->noparse += add->noparse;
398}