Merge branch 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
[linux-2.6-block.git] / tools / perf / util / mem-events.c
CommitLineData
ce1e22b0
JO
1#include <stddef.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
54fbad54
JO
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <api/fs/fs.h>
acbe613e 9#include "mem-events.h"
ce1e22b0 10#include "debug.h"
0c877d75 11#include "symbol.h"
acbe613e 12
b0d745b3
JO
13unsigned int perf_mem_events__loads_ldlat = 30;
14
54fbad54 15#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
acbe613e
JO
16
17struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
b0d745b3 18 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
54fbad54 19 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
acbe613e 20};
54fbad54 21#undef E
acbe613e
JO
22
23#undef E
ce1e22b0 24
b0d745b3
JO
25static char mem_loads_name[100];
26static bool mem_loads_name__init;
27
2ba7ac58
JO
28char *perf_mem_events__name(int i)
29{
b0d745b3
JO
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
2ba7ac58
JO
40 return (char *)perf_mem_events[i].name;
41}
42
ce1e22b0
JO
43int 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}
54fbad54
JO
78
79int 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}
0c877d75
JO
102
103static const char * const tlb_access[] = {
104 "N/A",
105 "HIT",
106 "MISS",
107 "L1",
108 "L2",
109 "Walker",
110 "Fault",
111};
112
b1a5fbea 113int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
0c877d75
JO
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 }
b1a5fbea 138 l += scnprintf(out + l, sz - l, tlb_access[i]);
0c877d75
JO
139 }
140 if (*out == '\0')
b1a5fbea 141 l += scnprintf(out, sz - l, "N/A");
0c877d75 142 if (hit)
b1a5fbea 143 l += scnprintf(out + l, sz - l, " hit");
0c877d75 144 if (miss)
b1a5fbea
JO
145 l += scnprintf(out + l, sz - l, " miss");
146
147 return l;
0c877d75 148}
071e9a1e
JO
149
150static 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
96907563 167int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
071e9a1e
JO
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 }
96907563 192 l += scnprintf(out + l, sz - l, mem_lvl[i]);
071e9a1e
JO
193 }
194 if (*out == '\0')
96907563 195 l += scnprintf(out, sz - l, "N/A");
071e9a1e 196 if (hit)
96907563 197 l += scnprintf(out + l, sz - l, " hit");
071e9a1e 198 if (miss)
96907563
JO
199 l += scnprintf(out + l, sz - l, " miss");
200
201 return l;
071e9a1e 202}
2c07af13
JO
203
204static const char * const snoop_access[] = {
205 "N/A",
206 "None",
207 "Miss",
208 "Hit",
209 "HitM",
210};
211
149d7507 212int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
2c07af13
JO
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 }
149d7507 230 l += scnprintf(out + l, sz - l, snoop_access[i]);
2c07af13
JO
231 }
232
233 if (*out == '\0')
149d7507
JO
234 l += scnprintf(out, sz - l, "N/A");
235
236 return l;
2c07af13 237}
69a77275 238
8b0819c8 239int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
69a77275
JO
240{
241 u64 mask = PERF_MEM_LOCK_NA;
8b0819c8 242 int l;
69a77275
JO
243
244 if (mem_info)
245 mask = mem_info->data_src.mem_lock;
246
247 if (mask & PERF_MEM_LOCK_NA)
8b0819c8 248 l = scnprintf(out, sz, "N/A");
69a77275 249 else if (mask & PERF_MEM_LOCK_LOCKED)
8b0819c8 250 l = scnprintf(out, sz, "Yes");
69a77275 251 else
8b0819c8
JO
252 l = scnprintf(out, sz, "No");
253
254 return l;
69a77275 255}
c19ac912
JO
256
257int 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}