diff options
| author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-09-11 17:19:45 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-09-13 04:22:40 -0400 |
| commit | bcd3279f465cdcc1e0454b5f605f021c4ff4dbb5 (patch) | |
| tree | 9a3d5fa6542742144aaecbfc796ec40b2287e04c /tools | |
| parent | ad236fd23b6d6372dcacd549983cce051d2ccff6 (diff) | |
perf tools: Allow the specification of all tracepoints at once
Currently, when one wants to activate every tracepoint
counters of a subsystem from perf record, the current sequence
is needed:
perf record -e subsys:ev1 -e subsys:ev2 -e subsys:ev3
This may annoy the most patient of us.
Now we can just do:
perf record -e subsys:*
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/util/parse-events.c | 204 |
1 files changed, 154 insertions, 50 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a587d41ae3c9..d06c66cd358b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -18,6 +18,12 @@ struct event_symbol { | |||
| 18 | const char *alias; | 18 | const char *alias; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | enum event_result { | ||
| 22 | EVT_FAILED, | ||
| 23 | EVT_HANDLED, | ||
| 24 | EVT_HANDLED_ALL | ||
| 25 | }; | ||
| 26 | |||
| 21 | char debugfs_path[MAXPATHLEN]; | 27 | char debugfs_path[MAXPATHLEN]; |
| 22 | 28 | ||
| 23 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 29 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x |
| @@ -344,7 +350,7 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int | |||
| 344 | return -1; | 350 | return -1; |
| 345 | } | 351 | } |
| 346 | 352 | ||
| 347 | static int | 353 | static enum event_result |
| 348 | parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | 354 | parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) |
| 349 | { | 355 | { |
| 350 | const char *s = *str; | 356 | const char *s = *str; |
| @@ -356,7 +362,7 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | |||
| 356 | * then bail out: | 362 | * then bail out: |
| 357 | */ | 363 | */ |
| 358 | if (cache_type == -1) | 364 | if (cache_type == -1) |
| 359 | return 0; | 365 | return EVT_FAILED; |
| 360 | 366 | ||
| 361 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { | 367 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { |
| 362 | ++s; | 368 | ++s; |
| @@ -402,27 +408,112 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) | |||
| 402 | attr->type = PERF_TYPE_HW_CACHE; | 408 | attr->type = PERF_TYPE_HW_CACHE; |
| 403 | 409 | ||
| 404 | *str = s; | 410 | *str = s; |
| 405 | return 1; | 411 | return EVT_HANDLED; |
| 412 | } | ||
| 413 | |||
| 414 | static enum event_result | ||
| 415 | parse_single_tracepoint_event(char *sys_name, | ||
| 416 | const char *evt_name, | ||
| 417 | unsigned int evt_length, | ||
| 418 | char *flags, | ||
| 419 | struct perf_counter_attr *attr, | ||
| 420 | const char **strp) | ||
| 421 | { | ||
| 422 | char evt_path[MAXPATHLEN]; | ||
| 423 | char id_buf[4]; | ||
| 424 | u64 id; | ||
| 425 | int fd; | ||
| 426 | |||
| 427 | if (flags) { | ||
| 428 | if (!strncmp(flags, "record", strlen(flags))) | ||
| 429 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
| 430 | } | ||
| 431 | |||
| 432 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | ||
| 433 | sys_name, evt_name); | ||
| 434 | |||
| 435 | fd = open(evt_path, O_RDONLY); | ||
| 436 | if (fd < 0) | ||
| 437 | return EVT_FAILED; | ||
| 438 | |||
| 439 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
| 440 | close(fd); | ||
| 441 | return EVT_FAILED; | ||
| 442 | } | ||
| 443 | |||
| 444 | close(fd); | ||
| 445 | id = atoll(id_buf); | ||
| 446 | attr->config = id; | ||
| 447 | attr->type = PERF_TYPE_TRACEPOINT; | ||
| 448 | *strp = evt_name + evt_length; | ||
| 449 | |||
| 450 | return EVT_HANDLED; | ||
| 406 | } | 451 | } |
| 407 | 452 | ||
| 408 | static int parse_tracepoint_event(const char **strp, | 453 | /* sys + ':' + event + ':' + flags*/ |
| 454 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) | ||
| 455 | static enum event_result | ||
| 456 | parse_subsystem_tracepoint_event(char *sys_name, char *flags) | ||
| 457 | { | ||
| 458 | char evt_path[MAXPATHLEN]; | ||
| 459 | struct dirent *evt_ent; | ||
| 460 | DIR *evt_dir; | ||
| 461 | |||
| 462 | snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); | ||
| 463 | evt_dir = opendir(evt_path); | ||
| 464 | |||
| 465 | if (!evt_dir) { | ||
| 466 | perror("Can't open event dir"); | ||
| 467 | return EVT_FAILED; | ||
| 468 | } | ||
| 469 | |||
| 470 | while ((evt_ent = readdir(evt_dir))) { | ||
| 471 | char event_opt[MAX_EVOPT_LEN + 1]; | ||
| 472 | int len; | ||
| 473 | unsigned int rem = MAX_EVOPT_LEN; | ||
| 474 | |||
| 475 | if (!strcmp(evt_ent->d_name, ".") | ||
| 476 | || !strcmp(evt_ent->d_name, "..") | ||
| 477 | || !strcmp(evt_ent->d_name, "enable") | ||
| 478 | || !strcmp(evt_ent->d_name, "filter")) | ||
| 479 | continue; | ||
| 480 | |||
| 481 | len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, | ||
| 482 | evt_ent->d_name); | ||
| 483 | if (len < 0) | ||
| 484 | return EVT_FAILED; | ||
| 485 | |||
| 486 | rem -= len; | ||
| 487 | if (flags) { | ||
| 488 | if (rem < strlen(flags) + 1) | ||
| 489 | return EVT_FAILED; | ||
| 490 | |||
| 491 | strcat(event_opt, ":"); | ||
| 492 | strcat(event_opt, flags); | ||
| 493 | } | ||
| 494 | |||
| 495 | if (parse_events(NULL, event_opt, 0)) | ||
| 496 | return EVT_FAILED; | ||
| 497 | } | ||
| 498 | |||
| 499 | return EVT_HANDLED_ALL; | ||
| 500 | } | ||
| 501 | |||
| 502 | |||
| 503 | static enum event_result parse_tracepoint_event(const char **strp, | ||
| 409 | struct perf_counter_attr *attr) | 504 | struct perf_counter_attr *attr) |
| 410 | { | 505 | { |
| 411 | const char *evt_name; | 506 | const char *evt_name; |
| 412 | char *flags; | 507 | char *flags; |
| 413 | char sys_name[MAX_EVENT_LENGTH]; | 508 | char sys_name[MAX_EVENT_LENGTH]; |
| 414 | char id_buf[4]; | ||
| 415 | int fd; | ||
| 416 | unsigned int sys_length, evt_length; | 509 | unsigned int sys_length, evt_length; |
| 417 | u64 id; | ||
| 418 | char evt_path[MAXPATHLEN]; | ||
| 419 | 510 | ||
| 420 | if (valid_debugfs_mount(debugfs_path)) | 511 | if (valid_debugfs_mount(debugfs_path)) |
| 421 | return 0; | 512 | return 0; |
| 422 | 513 | ||
| 423 | evt_name = strchr(*strp, ':'); | 514 | evt_name = strchr(*strp, ':'); |
| 424 | if (!evt_name) | 515 | if (!evt_name) |
| 425 | return 0; | 516 | return EVT_FAILED; |
| 426 | 517 | ||
| 427 | sys_length = evt_name - *strp; | 518 | sys_length = evt_name - *strp; |
| 428 | if (sys_length >= MAX_EVENT_LENGTH) | 519 | if (sys_length >= MAX_EVENT_LENGTH) |
| @@ -436,30 +527,19 @@ static int parse_tracepoint_event(const char **strp, | |||
| 436 | if (flags) { | 527 | if (flags) { |
| 437 | *flags = '\0'; | 528 | *flags = '\0'; |
| 438 | flags++; | 529 | flags++; |
| 439 | if (!strncmp(flags, "record", strlen(flags))) | ||
| 440 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
| 441 | } | 530 | } |
| 442 | 531 | ||
| 443 | evt_length = strlen(evt_name); | 532 | evt_length = strlen(evt_name); |
| 444 | if (evt_length >= MAX_EVENT_LENGTH) | 533 | if (evt_length >= MAX_EVENT_LENGTH) |
| 445 | return 0; | 534 | return EVT_FAILED; |
| 446 | 535 | ||
| 447 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | 536 | if (!strcmp(evt_name, "*")) { |
| 448 | sys_name, evt_name); | 537 | *strp = evt_name + evt_length; |
| 449 | fd = open(evt_path, O_RDONLY); | 538 | return parse_subsystem_tracepoint_event(sys_name, flags); |
| 450 | if (fd < 0) | 539 | } else |
| 451 | return 0; | 540 | return parse_single_tracepoint_event(sys_name, evt_name, |
| 452 | 541 | evt_length, flags, | |
| 453 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | 542 | attr, strp); |
| 454 | close(fd); | ||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | close(fd); | ||
| 458 | id = atoll(id_buf); | ||
| 459 | attr->config = id; | ||
| 460 | attr->type = PERF_TYPE_TRACEPOINT; | ||
| 461 | *strp = evt_name + evt_length; | ||
| 462 | return 1; | ||
| 463 | } | 543 | } |
| 464 | 544 | ||
| 465 | static int check_events(const char *str, unsigned int i) | 545 | static int check_events(const char *str, unsigned int i) |
| @@ -477,7 +557,7 @@ static int check_events(const char *str, unsigned int i) | |||
| 477 | return 0; | 557 | return 0; |
| 478 | } | 558 | } |
| 479 | 559 | ||
| 480 | static int | 560 | static enum event_result |
| 481 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) | 561 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) |
| 482 | { | 562 | { |
| 483 | const char *str = *strp; | 563 | const char *str = *strp; |
| @@ -490,31 +570,32 @@ parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) | |||
| 490 | attr->type = event_symbols[i].type; | 570 | attr->type = event_symbols[i].type; |
| 491 | attr->config = event_symbols[i].config; | 571 | attr->config = event_symbols[i].config; |
| 492 | *strp = str + n; | 572 | *strp = str + n; |
| 493 | return 1; | 573 | return EVT_HANDLED; |
| 494 | } | 574 | } |
| 495 | } | 575 | } |
| 496 | return 0; | 576 | return EVT_FAILED; |
| 497 | } | 577 | } |
| 498 | 578 | ||
| 499 | static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) | 579 | static enum event_result |
| 580 | parse_raw_event(const char **strp, struct perf_counter_attr *attr) | ||
| 500 | { | 581 | { |
| 501 | const char *str = *strp; | 582 | const char *str = *strp; |
| 502 | u64 config; | 583 | u64 config; |
| 503 | int n; | 584 | int n; |
| 504 | 585 | ||
| 505 | if (*str != 'r') | 586 | if (*str != 'r') |
| 506 | return 0; | 587 | return EVT_FAILED; |
| 507 | n = hex2u64(str + 1, &config); | 588 | n = hex2u64(str + 1, &config); |
| 508 | if (n > 0) { | 589 | if (n > 0) { |
| 509 | *strp = str + n + 1; | 590 | *strp = str + n + 1; |
| 510 | attr->type = PERF_TYPE_RAW; | 591 | attr->type = PERF_TYPE_RAW; |
| 511 | attr->config = config; | 592 | attr->config = config; |
| 512 | return 1; | 593 | return EVT_HANDLED; |
| 513 | } | 594 | } |
| 514 | return 0; | 595 | return EVT_FAILED; |
| 515 | } | 596 | } |
| 516 | 597 | ||
| 517 | static int | 598 | static enum event_result |
| 518 | parse_numeric_event(const char **strp, struct perf_counter_attr *attr) | 599 | parse_numeric_event(const char **strp, struct perf_counter_attr *attr) |
| 519 | { | 600 | { |
| 520 | const char *str = *strp; | 601 | const char *str = *strp; |
| @@ -530,13 +611,13 @@ parse_numeric_event(const char **strp, struct perf_counter_attr *attr) | |||
| 530 | attr->type = type; | 611 | attr->type = type; |
| 531 | attr->config = config; | 612 | attr->config = config; |
| 532 | *strp = endp; | 613 | *strp = endp; |
| 533 | return 1; | 614 | return EVT_HANDLED; |
| 534 | } | 615 | } |
| 535 | } | 616 | } |
| 536 | return 0; | 617 | return EVT_FAILED; |
| 537 | } | 618 | } |
| 538 | 619 | ||
| 539 | static int | 620 | static enum event_result |
| 540 | parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | 621 | parse_event_modifier(const char **strp, struct perf_counter_attr *attr) |
| 541 | { | 622 | { |
| 542 | const char *str = *strp; | 623 | const char *str = *strp; |
| @@ -569,37 +650,60 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | |||
| 569 | * Each event can have multiple symbolic names. | 650 | * Each event can have multiple symbolic names. |
| 570 | * Symbolic names are (almost) exactly matched. | 651 | * Symbolic names are (almost) exactly matched. |
| 571 | */ | 652 | */ |
| 572 | static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) | 653 | static enum event_result |
| 654 | parse_event_symbols(const char **str, struct perf_counter_attr *attr) | ||
| 573 | { | 655 | { |
| 574 | if (!(parse_tracepoint_event(str, attr) || | 656 | enum event_result ret; |
| 575 | parse_raw_event(str, attr) || | 657 | |
| 576 | parse_numeric_event(str, attr) || | 658 | ret = parse_tracepoint_event(str, attr); |
| 577 | parse_symbolic_event(str, attr) || | 659 | if (ret != EVT_FAILED) |
| 578 | parse_generic_hw_event(str, attr))) | 660 | goto modifier; |
| 579 | return 0; | 661 | |
| 662 | ret = parse_raw_event(str, attr); | ||
| 663 | if (ret != EVT_FAILED) | ||
| 664 | goto modifier; | ||
| 580 | 665 | ||
| 666 | ret = parse_numeric_event(str, attr); | ||
| 667 | if (ret != EVT_FAILED) | ||
| 668 | goto modifier; | ||
| 669 | |||
| 670 | ret = parse_symbolic_event(str, attr); | ||
| 671 | if (ret != EVT_FAILED) | ||
| 672 | goto modifier; | ||
| 673 | |||
| 674 | ret = parse_generic_hw_event(str, attr); | ||
| 675 | if (ret != EVT_FAILED) | ||
| 676 | goto modifier; | ||
| 677 | |||
| 678 | return EVT_FAILED; | ||
| 679 | |||
| 680 | modifier: | ||
| 581 | parse_event_modifier(str, attr); | 681 | parse_event_modifier(str, attr); |
| 582 | 682 | ||
| 583 | return 1; | 683 | return ret; |
| 584 | } | 684 | } |
| 585 | 685 | ||
| 586 | int parse_events(const struct option *opt __used, const char *str, int unset __used) | 686 | int parse_events(const struct option *opt __used, const char *str, int unset __used) |
| 587 | { | 687 | { |
| 588 | struct perf_counter_attr attr; | 688 | struct perf_counter_attr attr; |
| 689 | enum event_result ret; | ||
| 589 | 690 | ||
| 590 | for (;;) { | 691 | for (;;) { |
| 591 | if (nr_counters == MAX_COUNTERS) | 692 | if (nr_counters == MAX_COUNTERS) |
| 592 | return -1; | 693 | return -1; |
| 593 | 694 | ||
| 594 | memset(&attr, 0, sizeof(attr)); | 695 | memset(&attr, 0, sizeof(attr)); |
| 595 | if (!parse_event_symbols(&str, &attr)) | 696 | ret = parse_event_symbols(&str, &attr); |
| 697 | if (ret == EVT_FAILED) | ||
| 596 | return -1; | 698 | return -1; |
| 597 | 699 | ||
| 598 | if (!(*str == 0 || *str == ',' || isspace(*str))) | 700 | if (!(*str == 0 || *str == ',' || isspace(*str))) |
| 599 | return -1; | 701 | return -1; |
| 600 | 702 | ||
| 601 | attrs[nr_counters] = attr; | 703 | if (ret != EVT_HANDLED_ALL) { |
| 602 | nr_counters++; | 704 | attrs[nr_counters] = attr; |
| 705 | nr_counters++; | ||
| 706 | } | ||
| 603 | 707 | ||
| 604 | if (*str == 0) | 708 | if (*str == 0) |
| 605 | break; | 709 | break; |
