]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/util/mem-events.c
Merge tag 'iommu-updates-v4.12' 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 <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 }