diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-11-23 09:42:35 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-23 12:18:31 -0500 |
commit | 1b290d670ffa883b7e062177463a8efd00eaa2c1 (patch) | |
tree | d6449227ae19be6fb9046ac5d12cc3ae9d252972 /tools | |
parent | f5ffe02e5046003ae7e2ce70d3d1c2a73331268b (diff) |
perf tools: Add support for breakpoint events in perf tools
Add the breakpoint events support with this new sysnopsis:
mem:addr[:access]
Where addr is a raw addr value in the kernel and access can be
either [r][w][x]
Example to profile tasklist_lock:
$ grep tasklist_lock /proc/kallsyms
ffffffff8189c000 D tasklist_lock
$ perf record -e mem:0xffffffff8189c000:rw -a -f -c 1
$ perf report
# Samples: 62
#
# Overhead Command Shared Object Symbol
# ........ ............... ............. ......
#
29.03% swapper [kernel] [k] _raw_read_trylock
29.03% swapper [kernel] [k] _raw_read_unlock
19.35% init [kernel] [k] _raw_read_trylock
19.35% init [kernel] [k] _raw_read_unlock
1.61% events/0 [kernel] [k] _raw_read_trylock
1.61% events/0 [kernel] [k] _raw_read_unlock
Coming soon:
- Support for symbols in the event definition.
- Default period to 1 for breakpoint events because these are
not high frequency events. The same thing is needed for trace
events.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Prasad <prasad@linux.vnet.ibm.com>
LKML-Reference: <1258987355-8751-4-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Prasad <prasad@linux.vnet.ibm.com>
Diffstat (limited to 'tools')
-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); |