aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/parse-events.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r--tools/perf/util/parse-events.c232
1 files changed, 160 insertions, 72 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4d042f104cdc..e6b83a3311a5 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -184,16 +184,20 @@ char *event_name(int counter)
184 return "unknown"; 184 return "unknown";
185} 185}
186 186
187static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) 187static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
188{ 188{
189 int i, j; 189 int i, j;
190 int n, longest = -1;
190 191
191 for (i = 0; i < size; i++) { 192 for (i = 0; i < size; i++) {
192 for (j = 0; j < MAX_ALIASES; j++) { 193 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
193 if (!names[i][j]) 194 n = strlen(names[i][j]);
194 break; 195 if (n > longest && !strncasecmp(*str, names[i][j], n))
195 if (strcasestr(str, names[i][j])) 196 longest = n;
196 return i; 197 }
198 if (longest > 0) {
199 *str += longest;
200 return i;
197 } 201 }
198 } 202 }
199 203
@@ -201,30 +205,53 @@ static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
201} 205}
202 206
203static int 207static int
204parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) 208parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
205{ 209{
206 int cache_type = -1, cache_op = 0, cache_result = 0; 210 const char *s = *str;
211 int cache_type = -1, cache_op = -1, cache_result = -1;
207 212
208 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); 213 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
209 /* 214 /*
210 * No fallback - if we cannot get a clear cache type 215 * No fallback - if we cannot get a clear cache type
211 * then bail out: 216 * then bail out:
212 */ 217 */
213 if (cache_type == -1) 218 if (cache_type == -1)
214 return -EINVAL; 219 return 0;
220
221 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
222 ++s;
223
224 if (cache_op == -1) {
225 cache_op = parse_aliases(&s, hw_cache_op,
226 PERF_COUNT_HW_CACHE_OP_MAX);
227 if (cache_op >= 0) {
228 if (!is_cache_op_valid(cache_type, cache_op))
229 return 0;
230 continue;
231 }
232 }
233
234 if (cache_result == -1) {
235 cache_result = parse_aliases(&s, hw_cache_result,
236 PERF_COUNT_HW_CACHE_RESULT_MAX);
237 if (cache_result >= 0)
238 continue;
239 }
240
241 /*
242 * Can't parse this as a cache op or result, so back up
243 * to the '-'.
244 */
245 --s;
246 break;
247 }
215 248
216 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
217 /* 249 /*
218 * Fall back to reads: 250 * Fall back to reads:
219 */ 251 */
220 if (cache_op == -1) 252 if (cache_op == -1)
221 cache_op = PERF_COUNT_HW_CACHE_OP_READ; 253 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
222 254
223 if (!is_cache_op_valid(cache_type, cache_op))
224 return -EINVAL;
225
226 cache_result = parse_aliases(str, hw_cache_result,
227 PERF_COUNT_HW_CACHE_RESULT_MAX);
228 /* 255 /*
229 * Fall back to accesses: 256 * Fall back to accesses:
230 */ 257 */
@@ -234,93 +261,154 @@ parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
234 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 261 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
235 attr->type = PERF_TYPE_HW_CACHE; 262 attr->type = PERF_TYPE_HW_CACHE;
236 263
237 return 0; 264 *str = s;
265 return 1;
238} 266}
239 267
240static int check_events(const char *str, unsigned int i) 268static int check_events(const char *str, unsigned int i)
241{ 269{
242 if (!strncmp(str, event_symbols[i].symbol, 270 int n;
243 strlen(event_symbols[i].symbol)))
244 return 1;
245 271
246 if (strlen(event_symbols[i].alias)) 272 n = strlen(event_symbols[i].symbol);
247 if (!strncmp(str, event_symbols[i].alias, 273 if (!strncmp(str, event_symbols[i].symbol, n))
248 strlen(event_symbols[i].alias))) 274 return n;
249 return 1; 275
276 n = strlen(event_symbols[i].alias);
277 if (n)
278 if (!strncmp(str, event_symbols[i].alias, n))
279 return n;
250 return 0; 280 return 0;
251} 281}
252 282
253/* 283static int
254 * Each event can have multiple symbolic names. 284parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
255 * Symbolic names are (almost) exactly matched.
256 */
257static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
258{ 285{
259 u64 config, id; 286 const char *str = *strp;
260 int type;
261 unsigned int i; 287 unsigned int i;
262 const char *sep, *pstr; 288 int n;
263 289
264 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { 290 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
265 attr->type = PERF_TYPE_RAW; 291 n = check_events(str, i);
266 attr->config = config; 292 if (n > 0) {
293 attr->type = event_symbols[i].type;
294 attr->config = event_symbols[i].config;
295 *strp = str + n;
296 return 1;
297 }
298 }
299 return 0;
300}
301
302static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
303{
304 const char *str = *strp;
305 u64 config;
306 int n;
267 307
308 if (*str != 'r')
268 return 0; 309 return 0;
310 n = hex2u64(str + 1, &config);
311 if (n > 0) {
312 *strp = str + n + 1;
313 attr->type = PERF_TYPE_RAW;
314 attr->config = config;
315 return 1;
269 } 316 }
317 return 0;
318}
270 319
271 pstr = str; 320static int
272 sep = strchr(pstr, ':'); 321parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
273 if (sep) { 322{
274 type = atoi(pstr); 323 const char *str = *strp;
275 pstr = sep + 1; 324 char *endp;
276 id = atoi(pstr); 325 unsigned long type;
277 sep = strchr(pstr, ':'); 326 u64 config;
278 if (sep) { 327
279 pstr = sep + 1; 328 type = strtoul(str, &endp, 0);
280 if (strchr(pstr, 'k')) 329 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
281 attr->exclude_user = 1; 330 str = endp + 1;
282 if (strchr(pstr, 'u')) 331 config = strtoul(str, &endp, 0);
283 attr->exclude_kernel = 1; 332 if (endp > str) {
333 attr->type = type;
334 attr->config = config;
335 *strp = endp;
336 return 1;
284 } 337 }
285 attr->type = type; 338 }
286 attr->config = id; 339 return 0;
340}
341
342static int
343parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
344{
345 const char *str = *strp;
346 int eu = 1, ek = 1, eh = 1;
287 347
348 if (*str++ != ':')
288 return 0; 349 return 0;
350 while (*str) {
351 if (*str == 'u')
352 eu = 0;
353 else if (*str == 'k')
354 ek = 0;
355 else if (*str == 'h')
356 eh = 0;
357 else
358 break;
359 ++str;
289 } 360 }
361 if (str >= *strp + 2) {
362 *strp = str;
363 attr->exclude_user = eu;
364 attr->exclude_kernel = ek;
365 attr->exclude_hv = eh;
366 return 1;
367 }
368 return 0;
369}
290 370
291 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 371/*
292 if (check_events(str, i)) { 372 * Each event can have multiple symbolic names.
293 attr->type = event_symbols[i].type; 373 * Symbolic names are (almost) exactly matched.
294 attr->config = event_symbols[i].config; 374 */
375static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
376{
377 if (!(parse_raw_event(str, attr) ||
378 parse_numeric_event(str, attr) ||
379 parse_symbolic_event(str, attr) ||
380 parse_generic_hw_event(str, attr)))
381 return 0;
295 382
296 return 0; 383 parse_event_modifier(str, attr);
297 }
298 }
299 384
300 return parse_generic_hw_symbols(str, attr); 385 return 1;
301} 386}
302 387
303int parse_events(const struct option *opt, const char *str, int unset) 388int parse_events(const struct option *opt, const char *str, int unset)
304{ 389{
305 struct perf_counter_attr attr; 390 struct perf_counter_attr attr;
306 int ret;
307 391
308 memset(&attr, 0, sizeof(attr)); 392 for (;;) {
309again: 393 if (nr_counters == MAX_COUNTERS)
310 if (nr_counters == MAX_COUNTERS) 394 return -1;
311 return -1; 395
396 memset(&attr, 0, sizeof(attr));
397 if (!parse_event_symbols(&str, &attr))
398 return -1;
312 399
313 ret = parse_event_symbols(str, &attr); 400 if (!(*str == 0 || *str == ',' || isspace(*str)))
314 if (ret < 0) 401 return -1;
315 return ret;
316 402
317 attrs[nr_counters] = attr; 403 attrs[nr_counters] = attr;
318 nr_counters++; 404 nr_counters++;
319 405
320 str = strstr(str, ","); 406 if (*str == 0)
321 if (str) { 407 break;
322 str++; 408 if (*str == ',')
323 goto again; 409 ++str;
410 while (isspace(*str))
411 ++str;
324 } 412 }
325 413
326 return 0; 414 return 0;