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
 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}