Loading...
1// SPDX-License-Identifier: GPL-2.0
2#include <stddef.h>
3#include <stdlib.h>
4#include <string.h>
5#include <errno.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include <api/fs/fs.h>
10#include <linux/kernel.h>
11#include "map_symbol.h"
12#include "mem-events.h"
13#include "debug.h"
14#include "symbol.h"
15
16unsigned int perf_mem_events__loads_ldlat = 30;
17
18#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
19
20struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
21 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
22 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
23};
24#undef E
25
26#undef E
27
28static char mem_loads_name[100];
29static bool mem_loads_name__init;
30
31char * __weak perf_mem_events__name(int i)
32{
33 if (i == PERF_MEM_EVENTS__LOAD) {
34 if (!mem_loads_name__init) {
35 mem_loads_name__init = true;
36 scnprintf(mem_loads_name, sizeof(mem_loads_name),
37 perf_mem_events[i].name,
38 perf_mem_events__loads_ldlat);
39 }
40 return mem_loads_name;
41 }
42
43 return (char *)perf_mem_events[i].name;
44}
45
46int perf_mem_events__parse(const char *str)
47{
48 char *tok, *saveptr = NULL;
49 bool found = false;
50 char *buf;
51 int j;
52
53 /* We need buffer that we know we can write to. */
54 buf = malloc(strlen(str) + 1);
55 if (!buf)
56 return -ENOMEM;
57
58 strcpy(buf, str);
59
60 tok = strtok_r((char *)buf, ",", &saveptr);
61
62 while (tok) {
63 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
64 struct perf_mem_event *e = &perf_mem_events[j];
65
66 if (strstr(e->tag, tok))
67 e->record = found = true;
68 }
69
70 tok = strtok_r(NULL, ",", &saveptr);
71 }
72
73 free(buf);
74
75 if (found)
76 return 0;
77
78 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
79 return -1;
80}
81
82int perf_mem_events__init(void)
83{
84 const char *mnt = sysfs__mount();
85 bool found = false;
86 int j;
87
88 if (!mnt)
89 return -ENOENT;
90
91 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
92 char path[PATH_MAX];
93 struct perf_mem_event *e = &perf_mem_events[j];
94 struct stat st;
95
96 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
97 mnt, e->sysfs_name);
98
99 if (!stat(path, &st))
100 e->supported = found = true;
101 }
102
103 return found ? 0 : -ENOENT;
104}
105
106static const char * const tlb_access[] = {
107 "N/A",
108 "HIT",
109 "MISS",
110 "L1",
111 "L2",
112 "Walker",
113 "Fault",
114};
115
116int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
117{
118 size_t l = 0, i;
119 u64 m = PERF_MEM_TLB_NA;
120 u64 hit, miss;
121
122 sz -= 1; /* -1 for null termination */
123 out[0] = '\0';
124
125 if (mem_info)
126 m = mem_info->data_src.mem_dtlb;
127
128 hit = m & PERF_MEM_TLB_HIT;
129 miss = m & PERF_MEM_TLB_MISS;
130
131 /* already taken care of */
132 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
133
134 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
135 if (!(m & 0x1))
136 continue;
137 if (l) {
138 strcat(out, " or ");
139 l += 4;
140 }
141 l += scnprintf(out + l, sz - l, tlb_access[i]);
142 }
143 if (*out == '\0')
144 l += scnprintf(out, sz - l, "N/A");
145 if (hit)
146 l += scnprintf(out + l, sz - l, " hit");
147 if (miss)
148 l += scnprintf(out + l, sz - l, " miss");
149
150 return l;
151}
152
153static const char * const mem_lvl[] = {
154 "N/A",
155 "HIT",
156 "MISS",
157 "L1",
158 "LFB",
159 "L2",
160 "L3",
161 "Local RAM",
162 "Remote RAM (1 hop)",
163 "Remote RAM (2 hops)",
164 "Remote Cache (1 hop)",
165 "Remote Cache (2 hops)",
166 "I/O",
167 "Uncached",
168};
169
170static const char * const mem_lvlnum[] = {
171 [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
172 [PERF_MEM_LVLNUM_LFB] = "LFB",
173 [PERF_MEM_LVLNUM_RAM] = "RAM",
174 [PERF_MEM_LVLNUM_PMEM] = "PMEM",
175 [PERF_MEM_LVLNUM_NA] = "N/A",
176};
177
178int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
179{
180 size_t i, l = 0;
181 u64 m = PERF_MEM_LVL_NA;
182 u64 hit, miss;
183 int printed;
184
185 if (mem_info)
186 m = mem_info->data_src.mem_lvl;
187
188 sz -= 1; /* -1 for null termination */
189 out[0] = '\0';
190
191 hit = m & PERF_MEM_LVL_HIT;
192 miss = m & PERF_MEM_LVL_MISS;
193
194 /* already taken care of */
195 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
196
197
198 if (mem_info && mem_info->data_src.mem_remote) {
199 strcat(out, "Remote ");
200 l += 7;
201 }
202
203 printed = 0;
204 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
205 if (!(m & 0x1))
206 continue;
207 if (printed++) {
208 strcat(out, " or ");
209 l += 4;
210 }
211 l += scnprintf(out + l, sz - l, mem_lvl[i]);
212 }
213
214 if (mem_info && mem_info->data_src.mem_lvl_num) {
215 int lvl = mem_info->data_src.mem_lvl_num;
216 if (printed++) {
217 strcat(out, " or ");
218 l += 4;
219 }
220 if (mem_lvlnum[lvl])
221 l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
222 else
223 l += scnprintf(out + l, sz - l, "L%d", lvl);
224 }
225
226 if (l == 0)
227 l += scnprintf(out + l, sz - l, "N/A");
228 if (hit)
229 l += scnprintf(out + l, sz - l, " hit");
230 if (miss)
231 l += scnprintf(out + l, sz - l, " miss");
232
233 return l;
234}
235
236static const char * const snoop_access[] = {
237 "N/A",
238 "None",
239 "Hit",
240 "Miss",
241 "HitM",
242};
243
244int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
245{
246 size_t i, l = 0;
247 u64 m = PERF_MEM_SNOOP_NA;
248
249 sz -= 1; /* -1 for null termination */
250 out[0] = '\0';
251
252 if (mem_info)
253 m = mem_info->data_src.mem_snoop;
254
255 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
256 if (!(m & 0x1))
257 continue;
258 if (l) {
259 strcat(out, " or ");
260 l += 4;
261 }
262 l += scnprintf(out + l, sz - l, snoop_access[i]);
263 }
264 if (mem_info &&
265 (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) {
266 if (l) {
267 strcat(out, " or ");
268 l += 4;
269 }
270 l += scnprintf(out + l, sz - l, "Fwd");
271 }
272
273 if (*out == '\0')
274 l += scnprintf(out, sz - l, "N/A");
275
276 return l;
277}
278
279int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
280{
281 u64 mask = PERF_MEM_LOCK_NA;
282 int l;
283
284 if (mem_info)
285 mask = mem_info->data_src.mem_lock;
286
287 if (mask & PERF_MEM_LOCK_NA)
288 l = scnprintf(out, sz, "N/A");
289 else if (mask & PERF_MEM_LOCK_LOCKED)
290 l = scnprintf(out, sz, "Yes");
291 else
292 l = scnprintf(out, sz, "No");
293
294 return l;
295}
296
297int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
298{
299 int i = 0;
300
301 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
302 i += scnprintf(out + i, sz - i, "|SNP ");
303 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
304 i += scnprintf(out + i, sz - i, "|TLB ");
305 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
306 i += scnprintf(out + i, sz - i, "|LCK ");
307 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
308
309 return i;
310}
311
312int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
313{
314 union perf_mem_data_src *data_src = &mi->data_src;
315 u64 daddr = mi->daddr.addr;
316 u64 op = data_src->mem_op;
317 u64 lvl = data_src->mem_lvl;
318 u64 snoop = data_src->mem_snoop;
319 u64 lock = data_src->mem_lock;
320 /*
321 * Skylake might report unknown remote level via this
322 * bit, consider it when evaluating remote HITMs.
323 */
324 bool mrem = data_src->mem_remote;
325 int err = 0;
326
327#define HITM_INC(__f) \
328do { \
329 stats->__f++; \
330 stats->tot_hitm++; \
331} while (0)
332
333#define P(a, b) PERF_MEM_##a##_##b
334
335 stats->nr_entries++;
336
337 if (lock & P(LOCK, LOCKED)) stats->locks++;
338
339 if (op & P(OP, LOAD)) {
340 /* load */
341 stats->load++;
342
343 if (!daddr) {
344 stats->ld_noadrs++;
345 return -1;
346 }
347
348 if (lvl & P(LVL, HIT)) {
349 if (lvl & P(LVL, UNC)) stats->ld_uncache++;
350 if (lvl & P(LVL, IO)) stats->ld_io++;
351 if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
352 if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
353 if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
354 if (lvl & P(LVL, L3 )) {
355 if (snoop & P(SNOOP, HITM))
356 HITM_INC(lcl_hitm);
357 else
358 stats->ld_llchit++;
359 }
360
361 if (lvl & P(LVL, LOC_RAM)) {
362 stats->lcl_dram++;
363 if (snoop & P(SNOOP, HIT))
364 stats->ld_shared++;
365 else
366 stats->ld_excl++;
367 }
368
369 if ((lvl & P(LVL, REM_RAM1)) ||
370 (lvl & P(LVL, REM_RAM2)) ||
371 mrem) {
372 stats->rmt_dram++;
373 if (snoop & P(SNOOP, HIT))
374 stats->ld_shared++;
375 else
376 stats->ld_excl++;
377 }
378 }
379
380 if ((lvl & P(LVL, REM_CCE1)) ||
381 (lvl & P(LVL, REM_CCE2)) ||
382 mrem) {
383 if (snoop & P(SNOOP, HIT))
384 stats->rmt_hit++;
385 else if (snoop & P(SNOOP, HITM))
386 HITM_INC(rmt_hitm);
387 }
388
389 if ((lvl & P(LVL, MISS)))
390 stats->ld_miss++;
391
392 } else if (op & P(OP, STORE)) {
393 /* store */
394 stats->store++;
395
396 if (!daddr) {
397 stats->st_noadrs++;
398 return -1;
399 }
400
401 if (lvl & P(LVL, HIT)) {
402 if (lvl & P(LVL, UNC)) stats->st_uncache++;
403 if (lvl & P(LVL, L1 )) stats->st_l1hit++;
404 }
405 if (lvl & P(LVL, MISS))
406 if (lvl & P(LVL, L1)) stats->st_l1miss++;
407 } else {
408 /* unparsable data_src? */
409 stats->noparse++;
410 return -1;
411 }
412
413 if (!mi->daddr.map || !mi->iaddr.map) {
414 stats->nomap++;
415 return -1;
416 }
417
418#undef P
419#undef HITM_INC
420 return err;
421}
422
423void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
424{
425 stats->nr_entries += add->nr_entries;
426
427 stats->locks += add->locks;
428 stats->store += add->store;
429 stats->st_uncache += add->st_uncache;
430 stats->st_noadrs += add->st_noadrs;
431 stats->st_l1hit += add->st_l1hit;
432 stats->st_l1miss += add->st_l1miss;
433 stats->load += add->load;
434 stats->ld_excl += add->ld_excl;
435 stats->ld_shared += add->ld_shared;
436 stats->ld_uncache += add->ld_uncache;
437 stats->ld_io += add->ld_io;
438 stats->ld_miss += add->ld_miss;
439 stats->ld_noadrs += add->ld_noadrs;
440 stats->ld_fbhit += add->ld_fbhit;
441 stats->ld_l1hit += add->ld_l1hit;
442 stats->ld_l2hit += add->ld_l2hit;
443 stats->ld_llchit += add->ld_llchit;
444 stats->lcl_hitm += add->lcl_hitm;
445 stats->rmt_hitm += add->rmt_hitm;
446 stats->tot_hitm += add->tot_hitm;
447 stats->rmt_hit += add->rmt_hit;
448 stats->lcl_dram += add->lcl_dram;
449 stats->rmt_dram += add->rmt_dram;
450 stats->nomap += add->nomap;
451 stats->noparse += add->noparse;
452}
1// SPDX-License-Identifier: GPL-2.0
2#include <stddef.h>
3#include <stdlib.h>
4#include <string.h>
5#include <errno.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include <api/fs/fs.h>
10#include <linux/kernel.h>
11#include "map_symbol.h"
12#include "mem-events.h"
13#include "debug.h"
14#include "symbol.h"
15
16unsigned int perf_mem_events__loads_ldlat = 30;
17
18#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
19
20struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
21 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
22 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
23};
24#undef E
25
26#undef E
27
28static char mem_loads_name[100];
29static bool mem_loads_name__init;
30
31char * __weak perf_mem_events__name(int i)
32{
33 if (i == PERF_MEM_EVENTS__LOAD) {
34 if (!mem_loads_name__init) {
35 mem_loads_name__init = true;
36 scnprintf(mem_loads_name, sizeof(mem_loads_name),
37 perf_mem_events[i].name,
38 perf_mem_events__loads_ldlat);
39 }
40 return mem_loads_name;
41 }
42
43 return (char *)perf_mem_events[i].name;
44}
45
46int perf_mem_events__parse(const char *str)
47{
48 char *tok, *saveptr = NULL;
49 bool found = false;
50 char *buf;
51 int j;
52
53 /* We need buffer that we know we can write to. */
54 buf = malloc(strlen(str) + 1);
55 if (!buf)
56 return -ENOMEM;
57
58 strcpy(buf, str);
59
60 tok = strtok_r((char *)buf, ",", &saveptr);
61
62 while (tok) {
63 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
64 struct perf_mem_event *e = &perf_mem_events[j];
65
66 if (strstr(e->tag, tok))
67 e->record = found = true;
68 }
69
70 tok = strtok_r(NULL, ",", &saveptr);
71 }
72
73 free(buf);
74
75 if (found)
76 return 0;
77
78 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
79 return -1;
80}
81
82int perf_mem_events__init(void)
83{
84 const char *mnt = sysfs__mount();
85 bool found = false;
86 int j;
87
88 if (!mnt)
89 return -ENOENT;
90
91 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
92 char path[PATH_MAX];
93 struct perf_mem_event *e = &perf_mem_events[j];
94 struct stat st;
95
96 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
97 mnt, e->sysfs_name);
98
99 if (!stat(path, &st))
100 e->supported = found = true;
101 }
102
103 return found ? 0 : -ENOENT;
104}
105
106void perf_mem_events__list(void)
107{
108 int j;
109
110 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
111 struct perf_mem_event *e = &perf_mem_events[j];
112
113 fprintf(stderr, "%-13s%-*s%s\n",
114 e->tag,
115 verbose > 0 ? 25 : 0,
116 verbose > 0 ? perf_mem_events__name(j) : "",
117 e->supported ? ": available" : "");
118 }
119}
120
121static const char * const tlb_access[] = {
122 "N/A",
123 "HIT",
124 "MISS",
125 "L1",
126 "L2",
127 "Walker",
128 "Fault",
129};
130
131int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
132{
133 size_t l = 0, i;
134 u64 m = PERF_MEM_TLB_NA;
135 u64 hit, miss;
136
137 sz -= 1; /* -1 for null termination */
138 out[0] = '\0';
139
140 if (mem_info)
141 m = mem_info->data_src.mem_dtlb;
142
143 hit = m & PERF_MEM_TLB_HIT;
144 miss = m & PERF_MEM_TLB_MISS;
145
146 /* already taken care of */
147 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
148
149 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
150 if (!(m & 0x1))
151 continue;
152 if (l) {
153 strcat(out, " or ");
154 l += 4;
155 }
156 l += scnprintf(out + l, sz - l, tlb_access[i]);
157 }
158 if (*out == '\0')
159 l += scnprintf(out, sz - l, "N/A");
160 if (hit)
161 l += scnprintf(out + l, sz - l, " hit");
162 if (miss)
163 l += scnprintf(out + l, sz - l, " miss");
164
165 return l;
166}
167
168static const char * const mem_lvl[] = {
169 "N/A",
170 "HIT",
171 "MISS",
172 "L1",
173 "LFB",
174 "L2",
175 "L3",
176 "Local RAM",
177 "Remote RAM (1 hop)",
178 "Remote RAM (2 hops)",
179 "Remote Cache (1 hop)",
180 "Remote Cache (2 hops)",
181 "I/O",
182 "Uncached",
183};
184
185static const char * const mem_lvlnum[] = {
186 [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
187 [PERF_MEM_LVLNUM_LFB] = "LFB",
188 [PERF_MEM_LVLNUM_RAM] = "RAM",
189 [PERF_MEM_LVLNUM_PMEM] = "PMEM",
190 [PERF_MEM_LVLNUM_NA] = "N/A",
191};
192
193int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
194{
195 size_t i, l = 0;
196 u64 m = PERF_MEM_LVL_NA;
197 u64 hit, miss;
198 int printed;
199
200 if (mem_info)
201 m = mem_info->data_src.mem_lvl;
202
203 sz -= 1; /* -1 for null termination */
204 out[0] = '\0';
205
206 hit = m & PERF_MEM_LVL_HIT;
207 miss = m & PERF_MEM_LVL_MISS;
208
209 /* already taken care of */
210 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
211
212
213 if (mem_info && mem_info->data_src.mem_remote) {
214 strcat(out, "Remote ");
215 l += 7;
216 }
217
218 printed = 0;
219 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
220 if (!(m & 0x1))
221 continue;
222 if (printed++) {
223 strcat(out, " or ");
224 l += 4;
225 }
226 l += scnprintf(out + l, sz - l, mem_lvl[i]);
227 }
228
229 if (mem_info && mem_info->data_src.mem_lvl_num) {
230 int lvl = mem_info->data_src.mem_lvl_num;
231 if (printed++) {
232 strcat(out, " or ");
233 l += 4;
234 }
235 if (mem_lvlnum[lvl])
236 l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
237 else
238 l += scnprintf(out + l, sz - l, "L%d", lvl);
239 }
240
241 if (l == 0)
242 l += scnprintf(out + l, sz - l, "N/A");
243 if (hit)
244 l += scnprintf(out + l, sz - l, " hit");
245 if (miss)
246 l += scnprintf(out + l, sz - l, " miss");
247
248 return l;
249}
250
251static const char * const snoop_access[] = {
252 "N/A",
253 "None",
254 "Hit",
255 "Miss",
256 "HitM",
257};
258
259int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
260{
261 size_t i, l = 0;
262 u64 m = PERF_MEM_SNOOP_NA;
263
264 sz -= 1; /* -1 for null termination */
265 out[0] = '\0';
266
267 if (mem_info)
268 m = mem_info->data_src.mem_snoop;
269
270 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
271 if (!(m & 0x1))
272 continue;
273 if (l) {
274 strcat(out, " or ");
275 l += 4;
276 }
277 l += scnprintf(out + l, sz - l, snoop_access[i]);
278 }
279 if (mem_info &&
280 (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) {
281 if (l) {
282 strcat(out, " or ");
283 l += 4;
284 }
285 l += scnprintf(out + l, sz - l, "Fwd");
286 }
287
288 if (*out == '\0')
289 l += scnprintf(out, sz - l, "N/A");
290
291 return l;
292}
293
294int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
295{
296 u64 mask = PERF_MEM_LOCK_NA;
297 int l;
298
299 if (mem_info)
300 mask = mem_info->data_src.mem_lock;
301
302 if (mask & PERF_MEM_LOCK_NA)
303 l = scnprintf(out, sz, "N/A");
304 else if (mask & PERF_MEM_LOCK_LOCKED)
305 l = scnprintf(out, sz, "Yes");
306 else
307 l = scnprintf(out, sz, "No");
308
309 return l;
310}
311
312int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
313{
314 int i = 0;
315
316 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
317 i += scnprintf(out + i, sz - i, "|SNP ");
318 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
319 i += scnprintf(out + i, sz - i, "|TLB ");
320 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
321 i += scnprintf(out + i, sz - i, "|LCK ");
322 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
323
324 return i;
325}
326
327int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
328{
329 union perf_mem_data_src *data_src = &mi->data_src;
330 u64 daddr = mi->daddr.addr;
331 u64 op = data_src->mem_op;
332 u64 lvl = data_src->mem_lvl;
333 u64 snoop = data_src->mem_snoop;
334 u64 lock = data_src->mem_lock;
335 /*
336 * Skylake might report unknown remote level via this
337 * bit, consider it when evaluating remote HITMs.
338 */
339 bool mrem = data_src->mem_remote;
340 int err = 0;
341
342#define HITM_INC(__f) \
343do { \
344 stats->__f++; \
345 stats->tot_hitm++; \
346} while (0)
347
348#define P(a, b) PERF_MEM_##a##_##b
349
350 stats->nr_entries++;
351
352 if (lock & P(LOCK, LOCKED)) stats->locks++;
353
354 if (op & P(OP, LOAD)) {
355 /* load */
356 stats->load++;
357
358 if (!daddr) {
359 stats->ld_noadrs++;
360 return -1;
361 }
362
363 if (lvl & P(LVL, HIT)) {
364 if (lvl & P(LVL, UNC)) stats->ld_uncache++;
365 if (lvl & P(LVL, IO)) stats->ld_io++;
366 if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
367 if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
368 if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
369 if (lvl & P(LVL, L3 )) {
370 if (snoop & P(SNOOP, HITM))
371 HITM_INC(lcl_hitm);
372 else
373 stats->ld_llchit++;
374 }
375
376 if (lvl & P(LVL, LOC_RAM)) {
377 stats->lcl_dram++;
378 if (snoop & P(SNOOP, HIT))
379 stats->ld_shared++;
380 else
381 stats->ld_excl++;
382 }
383
384 if ((lvl & P(LVL, REM_RAM1)) ||
385 (lvl & P(LVL, REM_RAM2)) ||
386 mrem) {
387 stats->rmt_dram++;
388 if (snoop & P(SNOOP, HIT))
389 stats->ld_shared++;
390 else
391 stats->ld_excl++;
392 }
393 }
394
395 if ((lvl & P(LVL, REM_CCE1)) ||
396 (lvl & P(LVL, REM_CCE2)) ||
397 mrem) {
398 if (snoop & P(SNOOP, HIT))
399 stats->rmt_hit++;
400 else if (snoop & P(SNOOP, HITM))
401 HITM_INC(rmt_hitm);
402 }
403
404 if ((lvl & P(LVL, MISS)))
405 stats->ld_miss++;
406
407 } else if (op & P(OP, STORE)) {
408 /* store */
409 stats->store++;
410
411 if (!daddr) {
412 stats->st_noadrs++;
413 return -1;
414 }
415
416 if (lvl & P(LVL, HIT)) {
417 if (lvl & P(LVL, UNC)) stats->st_uncache++;
418 if (lvl & P(LVL, L1 )) stats->st_l1hit++;
419 }
420 if (lvl & P(LVL, MISS))
421 if (lvl & P(LVL, L1)) stats->st_l1miss++;
422 } else {
423 /* unparsable data_src? */
424 stats->noparse++;
425 return -1;
426 }
427
428 if (!mi->daddr.ms.map || !mi->iaddr.ms.map) {
429 stats->nomap++;
430 return -1;
431 }
432
433#undef P
434#undef HITM_INC
435 return err;
436}
437
438void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
439{
440 stats->nr_entries += add->nr_entries;
441
442 stats->locks += add->locks;
443 stats->store += add->store;
444 stats->st_uncache += add->st_uncache;
445 stats->st_noadrs += add->st_noadrs;
446 stats->st_l1hit += add->st_l1hit;
447 stats->st_l1miss += add->st_l1miss;
448 stats->load += add->load;
449 stats->ld_excl += add->ld_excl;
450 stats->ld_shared += add->ld_shared;
451 stats->ld_uncache += add->ld_uncache;
452 stats->ld_io += add->ld_io;
453 stats->ld_miss += add->ld_miss;
454 stats->ld_noadrs += add->ld_noadrs;
455 stats->ld_fbhit += add->ld_fbhit;
456 stats->ld_l1hit += add->ld_l1hit;
457 stats->ld_l2hit += add->ld_l2hit;
458 stats->ld_llchit += add->ld_llchit;
459 stats->lcl_hitm += add->lcl_hitm;
460 stats->rmt_hitm += add->rmt_hitm;
461 stats->tot_hitm += add->tot_hitm;
462 stats->rmt_hit += add->rmt_hit;
463 stats->lcl_dram += add->lcl_dram;
464 stats->rmt_dram += add->rmt_dram;
465 stats->nomap += add->nomap;
466 stats->noparse += add->noparse;
467}