[PATCH V2 3/4] perf tools: Add hardware breakpoint address mask event parser

From: Jacob Shin
Date: Tue Apr 23 2013 - 03:57:24 EST


From: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>

Allow perf tool to pass in breakpoint address mask to match an address
range, i.e.:

$ perf stat -e mem:0x1000/0xf:w a.out

Will count writes to [0x1000 ~ 0x1010)

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
Signed-off-by: Jacob Shin <jacob.shin@xxxxxxx>
---
tools/perf/Documentation/perf-record.txt | 14 ++++++++++----
tools/perf/util/parse-events.c | 5 +++--
tools/perf/util/parse-events.h | 2 +-
tools/perf/util/parse-events.l | 1 +
tools/perf/util/parse-events.y | 24 ++++++++++++++++++++++--
5 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index d4da111..c516320 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -33,13 +33,19 @@ OPTIONS
- a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
hexadecimal event descriptor.

- - a hardware breakpoint event in the form of '\mem:addr[:access]'
- where addr is the address in memory you want to break in.
- Access is the memory access type (read, write, execute) it can
- be passed as follows: '\mem:addr[:[r][w][x]]'.
+ - a hardware breakpoint event in the form of
+ '\mem:addr[/addr_mask][:access]' where addr is the address in
+ memory you want to break in. Access is the memory access type (read,
+ write, execute) it can be passed as follows: '\mem:addr[:[r][w][x]]'.
+ addr_mask is the "don't care" bit mask to further qualify the given
+ addr, to break in on accesses to an address range.
+
If you want to profile read-write accesses in 0x1000, just set
'mem:0x1000:rw'.

+ If you want to profile write accesses in [0x1000 ~ 0x1010), just set
+ 'mem:0x1000/0xf:w'. (Only supported on some hardware)
+
--filter=<filter>::
Event filter.

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6c8bb0f..0ca518f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -508,12 +508,13 @@ do { \
}

int parse_events_add_breakpoint(struct list_head **list, int *idx,
- void *ptr, char *type)
+ void *ptr, char *type, void *msk)
{
struct perf_event_attr attr;

memset(&attr, 0, sizeof(attr));
attr.bp_addr = (unsigned long) ptr;
+ attr.bp_addr_mask = (unsigned long) msk;

if (parse_breakpoint_type(type, &attr))
return -EINVAL;
@@ -1147,7 +1148,7 @@ void print_events(const char *event_glob, bool name_only)
printf("\n");

printf(" %-50s [%s]\n",
- "mem:<addr>[:access]",
+ "mem:<addr>[/addr_mask][:access]",
event_type_descriptors[PERF_TYPE_BREAKPOINT]);
printf("\n");
}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8a48593..83920cc 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -92,7 +92,7 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
int parse_events_add_cache(struct list_head **list, int *idx,
char *type, char *op_result1, char *op_result2);
int parse_events_add_breakpoint(struct list_head **list, int *idx,
- void *ptr, char *type);
+ void *ptr, char *type, void *msk);
int parse_events_add_pmu(struct list_head **list, int *idx,
char *pmu , struct list_head *head_config);
void parse_events__set_leader(char *name, struct list_head *list);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index e9d1134..15b3efc 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -191,6 +191,7 @@ r{num_raw_hex} { return raw(yyscanner); }
<mem>{
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
: { return ':'; }
+"/" { return '/'; }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }
/*
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index afc44c1..8b17979 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -263,13 +263,33 @@ PE_NAME_CACHE_TYPE
}

event_legacy_mem:
+PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
+{
+ struct parse_events_evlist *data = _data;
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+ (void *) $2, $6, (void *) $4));
+ $$ = list;
+}
+|
+PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
+{
+ struct parse_events_evlist *data = _data;
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+ (void *) $2, NULL, (void *) $4));
+ $$ = list;
+}
+|
PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;

ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
- (void *) $2, $4));
+ (void *) $2, $4, NULL));
$$ = list;
}
|
@@ -279,7 +299,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
struct list_head *list = NULL;

ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
- (void *) $2, NULL));
+ (void *) $2, NULL, NULL));
$$ = list;
}

--
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/