diff options
| -rw-r--r-- | tools/perf/Documentation/perf-record.txt | 16 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 84 |
2 files changed, 95 insertions, 5 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 0ff23de9e453..fc46c0b40f6e 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
| @@ -26,11 +26,19 @@ OPTIONS | |||
| 26 | 26 | ||
| 27 | -e:: | 27 | -e:: |
| 28 | --event=:: | 28 | --event=:: |
| 29 | Select the PMU event. Selection can be a symbolic event name | 29 | Select the PMU event. Selection can be: |
| 30 | (use 'perf list' to list all events) or a raw PMU | ||
| 31 | event (eventsel+umask) in the form of rNNN where NNN is a | ||
| 32 | hexadecimal event descriptor. | ||
| 33 | 30 | ||
| 31 | - a symbolic event name (use 'perf list' to list all events) | ||
| 32 | |||
| 33 | - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a | ||
| 34 | hexadecimal event descriptor. | ||
| 35 | |||
| 36 | - a hardware breakpoint event in the form of '\mem:addr[:access]' | ||
| 37 | where addr is the address in memory you want to break in. | ||
| 38 | Access is the memory access type (read, write, execute) it can | ||
| 39 | be passed as follows: '\mem:addr[:[r][w][x]]'. | ||
| 40 | If you want to profile read-write accesses in 0x1000, just set | ||
| 41 | 'mem:0x1000:rw'. | ||
| 34 | -a:: | 42 | -a:: |
| 35 | System-wide collection. | 43 | System-wide collection. |
| 36 | 44 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 0faf4f2bb5ca..070027469270 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | 1 | #include "../../../include/linux/hw_breakpoint.h" | |
| 2 | #include "util.h" | 2 | #include "util.h" |
| 3 | #include "../perf.h" | 3 | #include "../perf.h" |
| 4 | #include "parse-options.h" | 4 | #include "parse-options.h" |
| @@ -540,6 +540,81 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
| 540 | attr, strp); | 540 | attr, strp); |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | static enum event_result | ||
| 544 | parse_breakpoint_type(const char *type, const char **strp, | ||
| 545 | struct perf_event_attr *attr) | ||
| 546 | { | ||
| 547 | int i; | ||
| 548 | |||
| 549 | for (i = 0; i < 3; i++) { | ||
| 550 | if (!type[i]) | ||
| 551 | break; | ||
| 552 | |||
| 553 | switch (type[i]) { | ||
| 554 | case 'r': | ||
| 555 | attr->bp_type |= HW_BREAKPOINT_R; | ||
| 556 | break; | ||
| 557 | case 'w': | ||
| 558 | attr->bp_type |= HW_BREAKPOINT_W; | ||
| 559 | break; | ||
| 560 | case 'x': | ||
| 561 | attr->bp_type |= HW_BREAKPOINT_X; | ||
| 562 | break; | ||
| 563 | default: | ||
| 564 | return EVT_FAILED; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | if (!attr->bp_type) /* Default */ | ||
| 568 | attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; | ||
| 569 | |||
| 570 | *strp = type + i; | ||
| 571 | |||
| 572 | return EVT_HANDLED; | ||
| 573 | } | ||
| 574 | |||
| 575 | static enum event_result | ||
| 576 | parse_breakpoint_event(const char **strp, struct perf_event_attr *attr) | ||
| 577 | { | ||
| 578 | const char *target; | ||
| 579 | const char *type; | ||
| 580 | char *endaddr; | ||
| 581 | u64 addr; | ||
| 582 | enum event_result err; | ||
| 583 | |||
| 584 | target = strchr(*strp, ':'); | ||
| 585 | if (!target) | ||
| 586 | return EVT_FAILED; | ||
| 587 | |||
| 588 | if (strncmp(*strp, "mem", target - *strp) != 0) | ||
| 589 | return EVT_FAILED; | ||
| 590 | |||
| 591 | target++; | ||
| 592 | |||
| 593 | addr = strtoull(target, &endaddr, 0); | ||
| 594 | if (target == endaddr) | ||
| 595 | return EVT_FAILED; | ||
| 596 | |||
| 597 | attr->bp_addr = addr; | ||
| 598 | *strp = endaddr; | ||
| 599 | |||
| 600 | type = strchr(target, ':'); | ||
| 601 | |||
| 602 | /* If no type is defined, just rw as default */ | ||
| 603 | if (!type) { | ||
| 604 | attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; | ||
| 605 | } else { | ||
| 606 | err = parse_breakpoint_type(++type, strp, attr); | ||
| 607 | if (err == EVT_FAILED) | ||
| 608 | return EVT_FAILED; | ||
| 609 | } | ||
| 610 | |||
| 611 | /* We should find a nice way to override the access type */ | ||
| 612 | attr->bp_len = HW_BREAKPOINT_LEN_4; | ||
| 613 | attr->type = PERF_TYPE_BREAKPOINT; | ||
| 614 | |||
| 615 | return EVT_HANDLED; | ||
| 616 | } | ||
| 617 | |||
| 543 | static int check_events(const char *str, unsigned int i) | 618 | static int check_events(const char *str, unsigned int i) |
| 544 | { | 619 | { |
| 545 | int n; | 620 | int n; |
| @@ -673,6 +748,10 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr) | |||
| 673 | if (ret != EVT_FAILED) | 748 | if (ret != EVT_FAILED) |
| 674 | goto modifier; | 749 | goto modifier; |
| 675 | 750 | ||
| 751 | ret = parse_breakpoint_event(str, attr); | ||
| 752 | if (ret != EVT_FAILED) | ||
| 753 | goto modifier; | ||
| 754 | |||
| 676 | fprintf(stderr, "invalid or unsupported event: '%s'\n", *str); | 755 | fprintf(stderr, "invalid or unsupported event: '%s'\n", *str); |
| 677 | fprintf(stderr, "Run 'perf list' for a list of valid events\n"); | 756 | fprintf(stderr, "Run 'perf list' for a list of valid events\n"); |
| 678 | return EVT_FAILED; | 757 | return EVT_FAILED; |
| @@ -859,6 +938,9 @@ void print_events(void) | |||
| 859 | "rNNN"); | 938 | "rNNN"); |
| 860 | printf("\n"); | 939 | printf("\n"); |
| 861 | 940 | ||
| 941 | printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); | ||
| 942 | printf("\n"); | ||
| 943 | |||
| 862 | print_tracepoint_events(); | 944 | print_tracepoint_events(); |
| 863 | 945 | ||
| 864 | exit(129); | 946 | exit(129); |
