perf mem: Add --ldlat option
[cascardo/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
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 }