Linux Audio

Check our new training course

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