]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/util/mem-events.c
Merge tag 'for-linus-4.10-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.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 #include "sort.h"
13
14 unsigned int perf_mem_events__loads_ldlat = 30;
15
16 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
17
18 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
19         E("ldlat-loads",        "cpu/mem-loads,ldlat=%u/P",     "mem-loads"),
20         E("ldlat-stores",       "cpu/mem-stores/P",             "mem-stores"),
21 };
22 #undef E
23
24 #undef E
25
26 static char mem_loads_name[100];
27 static bool mem_loads_name__init;
28
29 char *perf_mem_events__name(int i)
30 {
31         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
41         return (char *)perf_mem_events[i].name;
42 }
43
44 int 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 }
79
80 int 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 }
103
104 static const char * const tlb_access[] = {
105         "N/A",
106         "HIT",
107         "MISS",
108         "L1",
109         "L2",
110         "Walker",
111         "Fault",
112 };
113
114 int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
115 {
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                 }
139                 l += scnprintf(out + l, sz - l, tlb_access[i]);
140         }
141         if (*out == '\0')
142                 l += scnprintf(out, sz - l, "N/A");
143         if (hit)
144                 l += scnprintf(out + l, sz - l, " hit");
145         if (miss)
146                 l += scnprintf(out + l, sz - l, " miss");
147
148         return l;
149 }
150
151 static 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
168 int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
169 {
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                 }
193                 l += scnprintf(out + l, sz - l, mem_lvl[i]);
194         }
195         if (*out == '\0')
196                 l += scnprintf(out, sz - l, "N/A");
197         if (hit)
198                 l += scnprintf(out + l, sz - l, " hit");
199         if (miss)
200                 l += scnprintf(out + l, sz - l, " miss");
201
202         return l;
203 }
204
205 static const char * const snoop_access[] = {
206         "N/A",
207         "None",
208         "Miss",
209         "Hit",
210         "HitM",
211 };
212
213 int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
214 {
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                 }
231                 l += scnprintf(out + l, sz - l, snoop_access[i]);
232         }
233
234         if (*out == '\0')
235                 l += scnprintf(out, sz - l, "N/A");
236
237         return l;
238 }
239
240 int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
241 {
242         u64 mask = PERF_MEM_LOCK_NA;
243         int l;
244
245         if (mem_info)
246                 mask = mem_info->data_src.mem_lock;
247
248         if (mask & PERF_MEM_LOCK_NA)
249                 l = scnprintf(out, sz, "N/A");
250         else if (mask & PERF_MEM_LOCK_LOCKED)
251                 l = scnprintf(out, sz, "Yes");
252         else
253                 l = scnprintf(out, sz, "No");
254
255         return l;
256 }
257
258 int 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 }
272
273 int 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 HITM_INC(__f)           \
284 do {                            \
285         stats->__f++;           \
286         stats->tot_hitm++;      \
287 } while (0)
288
289 #define P(a, b) PERF_MEM_##a##_##b
290
291         stats->nr_entries++;
292
293         if (lock & P(LOCK, LOCKED)) stats->locks++;
294
295         if (op & P(OP, LOAD)) {
296                 /* load */
297                 stats->load++;
298
299                 if (!daddr) {
300                         stats->ld_noadrs++;
301                         return -1;
302                 }
303
304                 if (lvl & P(LVL, HIT)) {
305                         if (lvl & P(LVL, UNC)) stats->ld_uncache++;
306                         if (lvl & P(LVL, IO))  stats->ld_io++;
307                         if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
308                         if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
309                         if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
310                         if (lvl & P(LVL, L3 )) {
311                                 if (snoop & P(SNOOP, HITM))
312                                         HITM_INC(lcl_hitm);
313                                 else
314                                         stats->ld_llchit++;
315                         }
316
317                         if (lvl & P(LVL, LOC_RAM)) {
318                                 stats->lcl_dram++;
319                                 if (snoop & P(SNOOP, HIT))
320                                         stats->ld_shared++;
321                                 else
322                                         stats->ld_excl++;
323                         }
324
325                         if ((lvl & P(LVL, REM_RAM1)) ||
326                             (lvl & P(LVL, REM_RAM2))) {
327                                 stats->rmt_dram++;
328                                 if (snoop & P(SNOOP, HIT))
329                                         stats->ld_shared++;
330                                 else
331                                         stats->ld_excl++;
332                         }
333                 }
334
335                 if ((lvl & P(LVL, REM_CCE1)) ||
336                     (lvl & P(LVL, REM_CCE2))) {
337                         if (snoop & P(SNOOP, HIT))
338                                 stats->rmt_hit++;
339                         else if (snoop & P(SNOOP, HITM))
340                                 HITM_INC(rmt_hitm);
341                 }
342
343                 if ((lvl & P(LVL, MISS)))
344                         stats->ld_miss++;
345
346         } else if (op & P(OP, STORE)) {
347                 /* store */
348                 stats->store++;
349
350                 if (!daddr) {
351                         stats->st_noadrs++;
352                         return -1;
353                 }
354
355                 if (lvl & P(LVL, HIT)) {
356                         if (lvl & P(LVL, UNC)) stats->st_uncache++;
357                         if (lvl & P(LVL, L1 )) stats->st_l1hit++;
358                 }
359                 if (lvl & P(LVL, MISS))
360                         if (lvl & P(LVL, L1)) stats->st_l1miss++;
361         } else {
362                 /* unparsable data_src? */
363                 stats->noparse++;
364                 return -1;
365         }
366
367         if (!mi->daddr.map || !mi->iaddr.map) {
368                 stats->nomap++;
369                 return -1;
370         }
371
372 #undef P
373 #undef HITM_INC
374         return err;
375 }
376
377 void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
378 {
379         stats->nr_entries       += add->nr_entries;
380
381         stats->locks            += add->locks;
382         stats->store            += add->store;
383         stats->st_uncache       += add->st_uncache;
384         stats->st_noadrs        += add->st_noadrs;
385         stats->st_l1hit         += add->st_l1hit;
386         stats->st_l1miss        += add->st_l1miss;
387         stats->load             += add->load;
388         stats->ld_excl          += add->ld_excl;
389         stats->ld_shared        += add->ld_shared;
390         stats->ld_uncache       += add->ld_uncache;
391         stats->ld_io            += add->ld_io;
392         stats->ld_miss          += add->ld_miss;
393         stats->ld_noadrs        += add->ld_noadrs;
394         stats->ld_fbhit         += add->ld_fbhit;
395         stats->ld_l1hit         += add->ld_l1hit;
396         stats->ld_l2hit         += add->ld_l2hit;
397         stats->ld_llchit        += add->ld_llchit;
398         stats->lcl_hitm         += add->lcl_hitm;
399         stats->rmt_hitm         += add->rmt_hitm;
400         stats->tot_hitm         += add->tot_hitm;
401         stats->rmt_hit          += add->rmt_hit;
402         stats->lcl_dram         += add->lcl_dram;
403         stats->rmt_dram         += add->rmt_dram;
404         stats->nomap            += add->nomap;
405         stats->noparse          += add->noparse;
406 }