xref: /openbmc/linux/tools/perf/util/parse-events.c (revision 74d5b5889ea71a95d8924c08f8a7c6e2bdcbc0ba)
1 
2 #include "../perf.h"
3 #include "util.h"
4 #include "parse-options.h"
5 #include "parse-events.h"
6 #include "exec_cmd.h"
7 #include "string.h"
8 
9 extern char *strcasestr(const char *haystack, const char *needle);
10 
11 int					nr_counters;
12 
13 struct perf_counter_attr		attrs[MAX_COUNTERS];
14 
15 struct event_symbol {
16 	u8	type;
17 	u64	config;
18 	char	*symbol;
19 	char	*alias;
20 };
21 
22 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
23 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
24 
25 static struct event_symbol event_symbols[] = {
26   { CHW(CPU_CYCLES),		"cpu-cycles",		"cycles"	},
27   { CHW(INSTRUCTIONS),		"instructions",		""		},
28   { CHW(CACHE_REFERENCES),	"cache-references",	""		},
29   { CHW(CACHE_MISSES),		"cache-misses",		""		},
30   { CHW(BRANCH_INSTRUCTIONS),	"branch-instructions",	"branches"	},
31   { CHW(BRANCH_MISSES),		"branch-misses",	""		},
32   { CHW(BUS_CYCLES),		"bus-cycles",		""		},
33 
34   { CSW(CPU_CLOCK),		"cpu-clock",		""		},
35   { CSW(TASK_CLOCK),		"task-clock",		""		},
36   { CSW(PAGE_FAULTS),		"page-faults",		""		},
37   { CSW(PAGE_FAULTS),		"faults",		""		},
38   { CSW(PAGE_FAULTS_MIN),	"minor-faults",		""		},
39   { CSW(PAGE_FAULTS_MAJ),	"major-faults",		""		},
40   { CSW(CONTEXT_SWITCHES),	"context-switches",	"cs"		},
41   { CSW(CPU_MIGRATIONS),	"cpu-migrations",	"migrations"	},
42 };
43 
44 #define __PERF_COUNTER_FIELD(config, name) \
45 	((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
46 
47 #define PERF_COUNTER_RAW(config)	__PERF_COUNTER_FIELD(config, RAW)
48 #define PERF_COUNTER_CONFIG(config)	__PERF_COUNTER_FIELD(config, CONFIG)
49 #define PERF_COUNTER_TYPE(config)	__PERF_COUNTER_FIELD(config, TYPE)
50 #define PERF_COUNTER_ID(config)		__PERF_COUNTER_FIELD(config, EVENT)
51 
52 static char *hw_event_names[] = {
53 	"cycles",
54 	"instructions",
55 	"cache-references",
56 	"cache-misses",
57 	"branches",
58 	"branch-misses",
59 	"bus-cycles",
60 };
61 
62 static char *sw_event_names[] = {
63 	"cpu-clock-msecs",
64 	"task-clock-msecs",
65 	"page-faults",
66 	"context-switches",
67 	"CPU-migrations",
68 	"minor-faults",
69 	"major-faults",
70 };
71 
72 #define MAX_ALIASES 8
73 
74 static char *hw_cache [][MAX_ALIASES] = {
75 	{ "L1-data"		, "l1-d", "l1d"					},
76 	{ "L1-instruction"	, "l1-i", "l1i"					},
77 	{ "L2"			, "l2"						},
78 	{ "Data-TLB"		, "dtlb", "d-tlb"				},
79 	{ "Instruction-TLB"	, "itlb", "i-tlb"				},
80 	{ "Branch"		, "bpu" , "btb", "bpc"				},
81 };
82 
83 static char *hw_cache_op [][MAX_ALIASES] = {
84 	{ "Load"		, "read"					},
85 	{ "Store"		, "write"					},
86 	{ "Prefetch"		, "speculative-read", "speculative-load"	},
87 };
88 
89 static char *hw_cache_result [][MAX_ALIASES] = {
90 	{ "Reference"		, "ops", "access"				},
91 	{ "Miss"								},
92 };
93 
94 char *event_name(int counter)
95 {
96 	u64 config = attrs[counter].config;
97 	int type = attrs[counter].type;
98 	static char buf[32];
99 
100 	if (attrs[counter].type == PERF_TYPE_RAW) {
101 		sprintf(buf, "raw 0x%llx", config);
102 		return buf;
103 	}
104 
105 	switch (type) {
106 	case PERF_TYPE_HARDWARE:
107 		if (config < PERF_COUNT_HW_MAX)
108 			return hw_event_names[config];
109 		return "unknown-hardware";
110 
111 	case PERF_TYPE_HW_CACHE: {
112 		u8 cache_type, cache_op, cache_result;
113 		static char name[100];
114 
115 		cache_type   = (config >>  0) & 0xff;
116 		if (cache_type > PERF_COUNT_HW_CACHE_MAX)
117 			return "unknown-ext-hardware-cache-type";
118 
119 		cache_op     = (config >>  8) & 0xff;
120 		if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
121 			return "unknown-ext-hardware-cache-op";
122 
123 		cache_result = (config >> 16) & 0xff;
124 		if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
125 			return "unknown-ext-hardware-cache-result";
126 
127 		sprintf(name, "%s-Cache-%s-%ses",
128 			hw_cache[cache_type][0],
129 			hw_cache_op[cache_op][0],
130 			hw_cache_result[cache_result][0]);
131 
132 		return name;
133 	}
134 
135 	case PERF_TYPE_SOFTWARE:
136 		if (config < PERF_COUNT_SW_MAX)
137 			return sw_event_names[config];
138 		return "unknown-software";
139 
140 	default:
141 		break;
142 	}
143 
144 	return "unknown";
145 }
146 
147 static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
148 {
149 	int i, j;
150 
151 	for (i = 0; i < size; i++) {
152 		for (j = 0; j < MAX_ALIASES; j++) {
153 			if (!names[i][j])
154 				break;
155 			if (strcasestr(str, names[i][j]))
156 				return i;
157 		}
158 	}
159 
160 	return -1;
161 }
162 
163 static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
164 {
165 	int cache_type = -1, cache_op = 0, cache_result = 0;
166 
167 	cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX);
168 	/*
169 	 * No fallback - if we cannot get a clear cache type
170 	 * then bail out:
171 	 */
172 	if (cache_type == -1)
173 		return -EINVAL;
174 
175 	cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
176 	/*
177 	 * Fall back to reads:
178 	 */
179 	if (cache_op == -1)
180 		cache_op = PERF_COUNT_HW_CACHE_OP_READ;
181 
182 	cache_result = parse_aliases(str, hw_cache_result,
183 					PERF_COUNT_HW_CACHE_RESULT_MAX);
184 	/*
185 	 * Fall back to accesses:
186 	 */
187 	if (cache_result == -1)
188 		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
189 
190 	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
191 	attr->type = PERF_TYPE_HW_CACHE;
192 
193 	return 0;
194 }
195 
196 static int check_events(const char *str, unsigned int i)
197 {
198 	if (!strncmp(str, event_symbols[i].symbol,
199 		     strlen(event_symbols[i].symbol)))
200 		return 1;
201 
202 	if (strlen(event_symbols[i].alias))
203 		if (!strncmp(str, event_symbols[i].alias,
204 		      strlen(event_symbols[i].alias)))
205 			return 1;
206 	return 0;
207 }
208 
209 /*
210  * Each event can have multiple symbolic names.
211  * Symbolic names are (almost) exactly matched.
212  */
213 static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
214 {
215 	u64 config, id;
216 	int type;
217 	unsigned int i;
218 	const char *sep, *pstr;
219 
220 	if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
221 		attr->type = PERF_TYPE_RAW;
222 		attr->config = config;
223 
224 		return 0;
225 	}
226 
227 	pstr = str;
228 	sep = strchr(pstr, ':');
229 	if (sep) {
230 		type = atoi(pstr);
231 		pstr = sep + 1;
232 		id = atoi(pstr);
233 		sep = strchr(pstr, ':');
234 		if (sep) {
235 			pstr = sep + 1;
236 			if (strchr(pstr, 'k'))
237 				attr->exclude_user = 1;
238 			if (strchr(pstr, 'u'))
239 				attr->exclude_kernel = 1;
240 		}
241 		attr->type = type;
242 		attr->config = id;
243 
244 		return 0;
245 	}
246 
247 	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
248 		if (check_events(str, i)) {
249 			attr->type = event_symbols[i].type;
250 			attr->config = event_symbols[i].config;
251 
252 			return 0;
253 		}
254 	}
255 
256 	return parse_generic_hw_symbols(str, attr);
257 }
258 
259 int parse_events(const struct option *opt, const char *str, int unset)
260 {
261 	struct perf_counter_attr attr;
262 	int ret;
263 
264 	memset(&attr, 0, sizeof(attr));
265 again:
266 	if (nr_counters == MAX_COUNTERS)
267 		return -1;
268 
269 	ret = parse_event_symbols(str, &attr);
270 	if (ret < 0)
271 		return ret;
272 
273 	attrs[nr_counters] = attr;
274 	nr_counters++;
275 
276 	str = strstr(str, ",");
277 	if (str) {
278 		str++;
279 		goto again;
280 	}
281 
282 	return 0;
283 }
284 
285 static const char * const event_type_descriptors[] = {
286 	"",
287 	"Hardware event",
288 	"Software event",
289 	"Tracepoint event",
290 	"Hardware cache event",
291 };
292 
293 /*
294  * Print the help text for the event symbols:
295  */
296 void print_events(void)
297 {
298 	struct event_symbol *syms = event_symbols;
299 	unsigned int i, type, prev_type = -1;
300 	char name[40];
301 
302 	fprintf(stderr, "\n");
303 	fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
304 
305 	for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
306 		type = syms->type + 1;
307 		if (type > ARRAY_SIZE(event_type_descriptors))
308 			type = 0;
309 
310 		if (type != prev_type)
311 			fprintf(stderr, "\n");
312 
313 		if (strlen(syms->alias))
314 			sprintf(name, "%s OR %s", syms->symbol, syms->alias);
315 		else
316 			strcpy(name, syms->symbol);
317 		fprintf(stderr, "  %-40s [%s]\n", name,
318 			event_type_descriptors[type]);
319 
320 		prev_type = type;
321 	}
322 
323 	fprintf(stderr, "\n");
324 	fprintf(stderr, "  %-40s [raw hardware event descriptor]\n",
325 		"rNNN");
326 	fprintf(stderr, "\n");
327 
328 	exit(129);
329 }
330