Loading...
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
15struct 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
23char *perf_mem_events__name(int i)
24{
25 return (char *)perf_mem_events[i].name;
26}
27
28int 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
64int 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
88static const char * const tlb_access[] = {
89 "N/A",
90 "HIT",
91 "MISS",
92 "L1",
93 "L2",
94 "Walker",
95 "Fault",
96};
97
98int 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
135static 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
152int 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
189static const char * const snoop_access[] = {
190 "N/A",
191 "None",
192 "Miss",
193 "Hit",
194 "HitM",
195};
196
197int 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
224int 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
242int 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}
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#include "pmu.h"
16#include "pmu-hybrid.h"
17
18unsigned int perf_mem_events__loads_ldlat = 30;
19
20#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
21
22static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
23 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "cpu/events/mem-loads"),
24 E("ldlat-stores", "cpu/mem-stores/P", "cpu/events/mem-stores"),
25 E(NULL, NULL, NULL),
26};
27#undef E
28
29static char mem_loads_name[100];
30static bool mem_loads_name__init;
31
32struct perf_mem_event * __weak perf_mem_events__ptr(int i)
33{
34 if (i >= PERF_MEM_EVENTS__MAX)
35 return NULL;
36
37 return &perf_mem_events[i];
38}
39
40char * __weak perf_mem_events__name(int i, char *pmu_name __maybe_unused)
41{
42 struct perf_mem_event *e = perf_mem_events__ptr(i);
43
44 if (!e)
45 return NULL;
46
47 if (i == PERF_MEM_EVENTS__LOAD) {
48 if (!mem_loads_name__init) {
49 mem_loads_name__init = true;
50 scnprintf(mem_loads_name, sizeof(mem_loads_name),
51 e->name, perf_mem_events__loads_ldlat);
52 }
53 return mem_loads_name;
54 }
55
56 return (char *)e->name;
57}
58
59__weak bool is_mem_loads_aux_event(struct evsel *leader __maybe_unused)
60{
61 return false;
62}
63
64int perf_mem_events__parse(const char *str)
65{
66 char *tok, *saveptr = NULL;
67 bool found = false;
68 char *buf;
69 int j;
70
71 /* We need buffer that we know we can write to. */
72 buf = malloc(strlen(str) + 1);
73 if (!buf)
74 return -ENOMEM;
75
76 strcpy(buf, str);
77
78 tok = strtok_r((char *)buf, ",", &saveptr);
79
80 while (tok) {
81 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
82 struct perf_mem_event *e = perf_mem_events__ptr(j);
83
84 if (!e->tag)
85 continue;
86
87 if (strstr(e->tag, tok))
88 e->record = found = true;
89 }
90
91 tok = strtok_r(NULL, ",", &saveptr);
92 }
93
94 free(buf);
95
96 if (found)
97 return 0;
98
99 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
100 return -1;
101}
102
103static bool perf_mem_event__supported(const char *mnt, char *sysfs_name)
104{
105 char path[PATH_MAX];
106 struct stat st;
107
108 scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name);
109 return !stat(path, &st);
110}
111
112int perf_mem_events__init(void)
113{
114 const char *mnt = sysfs__mount();
115 bool found = false;
116 int j;
117
118 if (!mnt)
119 return -ENOENT;
120
121 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
122 struct perf_mem_event *e = perf_mem_events__ptr(j);
123 struct perf_pmu *pmu;
124 char sysfs_name[100];
125
126 /*
127 * If the event entry isn't valid, skip initialization
128 * and "e->supported" will keep false.
129 */
130 if (!e->tag)
131 continue;
132
133 if (!perf_pmu__has_hybrid()) {
134 scnprintf(sysfs_name, sizeof(sysfs_name),
135 e->sysfs_name, "cpu");
136 e->supported = perf_mem_event__supported(mnt, sysfs_name);
137 } else {
138 perf_pmu__for_each_hybrid_pmu(pmu) {
139 scnprintf(sysfs_name, sizeof(sysfs_name),
140 e->sysfs_name, pmu->name);
141 e->supported |= perf_mem_event__supported(mnt, sysfs_name);
142 }
143 }
144
145 if (e->supported)
146 found = true;
147 }
148
149 return found ? 0 : -ENOENT;
150}
151
152void perf_mem_events__list(void)
153{
154 int j;
155
156 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
157 struct perf_mem_event *e = perf_mem_events__ptr(j);
158
159 fprintf(stderr, "%-13s%-*s%s\n",
160 e->tag ?: "",
161 verbose > 0 ? 25 : 0,
162 verbose > 0 ? perf_mem_events__name(j, NULL) : "",
163 e->supported ? ": available" : "");
164 }
165}
166
167static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e,
168 int idx)
169{
170 const char *mnt = sysfs__mount();
171 char sysfs_name[100];
172 struct perf_pmu *pmu;
173
174 perf_pmu__for_each_hybrid_pmu(pmu) {
175 scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name,
176 pmu->name);
177 if (!perf_mem_event__supported(mnt, sysfs_name)) {
178 pr_err("failed: event '%s' not supported\n",
179 perf_mem_events__name(idx, pmu->name));
180 }
181 }
182}
183
184int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
185 char **rec_tmp, int *tmp_nr)
186{
187 int i = *argv_nr, k = 0;
188 struct perf_mem_event *e;
189 struct perf_pmu *pmu;
190 char *s;
191
192 for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
193 e = perf_mem_events__ptr(j);
194 if (!e->record)
195 continue;
196
197 if (!perf_pmu__has_hybrid()) {
198 if (!e->supported) {
199 pr_err("failed: event '%s' not supported\n",
200 perf_mem_events__name(j, NULL));
201 return -1;
202 }
203
204 rec_argv[i++] = "-e";
205 rec_argv[i++] = perf_mem_events__name(j, NULL);
206 } else {
207 if (!e->supported) {
208 perf_mem_events__print_unsupport_hybrid(e, j);
209 return -1;
210 }
211
212 perf_pmu__for_each_hybrid_pmu(pmu) {
213 rec_argv[i++] = "-e";
214 s = perf_mem_events__name(j, pmu->name);
215 if (s) {
216 s = strdup(s);
217 if (!s)
218 return -1;
219
220 rec_argv[i++] = s;
221 rec_tmp[k++] = s;
222 }
223 }
224 }
225 }
226
227 *argv_nr = i;
228 *tmp_nr = k;
229 return 0;
230}
231
232static const char * const tlb_access[] = {
233 "N/A",
234 "HIT",
235 "MISS",
236 "L1",
237 "L2",
238 "Walker",
239 "Fault",
240};
241
242int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
243{
244 size_t l = 0, i;
245 u64 m = PERF_MEM_TLB_NA;
246 u64 hit, miss;
247
248 sz -= 1; /* -1 for null termination */
249 out[0] = '\0';
250
251 if (mem_info)
252 m = mem_info->data_src.mem_dtlb;
253
254 hit = m & PERF_MEM_TLB_HIT;
255 miss = m & PERF_MEM_TLB_MISS;
256
257 /* already taken care of */
258 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
259
260 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
261 if (!(m & 0x1))
262 continue;
263 if (l) {
264 strcat(out, " or ");
265 l += 4;
266 }
267 l += scnprintf(out + l, sz - l, tlb_access[i]);
268 }
269 if (*out == '\0')
270 l += scnprintf(out, sz - l, "N/A");
271 if (hit)
272 l += scnprintf(out + l, sz - l, " hit");
273 if (miss)
274 l += scnprintf(out + l, sz - l, " miss");
275
276 return l;
277}
278
279static const char * const mem_lvl[] = {
280 "N/A",
281 "HIT",
282 "MISS",
283 "L1",
284 "LFB",
285 "L2",
286 "L3",
287 "Local RAM",
288 "Remote RAM (1 hop)",
289 "Remote RAM (2 hops)",
290 "Remote Cache (1 hop)",
291 "Remote Cache (2 hops)",
292 "I/O",
293 "Uncached",
294};
295
296static const char * const mem_lvlnum[] = {
297 [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
298 [PERF_MEM_LVLNUM_LFB] = "LFB",
299 [PERF_MEM_LVLNUM_RAM] = "RAM",
300 [PERF_MEM_LVLNUM_PMEM] = "PMEM",
301 [PERF_MEM_LVLNUM_NA] = "N/A",
302};
303
304int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
305{
306 size_t i, l = 0;
307 u64 m = PERF_MEM_LVL_NA;
308 u64 hit, miss;
309 int printed;
310
311 if (mem_info)
312 m = mem_info->data_src.mem_lvl;
313
314 sz -= 1; /* -1 for null termination */
315 out[0] = '\0';
316
317 hit = m & PERF_MEM_LVL_HIT;
318 miss = m & PERF_MEM_LVL_MISS;
319
320 /* already taken care of */
321 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
322
323
324 if (mem_info && mem_info->data_src.mem_remote) {
325 strcat(out, "Remote ");
326 l += 7;
327 }
328
329 printed = 0;
330 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
331 if (!(m & 0x1))
332 continue;
333 if (printed++) {
334 strcat(out, " or ");
335 l += 4;
336 }
337 l += scnprintf(out + l, sz - l, mem_lvl[i]);
338 }
339
340 if (mem_info && mem_info->data_src.mem_lvl_num) {
341 int lvl = mem_info->data_src.mem_lvl_num;
342 if (printed++) {
343 strcat(out, " or ");
344 l += 4;
345 }
346 if (mem_lvlnum[lvl])
347 l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
348 else
349 l += scnprintf(out + l, sz - l, "L%d", lvl);
350 }
351
352 if (l == 0)
353 l += scnprintf(out + l, sz - l, "N/A");
354 if (hit)
355 l += scnprintf(out + l, sz - l, " hit");
356 if (miss)
357 l += scnprintf(out + l, sz - l, " miss");
358
359 return l;
360}
361
362static const char * const snoop_access[] = {
363 "N/A",
364 "None",
365 "Hit",
366 "Miss",
367 "HitM",
368};
369
370int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
371{
372 size_t i, l = 0;
373 u64 m = PERF_MEM_SNOOP_NA;
374
375 sz -= 1; /* -1 for null termination */
376 out[0] = '\0';
377
378 if (mem_info)
379 m = mem_info->data_src.mem_snoop;
380
381 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
382 if (!(m & 0x1))
383 continue;
384 if (l) {
385 strcat(out, " or ");
386 l += 4;
387 }
388 l += scnprintf(out + l, sz - l, snoop_access[i]);
389 }
390 if (mem_info &&
391 (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) {
392 if (l) {
393 strcat(out, " or ");
394 l += 4;
395 }
396 l += scnprintf(out + l, sz - l, "Fwd");
397 }
398
399 if (*out == '\0')
400 l += scnprintf(out, sz - l, "N/A");
401
402 return l;
403}
404
405int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
406{
407 u64 mask = PERF_MEM_LOCK_NA;
408 int l;
409
410 if (mem_info)
411 mask = mem_info->data_src.mem_lock;
412
413 if (mask & PERF_MEM_LOCK_NA)
414 l = scnprintf(out, sz, "N/A");
415 else if (mask & PERF_MEM_LOCK_LOCKED)
416 l = scnprintf(out, sz, "Yes");
417 else
418 l = scnprintf(out, sz, "No");
419
420 return l;
421}
422
423int perf_mem__blk_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
424{
425 size_t l = 0;
426 u64 mask = PERF_MEM_BLK_NA;
427
428 sz -= 1; /* -1 for null termination */
429 out[0] = '\0';
430
431 if (mem_info)
432 mask = mem_info->data_src.mem_blk;
433
434 if (!mask || (mask & PERF_MEM_BLK_NA)) {
435 l += scnprintf(out + l, sz - l, " N/A");
436 return l;
437 }
438 if (mask & PERF_MEM_BLK_DATA)
439 l += scnprintf(out + l, sz - l, " Data");
440 if (mask & PERF_MEM_BLK_ADDR)
441 l += scnprintf(out + l, sz - l, " Addr");
442
443 return l;
444}
445
446int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
447{
448 int i = 0;
449
450 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
451 i += scnprintf(out + i, sz - i, "|SNP ");
452 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
453 i += scnprintf(out + i, sz - i, "|TLB ");
454 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
455 i += scnprintf(out + i, sz - i, "|LCK ");
456 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
457 i += scnprintf(out + i, sz - i, "|BLK ");
458 i += perf_mem__blk_scnprintf(out + i, sz - i, mem_info);
459
460 return i;
461}
462
463int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
464{
465 union perf_mem_data_src *data_src = &mi->data_src;
466 u64 daddr = mi->daddr.addr;
467 u64 op = data_src->mem_op;
468 u64 lvl = data_src->mem_lvl;
469 u64 snoop = data_src->mem_snoop;
470 u64 lock = data_src->mem_lock;
471 u64 blk = data_src->mem_blk;
472 /*
473 * Skylake might report unknown remote level via this
474 * bit, consider it when evaluating remote HITMs.
475 */
476 bool mrem = data_src->mem_remote;
477 int err = 0;
478
479#define HITM_INC(__f) \
480do { \
481 stats->__f++; \
482 stats->tot_hitm++; \
483} while (0)
484
485#define P(a, b) PERF_MEM_##a##_##b
486
487 stats->nr_entries++;
488
489 if (lock & P(LOCK, LOCKED)) stats->locks++;
490
491 if (blk & P(BLK, DATA)) stats->blk_data++;
492 if (blk & P(BLK, ADDR)) stats->blk_addr++;
493
494 if (op & P(OP, LOAD)) {
495 /* load */
496 stats->load++;
497
498 if (!daddr) {
499 stats->ld_noadrs++;
500 return -1;
501 }
502
503 if (lvl & P(LVL, HIT)) {
504 if (lvl & P(LVL, UNC)) stats->ld_uncache++;
505 if (lvl & P(LVL, IO)) stats->ld_io++;
506 if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
507 if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
508 if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
509 if (lvl & P(LVL, L3 )) {
510 if (snoop & P(SNOOP, HITM))
511 HITM_INC(lcl_hitm);
512 else
513 stats->ld_llchit++;
514 }
515
516 if (lvl & P(LVL, LOC_RAM)) {
517 stats->lcl_dram++;
518 if (snoop & P(SNOOP, HIT))
519 stats->ld_shared++;
520 else
521 stats->ld_excl++;
522 }
523
524 if ((lvl & P(LVL, REM_RAM1)) ||
525 (lvl & P(LVL, REM_RAM2)) ||
526 mrem) {
527 stats->rmt_dram++;
528 if (snoop & P(SNOOP, HIT))
529 stats->ld_shared++;
530 else
531 stats->ld_excl++;
532 }
533 }
534
535 if ((lvl & P(LVL, REM_CCE1)) ||
536 (lvl & P(LVL, REM_CCE2)) ||
537 mrem) {
538 if (snoop & P(SNOOP, HIT))
539 stats->rmt_hit++;
540 else if (snoop & P(SNOOP, HITM))
541 HITM_INC(rmt_hitm);
542 }
543
544 if ((lvl & P(LVL, MISS)))
545 stats->ld_miss++;
546
547 } else if (op & P(OP, STORE)) {
548 /* store */
549 stats->store++;
550
551 if (!daddr) {
552 stats->st_noadrs++;
553 return -1;
554 }
555
556 if (lvl & P(LVL, HIT)) {
557 if (lvl & P(LVL, UNC)) stats->st_uncache++;
558 if (lvl & P(LVL, L1 )) stats->st_l1hit++;
559 }
560 if (lvl & P(LVL, MISS))
561 if (lvl & P(LVL, L1)) stats->st_l1miss++;
562 } else {
563 /* unparsable data_src? */
564 stats->noparse++;
565 return -1;
566 }
567
568 if (!mi->daddr.ms.map || !mi->iaddr.ms.map) {
569 stats->nomap++;
570 return -1;
571 }
572
573#undef P
574#undef HITM_INC
575 return err;
576}
577
578void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
579{
580 stats->nr_entries += add->nr_entries;
581
582 stats->locks += add->locks;
583 stats->store += add->store;
584 stats->st_uncache += add->st_uncache;
585 stats->st_noadrs += add->st_noadrs;
586 stats->st_l1hit += add->st_l1hit;
587 stats->st_l1miss += add->st_l1miss;
588 stats->load += add->load;
589 stats->ld_excl += add->ld_excl;
590 stats->ld_shared += add->ld_shared;
591 stats->ld_uncache += add->ld_uncache;
592 stats->ld_io += add->ld_io;
593 stats->ld_miss += add->ld_miss;
594 stats->ld_noadrs += add->ld_noadrs;
595 stats->ld_fbhit += add->ld_fbhit;
596 stats->ld_l1hit += add->ld_l1hit;
597 stats->ld_l2hit += add->ld_l2hit;
598 stats->ld_llchit += add->ld_llchit;
599 stats->lcl_hitm += add->lcl_hitm;
600 stats->rmt_hitm += add->rmt_hitm;
601 stats->tot_hitm += add->tot_hitm;
602 stats->rmt_hit += add->rmt_hit;
603 stats->lcl_dram += add->lcl_dram;
604 stats->rmt_dram += add->rmt_dram;
605 stats->blk_data += add->blk_data;
606 stats->blk_addr += add->blk_addr;
607 stats->nomap += add->nomap;
608 stats->noparse += add->noparse;
609}