diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 232 |
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 | ||
187 | static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) | 187 | static 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 | ||
203 | static int | 207 | static int |
204 | parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) | 208 | parse_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 | ||
240 | static int check_events(const char *str, unsigned int i) | 268 | static 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 | /* | 283 | static int |
254 | * Each event can have multiple symbolic names. | 284 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) |
255 | * Symbolic names are (almost) exactly matched. | ||
256 | */ | ||
257 | static 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 | |||
302 | static 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; | 320 | static int |
272 | sep = strchr(pstr, ':'); | 321 | parse_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 | |||
342 | static int | ||
343 | parse_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 | */ |
375 | static 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 | ||
303 | int parse_events(const struct option *opt, const char *str, int unset) | 388 | int 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 (;;) { |
309 | again: | 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; |