Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  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}