Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

Feb 18-20, 2025
Register
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}
v5.9
  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}