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