blob: bbc368e7d1e4f7f9a53a329fac26d28785db9efc [file] [log] [blame]
Jiri Olsace1e22b2016-02-15 09:34:35 +01001#include <stddef.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
Jiri Olsa54fbad52016-02-24 09:46:42 +01005#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <api/fs/fs.h>
Jiri Olsaacbe6132016-02-15 09:34:34 +01009#include "mem-events.h"
Jiri Olsace1e22b2016-02-15 09:34:35 +010010#include "debug.h"
Jiri Olsa0c877d72016-02-24 09:46:46 +010011#include "symbol.h"
Jiri Olsaacbe6132016-02-15 09:34:34 +010012
Jiri Olsab0d745b2016-06-14 20:19:11 +020013unsigned int perf_mem_events__loads_ldlat = 30;
14
Jiri Olsa54fbad52016-02-24 09:46:42 +010015#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
Jiri Olsaacbe6132016-02-15 09:34:34 +010016
17struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
Jiri Olsab0d745b2016-06-14 20:19:11 +020018 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
Jiri Olsa54fbad52016-02-24 09:46:42 +010019 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
Jiri Olsaacbe6132016-02-15 09:34:34 +010020};
Jiri Olsa54fbad52016-02-24 09:46:42 +010021#undef E
Jiri Olsaacbe6132016-02-15 09:34:34 +010022
23#undef E
Jiri Olsace1e22b2016-02-15 09:34:35 +010024
Jiri Olsab0d745b2016-06-14 20:19:11 +020025static char mem_loads_name[100];
26static bool mem_loads_name__init;
27
Jiri Olsa2ba7ac52016-02-24 09:46:43 +010028char *perf_mem_events__name(int i)
29{
Jiri Olsab0d745b2016-06-14 20:19:11 +020030 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
Jiri Olsa2ba7ac52016-02-24 09:46:43 +010040 return (char *)perf_mem_events[i].name;
41}
42
Jiri Olsace1e22b2016-02-15 09:34:35 +010043int 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}
Jiri Olsa54fbad52016-02-24 09:46:42 +010078
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}
Jiri Olsa0c877d72016-02-24 09:46:46 +0100102
103static const char * const tlb_access[] = {
104 "N/A",
105 "HIT",
106 "MISS",
107 "L1",
108 "L2",
109 "Walker",
110 "Fault",
111};
112
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100113int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa0c877d72016-02-24 09:46:46 +0100114{
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 }
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100138 l += scnprintf(out + l, sz - l, tlb_access[i]);
Jiri Olsa0c877d72016-02-24 09:46:46 +0100139 }
140 if (*out == '\0')
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100141 l += scnprintf(out, sz - l, "N/A");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100142 if (hit)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100143 l += scnprintf(out + l, sz - l, " hit");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100144 if (miss)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100145 l += scnprintf(out + l, sz - l, " miss");
146
147 return l;
Jiri Olsa0c877d72016-02-24 09:46:46 +0100148}
Jiri Olsa071e9a12016-02-24 09:46:47 +0100149
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
Jiri Olsa96907562016-02-24 09:46:51 +0100167int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa071e9a12016-02-24 09:46:47 +0100168{
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 }
Jiri Olsa96907562016-02-24 09:46:51 +0100192 l += scnprintf(out + l, sz - l, mem_lvl[i]);
Jiri Olsa071e9a12016-02-24 09:46:47 +0100193 }
194 if (*out == '\0')
Jiri Olsa96907562016-02-24 09:46:51 +0100195 l += scnprintf(out, sz - l, "N/A");
Jiri Olsa071e9a12016-02-24 09:46:47 +0100196 if (hit)
Jiri Olsa96907562016-02-24 09:46:51 +0100197 l += scnprintf(out + l, sz - l, " hit");
Jiri Olsa071e9a12016-02-24 09:46:47 +0100198 if (miss)
Jiri Olsa96907562016-02-24 09:46:51 +0100199 l += scnprintf(out + l, sz - l, " miss");
200
201 return l;
Jiri Olsa071e9a12016-02-24 09:46:47 +0100202}
Jiri Olsa2c07af12016-02-24 09:46:48 +0100203
204static const char * const snoop_access[] = {
205 "N/A",
206 "None",
207 "Miss",
208 "Hit",
209 "HitM",
210};
211
Jiri Olsa149d7502016-02-24 09:46:52 +0100212int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa2c07af12016-02-24 09:46:48 +0100213{
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 }
Jiri Olsa149d7502016-02-24 09:46:52 +0100230 l += scnprintf(out + l, sz - l, snoop_access[i]);
Jiri Olsa2c07af12016-02-24 09:46:48 +0100231 }
232
233 if (*out == '\0')
Jiri Olsa149d7502016-02-24 09:46:52 +0100234 l += scnprintf(out, sz - l, "N/A");
235
236 return l;
Jiri Olsa2c07af12016-02-24 09:46:48 +0100237}
Jiri Olsa69a77272016-02-24 09:46:49 +0100238
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100239int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa69a77272016-02-24 09:46:49 +0100240{
241 u64 mask = PERF_MEM_LOCK_NA;
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100242 int l;
Jiri Olsa69a77272016-02-24 09:46:49 +0100243
244 if (mem_info)
245 mask = mem_info->data_src.mem_lock;
246
247 if (mask & PERF_MEM_LOCK_NA)
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100248 l = scnprintf(out, sz, "N/A");
Jiri Olsa69a77272016-02-24 09:46:49 +0100249 else if (mask & PERF_MEM_LOCK_LOCKED)
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100250 l = scnprintf(out, sz, "Yes");
Jiri Olsa69a77272016-02-24 09:46:49 +0100251 else
Jiri Olsa8b0819c2016-02-24 09:46:53 +0100252 l = scnprintf(out, sz, "No");
253
254 return l;
Jiri Olsa69a77272016-02-24 09:46:49 +0100255}
Jiri Olsac19ac912016-02-24 09:46:54 +0100256
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}