Linux Audio

Check our new training course

Loading...
v4.6
 
  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}
v5.14.15
  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}