Merge tag 'char-misc-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-block.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 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
14
15 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
16         E("ldlat-loads",        "cpu/mem-loads,ldlat=30/P",     "mem-loads"),
17         E("ldlat-stores",       "cpu/mem-stores/P",             "mem-stores"),
18 };
19 #undef E
20
21 #undef E
22
23 char *perf_mem_events__name(int i)
24 {
25         return (char *)perf_mem_events[i].name;
26 }
27
28 int perf_mem_events__parse(const char *str)
29 {
30         char *tok, *saveptr = NULL;
31         bool found = false;
32         char *buf;
33         int j;
34
35         /* We need buffer that we know we can write to. */
36         buf = malloc(strlen(str) + 1);
37         if (!buf)
38                 return -ENOMEM;
39
40         strcpy(buf, str);
41
42         tok = strtok_r((char *)buf, ",", &saveptr);
43
44         while (tok) {
45                 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
46                         struct perf_mem_event *e = &perf_mem_events[j];
47
48                         if (strstr(e->tag, tok))
49                                 e->record = found = true;
50                 }
51
52                 tok = strtok_r(NULL, ",", &saveptr);
53         }
54
55         free(buf);
56
57         if (found)
58                 return 0;
59
60         pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
61         return -1;
62 }
63
64 int perf_mem_events__init(void)
65 {
66         const char *mnt = sysfs__mount();
67         bool found = false;
68         int j;
69
70         if (!mnt)
71                 return -ENOENT;
72
73         for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
74                 char path[PATH_MAX];
75                 struct perf_mem_event *e = &perf_mem_events[j];
76                 struct stat st;
77
78                 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
79                           mnt, e->sysfs_name);
80
81                 if (!stat(path, &st))
82                         e->supported = found = true;
83         }
84
85         return found ? 0 : -ENOENT;
86 }
87
88 static const char * const tlb_access[] = {
89         "N/A",
90         "HIT",
91         "MISS",
92         "L1",
93         "L2",
94         "Walker",
95         "Fault",
96 };
97
98 int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
99 {
100         size_t l = 0, i;
101         u64 m = PERF_MEM_TLB_NA;
102         u64 hit, miss;
103
104         sz -= 1; /* -1 for null termination */
105         out[0] = '\0';
106
107         if (mem_info)
108                 m = mem_info->data_src.mem_dtlb;
109
110         hit = m & PERF_MEM_TLB_HIT;
111         miss = m & PERF_MEM_TLB_MISS;
112
113         /* already taken care of */
114         m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
115
116         for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
117                 if (!(m & 0x1))
118                         continue;
119                 if (l) {
120                         strcat(out, " or ");
121                         l += 4;
122                 }
123                 l += scnprintf(out + l, sz - l, tlb_access[i]);
124         }
125         if (*out == '\0')
126                 l += scnprintf(out, sz - l, "N/A");
127         if (hit)
128                 l += scnprintf(out + l, sz - l, " hit");
129         if (miss)
130                 l += scnprintf(out + l, sz - l, " miss");
131
132         return l;
133 }
134
135 static const char * const mem_lvl[] = {
136         "N/A",
137         "HIT",
138         "MISS",
139         "L1",
140         "LFB",
141         "L2",
142         "L3",
143         "Local RAM",
144         "Remote RAM (1 hop)",
145         "Remote RAM (2 hops)",
146         "Remote Cache (1 hop)",
147         "Remote Cache (2 hops)",
148         "I/O",
149         "Uncached",
150 };
151
152 int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
153 {
154         size_t i, l = 0;
155         u64 m =  PERF_MEM_LVL_NA;
156         u64 hit, miss;
157
158         if (mem_info)
159                 m  = mem_info->data_src.mem_lvl;
160
161         sz -= 1; /* -1 for null termination */
162         out[0] = '\0';
163
164         hit = m & PERF_MEM_LVL_HIT;
165         miss = m & PERF_MEM_LVL_MISS;
166
167         /* already taken care of */
168         m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
169
170         for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
171                 if (!(m & 0x1))
172                         continue;
173                 if (l) {
174                         strcat(out, " or ");
175                         l += 4;
176                 }
177                 l += scnprintf(out + l, sz - l, mem_lvl[i]);
178         }
179         if (*out == '\0')
180                 l += scnprintf(out, sz - l, "N/A");
181         if (hit)
182                 l += scnprintf(out + l, sz - l, " hit");
183         if (miss)
184                 l += scnprintf(out + l, sz - l, " miss");
185
186         return l;
187 }
188
189 static const char * const snoop_access[] = {
190         "N/A",
191         "None",
192         "Miss",
193         "Hit",
194         "HitM",
195 };
196
197 int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
198 {
199         size_t i, l = 0;
200         u64 m = PERF_MEM_SNOOP_NA;
201
202         sz -= 1; /* -1 for null termination */
203         out[0] = '\0';
204
205         if (mem_info)
206                 m = mem_info->data_src.mem_snoop;
207
208         for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
209                 if (!(m & 0x1))
210                         continue;
211                 if (l) {
212                         strcat(out, " or ");
213                         l += 4;
214                 }
215                 l += scnprintf(out + l, sz - l, snoop_access[i]);
216         }
217
218         if (*out == '\0')
219                 l += scnprintf(out, sz - l, "N/A");
220
221         return l;
222 }
223
224 int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
225 {
226         u64 mask = PERF_MEM_LOCK_NA;
227         int l;
228
229         if (mem_info)
230                 mask = mem_info->data_src.mem_lock;
231
232         if (mask & PERF_MEM_LOCK_NA)
233                 l = scnprintf(out, sz, "N/A");
234         else if (mask & PERF_MEM_LOCK_LOCKED)
235                 l = scnprintf(out, sz, "Yes");
236         else
237                 l = scnprintf(out, sz, "No");
238
239         return l;
240 }
241
242 int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
243 {
244         int i = 0;
245
246         i += perf_mem__lvl_scnprintf(out, sz, mem_info);
247         i += scnprintf(out + i, sz - i, "|SNP ");
248         i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
249         i += scnprintf(out + i, sz - i, "|TLB ");
250         i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
251         i += scnprintf(out + i, sz - i, "|LCK ");
252         i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
253
254         return i;
255 }