All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] perf tool: event parsing enhancements/fixes
@ 2012-04-04 20:21 Jiri Olsa
  2012-04-04 20:21 ` [PATCH 1/8] perf, tool: Fix NULL deref in hists browsing code Jiri Olsa
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec; +Cc: linux-kernel

Hi,
adding some enhancements/fixies for perf event parsing.

- patch 1 is simple fix

- patches 2, 3, 4 and 5 are event config terms enhancements

- patches 6, 7 and 8 are maintanance patches either helping
  with developement (6, 7) or making the code more clear (8).

Attached patches:
 1/8 perf, tool: Fix NULL deref in hists browsing code
 2/8 perf, tool: Split term type into value type and term type
 3/8 perf, tool: Add list type for event term parsing
 4/8 perf, tool: Add hardcoded name term for pmu events
 5/8 perf, tool: Add pmu event parse support for branch_sample_type values
 6/8 perf, tool: Move parse event automated tests to separated object
 7/8 perf, tool: Add support for displaying event parser debug info
 8/8 perf, tool: Use allocated list for each parsed event

thanks,
jirka
---
 tools/perf/Makefile                 |   13 +-
 tools/perf/builtin-record.c         |   31 +--
 tools/perf/builtin-test.c           |  522 +-------------------------------
 tools/perf/util/parse-events-test.c |  588 +++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events.c      |  240 +++++++++++++--
 tools/perf/util/parse-events.h      |   59 +++-
 tools/perf/util/parse-events.l      |    2 +
 tools/perf/util/parse-events.y      |  147 ++++++++--
 tools/perf/util/pmu.c               |   85 ++++--
 tools/perf/util/pmu.h               |    2 +
 tools/perf/util/ui/browsers/hists.c |    3 +
 11 files changed, 1037 insertions(+), 655 deletions(-)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/8] perf, tool: Fix NULL deref in hists browsing code
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  2012-04-13 18:04   ` [tip:perf/core] perf hists browser: " tip-bot for Jiri Olsa
  2012-04-04 20:21 ` [PATCH 2/8] perf, tool: Split term type into value type and term type Jiri Olsa
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

If there's an event with no samples in data file, the perf report
command can segfault after entering the event details menu.

Following steps reproduce the issue:

 # ./perf record -e syscalls:sys_enter_kexec_load,syscalls:sys_enter_mmap ls
 # ./perf report
 # enter '0 syscalls:sys_enter_kexec_load' menu
 # pres ENTER twice

Above steps are valid assuming ls wont run kexec.. ;)

The check for sellection to be NULL is missing. The fix makes sure
it's being check. Above steps now endup with menu being displayed
allowing 'Exit' as the only option.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/ui/browsers/hists.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index d7a1c4a..2f83e5d 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -125,6 +125,9 @@ static int callchain__count_rows(struct rb_root *chain)
 
 static bool map_symbol__toggle_fold(struct map_symbol *self)
 {
+	if (!self)
+		return false;
+
 	if (!self->has_children)
 		return false;
 
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/8] perf, tool: Split term type into value type and term type
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
  2012-04-04 20:21 ` [PATCH 1/8] perf, tool: Fix NULL deref in hists browsing code Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  2012-04-04 20:21 ` [PATCH 3/8] perf, tool: Add list type for event term parsing Jiri Olsa
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

Introducing type_val and type_term for term instead of a single
type value. Currently the term type marked out the value type as
well.

With this change we can have future string term values being
specified by user and translated into proper number along the
processing. This is going to be the case for the branch_sample_type
comming in shortly.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/parse-events.c |   31 +++++++++++------
 tools/perf/util/parse-events.h |   19 ++++++-----
 tools/perf/util/parse-events.y |   26 ++++++++++----
 tools/perf/util/pmu.c          |   70 ++++++++++++++++++++++++----------------
 4 files changed, 90 insertions(+), 56 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5b3a0ef..37b8fc9 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -593,17 +593,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
 static int config_term(struct perf_event_attr *attr,
 		       struct parse_events__term *term)
 {
-	switch (term->type) {
+#define CHECK_TYPE_VAL(type)					\
+do {								\
+	if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val)	\
+		return -EINVAL;					\
+} while (0)
+
+	switch (term->type_term) {
 	case PARSE_EVENTS__TERM_TYPE_CONFIG:
+		CHECK_TYPE_VAL(NUM);
 		attr->config = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_CONFIG1:
+		CHECK_TYPE_VAL(NUM);
 		attr->config1 = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_CONFIG2:
+		CHECK_TYPE_VAL(NUM);
 		attr->config2 = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
+		CHECK_TYPE_VAL(NUM);
 		attr->sample_period = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
@@ -615,7 +625,10 @@ static int config_term(struct perf_event_attr *attr,
 	default:
 		return -EINVAL;
 	}
+
 	return 0;
+
+#undef CHECK_TYPE_VAL
 }
 
 static int config_attr(struct perf_event_attr *attr,
@@ -1015,11 +1028,11 @@ void print_events(const char *event_glob)
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term)
 {
-	return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
+	return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 }
 
-int parse_events__new_term(struct parse_events__term **_term, int type,
-			   char *config, char *str, long num)
+int parse_events__new_term(struct parse_events__term **_term, int type_val,
+			   int type_term, char *config, char *str, long num)
 {
 	struct parse_events__term *term;
 
@@ -1028,15 +1041,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
 		return -ENOMEM;
 
 	INIT_LIST_HEAD(&term->list);
-	term->type = type;
+	term->type_val  = type_val;
+	term->type_term = type_term;
 	term->config = config;
 
-	switch (type) {
-	case PARSE_EVENTS__TERM_TYPE_CONFIG:
-	case PARSE_EVENTS__TERM_TYPE_CONFIG1:
-	case PARSE_EVENTS__TERM_TYPE_CONFIG2:
-	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+	switch (type_val) {
 	case PARSE_EVENTS__TERM_TYPE_NUM:
 		term->val.num = num;
 		break;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ca069f8..7053aa3 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -34,16 +34,17 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
 #define EVENTS_HELP_MAX (128*1024)
 
 enum {
+	PARSE_EVENTS__TERM_TYPE_NUM,
+	PARSE_EVENTS__TERM_TYPE_STR,
+};
+
+enum {
+	PARSE_EVENTS__TERM_TYPE_USER,
 	PARSE_EVENTS__TERM_TYPE_CONFIG,
 	PARSE_EVENTS__TERM_TYPE_CONFIG1,
 	PARSE_EVENTS__TERM_TYPE_CONFIG2,
 	PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
-	PARSE_EVENTS__TERM_TYPE_NUM,
-	PARSE_EVENTS__TERM_TYPE_STR,
-
-	PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
-		PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 };
 
 struct parse_events__term {
@@ -52,14 +53,14 @@ struct parse_events__term {
 		char *str;
 		long  num;
 	} val;
-	int type;
-
+	int type_val;
+	int type_term;
 	struct list_head list;
 };
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term);
-int parse_events__new_term(struct parse_events__term **term, int type,
-			   char *config, char *str, long num);
+int parse_events__new_term(struct parse_events__term **_term, int type_val,
+			   int type_term, char *config, char *str, long num);
 void parse_events__free_terms(struct list_head *terms);
 int parse_events_modifier(struct list_head *list __used, char *str __used);
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da..b3b45e4 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -176,8 +176,10 @@ PE_NAME '=' PE_NAME
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
-		 $1, $3, 0));
+	ABORT_ON(parse_events__new_term(&term,
+					PARSE_EVENTS__TERM_TYPE_STR,
+					PARSE_EVENTS__TERM_TYPE_USER,
+					$1, $3, 0));
 	$$ = term;
 }
 |
@@ -185,8 +187,10 @@ PE_NAME '=' PE_VALUE
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
-		 $1, NULL, $3));
+	ABORT_ON(parse_events__new_term(&term,
+					PARSE_EVENTS__TERM_TYPE_NUM,
+					PARSE_EVENTS__TERM_TYPE_USER,
+					$1, NULL, $3));
 	$$ = term;
 }
 |
@@ -194,8 +198,10 @@ PE_NAME
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
-		 $1, NULL, 1));
+	ABORT_ON(parse_events__new_term(&term,
+					PARSE_EVENTS__TERM_TYPE_NUM,
+					PARSE_EVENTS__TERM_TYPE_USER,
+					$1, NULL, 1));
 	$$ = term;
 }
 |
@@ -203,7 +209,9 @@ PE_TERM '=' PE_VALUE
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
+	ABORT_ON(parse_events__new_term(&term,
+					PARSE_EVENTS__TERM_TYPE_NUM,
+					$1, NULL, NULL, $3));
 	$$ = term;
 }
 |
@@ -211,7 +219,9 @@ PE_TERM
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
+	ABORT_ON(parse_events__new_term(&term,
+					PARSE_EVENTS__TERM_TYPE_NUM,
+					$1, NULL, NULL, 1));
 	$$ = term;
 }
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index cb08a11..8ee219b 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -225,7 +225,7 @@ static int pmu_config_term(struct list_head *formats,
 	if (parse_events__is_hardcoded_term(term))
 		return 0;
 
-	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
 		return -EINVAL;
 
 	format = pmu_find_format(formats, term->config);
@@ -246,6 +246,11 @@ static int pmu_config_term(struct list_head *formats,
 		return -EINVAL;
 	}
 
+	/*
+	 * XXX If we ever decide to go with string values for
+	 * non-hardcoded terms, here's the place to translate
+	 * them into value.
+	 */
 	*vp |= pmu_format_value(format->bits, term->val.num);
 	return 0;
 }
@@ -324,49 +329,58 @@ static struct test_format {
 /* Simulated users input. */
 static struct parse_events__term test_terms[] = {
 	{
-		.config  = (char *) "krava01",
-		.val.num = 15,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava01",
+		.val.num   = 15,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava02",
-		.val.num = 170,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava02",
+		.val.num   = 170,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava03",
-		.val.num = 1,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava03",
+		.val.num   = 1,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava11",
-		.val.num = 27,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava11",
+		.val.num   = 27,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava12",
-		.val.num = 1,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava12",
+		.val.num   = 1,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava13",
-		.val.num = 2,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava13",
+		.val.num   = 2,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava21",
-		.val.num = 119,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava21",
+		.val.num   = 119,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava22",
-		.val.num = 11,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava22",
+		.val.num   = 11,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	{
-		.config  = (char *) "krava23",
-		.val.num = 2,
-		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+		.config    = (char *) "krava23",
+		.val.num   = 2,
+		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
+		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 };
 #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/8] perf, tool: Add list type for event term parsing
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
  2012-04-04 20:21 ` [PATCH 1/8] perf, tool: Fix NULL deref in hists browsing code Jiri Olsa
  2012-04-04 20:21 ` [PATCH 2/8] perf, tool: Split term type into value type and term type Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  2012-04-04 20:21 ` [PATCH 4/8] perf, tool: Add hardcoded name term for pmu events Jiri Olsa
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

Adding list type for event term to hanle multiple values
for single term. Term values can be now cpecified via
following grammar:

  event_term_list: event_term_list '|' event_term_elem
  event_term_list: event_term_elem '|' event_term_elem
  event_term_elem: PE_NAME | PE_VALUE

eg.:
  ...,term=str1|str2|num1|num2,...

This is going to be used for branch_type term in future.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/parse-events.c |   58 ++++++++++++++++++++++++++++-
 tools/perf/util/parse-events.h |   23 ++++++++++-
 tools/perf/util/parse-events.l |    1 +
 tools/perf/util/parse-events.y |   80 +++++++++++++++++++++++++++++++---------
 4 files changed, 140 insertions(+), 22 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 37b8fc9..e910632 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1031,8 +1031,9 @@ int parse_events__is_hardcoded_term(struct parse_events__term *term)
 	return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 }
 
-int parse_events__new_term(struct parse_events__term **_term, int type_val,
-			   int type_term, char *config, char *str, long num)
+static int new_term(struct parse_events__term **_term, int type_val,
+		    int type_term, char *config,
+		    char *str, long num, struct list_head *list)
 {
 	struct parse_events__term *term;
 
@@ -1052,6 +1053,10 @@ int parse_events__new_term(struct parse_events__term **_term, int type_val,
 	case PARSE_EVENTS__TERM_TYPE_STR:
 		term->val.str = str;
 		break;
+	case PARSE_EVENTS__TERM_TYPE_LIST:
+		INIT_LIST_HEAD(&term->val.list);
+		list_splice_tail(list, &term->val.list);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1060,6 +1065,55 @@ int parse_events__new_term(struct parse_events__term **_term, int type_val,
 	return 0;
 }
 
+int parse_events__term_num(struct parse_events__term **term,
+			   int type_term, char *config, long num)
+{
+	return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
+			config, NULL, num, NULL);
+}
+
+int parse_events__term_str(struct parse_events__term **term,
+			   int type_term, char *config, char *str)
+{
+	return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
+			config, str, 0, NULL);
+}
+
+int parse_events__term_list(struct parse_events__term **term,
+			    int type_term, char *config,
+			    struct list_head *list)
+{
+	return new_term(term, PARSE_EVENTS__TERM_TYPE_LIST, type_term,
+			config, NULL, 0, list);
+}
+
+int parse_events__term_elem(struct parse_events__term_elem **_elem,
+				     int type_val, char *str, long num)
+{
+	struct parse_events__term_elem *elem;
+
+	elem = zalloc(sizeof(*elem));
+	if (!elem)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&elem->list);
+	elem->type_val = type_val;
+
+	switch (type_val) {
+	case PARSE_EVENTS__TERM_TYPE_NUM:
+		elem->val.num = num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_STR:
+		elem->val.str = str;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_elem = elem;
+	return 0;
+}
+
 void parse_events__free_terms(struct list_head *terms)
 {
 	struct parse_events__term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7053aa3..363aa22 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -36,6 +36,7 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
 enum {
 	PARSE_EVENTS__TERM_TYPE_NUM,
 	PARSE_EVENTS__TERM_TYPE_STR,
+	PARSE_EVENTS__TERM_TYPE_LIST,
 };
 
 enum {
@@ -47,11 +48,22 @@ enum {
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 };
 
+
+struct parse_events__term_elem {
+	union {
+		char *str;
+		long  num;
+	} val;
+	int type_val;
+	struct list_head list;
+};
+
 struct parse_events__term {
 	char *config;
 	union {
 		char *str;
 		long  num;
+		struct list_head list;
 	} val;
 	int type_val;
 	int type_term;
@@ -59,8 +71,15 @@ struct parse_events__term {
 };
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term);
-int parse_events__new_term(struct parse_events__term **_term, int type_val,
-			   int type_term, char *config, char *str, long num);
+int parse_events__term_num(struct parse_events__term **_term,
+			   int type_term, char *config, long num);
+int parse_events__term_str(struct parse_events__term **_term,
+			   int type_term, char *config, char *str);
+int parse_events__term_list(struct parse_events__term **_term,
+			    int type_term, char *config,
+			    struct list_head *list);
+int parse_events__term_elem(struct parse_events__term_elem **_e,
+			    int type_val, char *str, long num);
 void parse_events__free_terms(struct list_head *terms);
 int parse_events_modifier(struct list_head *list __used, char *str __used);
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 05d766e..46c5b3a 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -118,6 +118,7 @@ r{num_raw_hex}		{ return raw(); }
 ,			{ return ','; }
 :			{ return ':'; }
 =			{ return '='; }
+\|			{ return '|'; }
 
 %%
 
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index b3b45e4..6d447b7 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -41,6 +41,8 @@ do { \
 %type <str> PE_MODIFIER_BP
 %type <head> event_config
 %type <term> event_term
+%type <head> event_term_list
+%type <elem> event_term_elem
 
 %union
 {
@@ -48,6 +50,7 @@ do { \
 	unsigned long num;
 	struct list_head *head;
 	struct parse_events__term *term;
+	struct parse_events__term_elem *elem;
 }
 %%
 
@@ -176,10 +179,8 @@ PE_NAME '=' PE_NAME
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term,
-					PARSE_EVENTS__TERM_TYPE_STR,
-					PARSE_EVENTS__TERM_TYPE_USER,
-					$1, $3, 0));
+	ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
+					$1, $3));
 	$$ = term;
 }
 |
@@ -187,10 +188,8 @@ PE_NAME '=' PE_VALUE
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term,
-					PARSE_EVENTS__TERM_TYPE_NUM,
-					PARSE_EVENTS__TERM_TYPE_USER,
-					$1, NULL, $3));
+	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+					$1, $3));
 	$$ = term;
 }
 |
@@ -198,10 +197,8 @@ PE_NAME
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term,
-					PARSE_EVENTS__TERM_TYPE_NUM,
-					PARSE_EVENTS__TERM_TYPE_USER,
-					$1, NULL, 1));
+	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+					$1, 1));
 	$$ = term;
 }
 |
@@ -209,9 +206,16 @@ PE_TERM '=' PE_VALUE
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term,
-					PARSE_EVENTS__TERM_TYPE_NUM,
-					$1, NULL, NULL, $3));
+	ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));
+	$$ = term;
+}
+|
+PE_TERM '=' event_term_list
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__term_list(&term, $1, NULL, $3));
+	free($3);
 	$$ = term;
 }
 |
@@ -219,12 +223,52 @@ PE_TERM
 {
 	struct parse_events__term *term;
 
-	ABORT_ON(parse_events__new_term(&term,
-					PARSE_EVENTS__TERM_TYPE_NUM,
-					$1, NULL, NULL, 1));
+	ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));
 	$$ = term;
 }
 
+event_term_list:
+event_term_list '|' event_term_elem
+{
+	struct list_head *list = $1;
+	struct parse_events__term_elem *elem = $3;
+
+	list_add_tail(&elem->list, list);
+	$$ = list;
+}
+|
+event_term_elem '|' event_term_elem
+{
+	struct list_head *list = malloc(sizeof(*list));
+	struct parse_events__term_elem *elem1 = $1;
+	struct parse_events__term_elem *elem2 = $3;
+
+	ABORT_ON(!list);
+	INIT_LIST_HEAD(list);
+	list_add_tail(&elem1->list, list);
+	list_add_tail(&elem2->list, list);
+	$$ = list;
+}
+
+event_term_elem:
+PE_NAME
+{
+	struct parse_events__term_elem *elem;
+
+	ABORT_ON(parse_events__term_elem(&elem, PARSE_EVENTS__TERM_TYPE_STR,
+					 $1, 0));
+	$$ = elem;
+}
+|
+PE_VALUE
+{
+	struct parse_events__term_elem *elem;
+
+	ABORT_ON(parse_events__term_elem(&elem, PARSE_EVENTS__TERM_TYPE_NUM,
+					 NULL, $1));
+	$$ = elem;
+}
+
 sep_dc: ':' |
 
 sep_slash_dc: '/' | ':' |
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/8] perf, tool: Add hardcoded name term for pmu events
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
                   ` (2 preceding siblings ...)
  2012-04-04 20:21 ` [PATCH 3/8] perf, tool: Add list type for event term parsing Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  2012-04-04 20:21 ` [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values Jiri Olsa
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

Adding a new hardcoded term 'name' allowing to specify a name
for the pmu event. The term is defined along with standard
pmu terms. If no 'name' term is given, the event name become
the pmu name itself ('cpu' for the example below).

running:
  perf stat -e cpu/config=1,name=krava1/u ls

will produce following output:
 ...
 Performance counter stats for 'ls':

                 0 krava1

       0.009779735 seconds time elapsed

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c      |   26 ++++++++++++++++++++++++++
 tools/perf/util/parse-events.c |   10 +++++++++-
 tools/perf/util/parse-events.h |    3 +++
 tools/perf/util/parse-events.l |    1 +
 tools/perf/util/parse-events.y |    8 ++++++++
 tools/perf/util/pmu.c          |   15 +++++++++++++--
 tools/perf/util/pmu.h          |    2 ++
 7 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 1c5b980..d522cf4 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -986,6 +986,28 @@ static int test__checkevent_list(struct perf_evlist *evlist)
 	return 0;
 }
 
+static int test__checkevent_pmu_name(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	/* cpu/config=1,name=krava1/u */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+
+	/* cpu/config=2/" */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "cpu"));
+
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -1091,6 +1113,10 @@ static struct test__event_st {
 		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
 		.check = test__checkevent_list,
 	},
+	{
+		.name  = "cpu/config=1,name=krava/u,cpu/config=2/u",
+		.check = test__checkevent_pmu_name,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e910632..c349cf3 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -682,7 +682,9 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
 	if (perf_pmu__config(pmu, &attr, head_config))
 		return -EINVAL;
 
-	return add_event(list, idx, &attr, (char *) "pmu");
+	name = perf_pmu__event_name(name, head_config);
+
+	return add_event(list, idx, &attr, name);
 }
 
 void parse_events_update_lists(struct list_head *list_event,
@@ -1031,6 +1033,11 @@ int parse_events__is_hardcoded_term(struct parse_events__term *term)
 	return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 }
 
+int parse_events__is_name_term(struct parse_events__term *term)
+{
+	return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
+}
+
 static int new_term(struct parse_events__term **_term, int type_val,
 		    int type_term, char *config,
 		    char *str, long num, struct list_head *list)
@@ -1050,6 +1057,7 @@ static int new_term(struct parse_events__term **_term, int type_val,
 	case PARSE_EVENTS__TERM_TYPE_NUM:
 		term->val.num = num;
 		break;
+	case PARSE_EVENTS__TERM_TYPE_NAME:
 	case PARSE_EVENTS__TERM_TYPE_STR:
 		term->val.str = str;
 		break;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 363aa22..cabcbc1 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,6 +4,7 @@
  * Parse symbolic events/counts passed in as options:
  */
 
+#include <linux/list.h>
 #include "../../../include/linux/perf_event.h"
 
 struct list_head;
@@ -44,6 +45,7 @@ enum {
 	PARSE_EVENTS__TERM_TYPE_CONFIG,
 	PARSE_EVENTS__TERM_TYPE_CONFIG1,
 	PARSE_EVENTS__TERM_TYPE_CONFIG2,
+	PARSE_EVENTS__TERM_TYPE_NAME,
 	PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 };
@@ -71,6 +73,7 @@ struct parse_events__term {
 };
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term);
+int parse_events__is_name_term(struct parse_events__term *term);
 int parse_events__term_num(struct parse_events__term **_term,
 			   int type_term, char *config, long num);
 int parse_events__term_str(struct parse_events__term **_term,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 46c5b3a..cd6614d 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -102,6 +102,7 @@ misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
 config			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
 config1			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
 config2			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+name			{ return term(PARSE_EVENTS__TERM_TYPE_NAME); }
 period			{ return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
 branch_type		{ return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
 
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 6d447b7..ef3ee2d 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -202,6 +202,14 @@ PE_NAME
 	$$ = term;
 }
 |
+PE_TERM '=' PE_NAME
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
+	$$ = term;
+}
+|
 PE_TERM '=' PE_VALUE
 {
 	struct parse_events__term *term;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 8ee219b..5526446 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -258,9 +258,9 @@ static int pmu_config_term(struct list_head *formats,
 static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
 		      struct list_head *head_terms)
 {
-	struct parse_events__term *term, *h;
+	struct parse_events__term *term;
 
-	list_for_each_entry_safe(term, h, head_terms, list)
+	list_for_each_entry(term, head_terms, list)
 		if (pmu_config_term(formats, attr, term))
 			return -EINVAL;
 
@@ -308,6 +308,17 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
 		set_bit(b, bits);
 }
 
+char *perf_pmu__event_name(char *name, struct list_head *head_terms)
+{
+	struct parse_events__term *term;
+
+	list_for_each_entry(term, head_terms, list)
+		if (parse_events__is_name_term(term))
+			return term->val.str;
+
+	return name;
+}
+
 /* Simulated format definitions. */
 static struct test_format {
 	const char *name;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 68c0db9..f602745 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -37,5 +37,7 @@ int perf_pmu__new_format(struct list_head *list, char *name,
 			 int config, unsigned long *bits);
 void perf_pmu__set_format(unsigned long *bits, long from, long to);
 
+char *perf_pmu__event_name(char *name, struct list_head *head_terms);
+
 int perf_pmu__test(void);
 #endif /* __PMU_H */
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
                   ` (3 preceding siblings ...)
  2012-04-04 20:21 ` [PATCH 4/8] perf, tool: Add hardcoded name term for pmu events Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  2012-04-05  4:50   ` Stephane Eranian
  2012-04-04 20:21 ` [PATCH 6/8] perf, tool: Move parse event automated tests to separated object Jiri Olsa
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Stephane Eranian, Jiri Olsa

Adding a support to specify branch_type as a hardcoded term
inside the pmu event definition.

It is possible to specify pmu event like:
  "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u"

Following string values could be used as value for branch_type:
  u (PERF_SAMPLE_BRANCH_USER)
  k (PERF_SAMPLE_BRANCH_KERNEL)
  hv (PERF_SAMPLE_BRANCH_HV)
  any (PERF_SAMPLE_BRANCH_ANY)
  any_call (PERF_SAMPLE_BRANCH_ANY_CALL)
  any_ret (PERF_SAMPLE_BRANCH_ANY_RETURN)
  ind_call (PERF_SAMPLE_BRANCH_IND_CALL)

Also a number could be specified as value.

CC: Stephane Eranian <eranian@google.com>

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-record.c    |   31 +-----------
 tools/perf/builtin-test.c      |   27 +++++++++++
 tools/perf/util/parse-events.c |  100 ++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/parse-events.h |    1 +
 4 files changed, 127 insertions(+), 32 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index be4e1ee..87fc68d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -641,27 +641,6 @@ out_delete_session:
 	return err;
 }
 
-#define BRANCH_OPT(n, m) \
-	{ .name = n, .mode = (m) }
-
-#define BRANCH_END { .name = NULL }
-
-struct branch_mode {
-	const char *name;
-	int mode;
-};
-
-static const struct branch_mode branch_modes[] = {
-	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
-	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
-	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
-	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
-	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
-	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
-	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
-	BRANCH_END
-};
-
 static int
 parse_branch_stack(const struct option *opt, const char *str, int unset)
 {
@@ -671,7 +650,6 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
 	 PERF_SAMPLE_BRANCH_HV)
 
 	uint64_t *mode = (uint64_t *)opt->value;
-	const struct branch_mode *br;
 	char *s, *os = NULL, *p;
 	int ret = -1;
 
@@ -692,21 +670,18 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
 			return -1;
 
 		for (;;) {
+			u64 bmode;
 			p = strchr(s, ',');
 			if (p)
 				*p = '\0';
 
-			for (br = branch_modes; br->name; br++) {
-				if (!strcasecmp(s, br->name))
-					break;
-			}
-			if (!br->name) {
+			if (parse_events__branch_type(&bmode, s)) {
 				ui__warning("unknown branch filter %s,"
 					    " check man page\n", s);
 				goto error;
 			}
 
-			*mode |= br->mode;
+			*mode |= bmode;
 
 			if (!p)
 				break;
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index d522cf4..2e4dc0a 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -1008,6 +1008,29 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
 	return 0;
 }
 
+static int test__checkevent_pmu_branch_type(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config2", 2 == evsel->attr.config2);
+
+#define BT (PERF_SAMPLE_BRANCH_USER | \
+	    PERF_SAMPLE_BRANCH_HV | \
+	    PERF_SAMPLE_BRANCH_ANY_RETURN)
+
+	TEST_ASSERT_VAL("wrong sample_type",
+		PERF_SAMPLE_BRANCH_STACK && evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong branch_type",
+		BT == evsel->attr.branch_sample_type);
+
+#undef BT
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -1117,6 +1140,10 @@ static struct test__event_st {
 		.name  = "cpu/config=1,name=krava/u,cpu/config=2/u",
 		.check = test__checkevent_pmu_name,
 	},
+	{
+		.name  = "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u",
+		.check = test__checkevent_pmu_branch_type,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c349cf3..076b1f8 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -590,6 +590,99 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
 	return add_event(list, idx, &attr, name);
 }
 
+#define BRANCH_OPT(n, m) { .name = n, .mode = (m) }
+#define BRANCH_END { .name = NULL }
+
+struct branch_mode {
+	const char *name;
+	int mode;
+};
+
+static const struct branch_mode branch_modes[] = {
+	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
+	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
+	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
+	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
+	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
+	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
+	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
+	BRANCH_END
+};
+
+int parse_events__branch_type(u64 *_type, char *str)
+{
+	const struct branch_mode *br;
+
+	for (br = branch_modes; br->name; br++) {
+		if (!strcasecmp(str, br->name)) {
+			*_type = br->mode;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+typedef int (process_term_list_cb)(struct parse_events__term_elem *elem,
+				   void *arg);
+
+static int branch_type_cb(struct parse_events__term_elem *elem, void *arg)
+{
+	u64 *_type = arg;
+	u64 type;
+
+	switch (elem->type_val) {
+	case PARSE_EVENTS__TERM_TYPE_NUM:
+		type = elem->val.num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_STR:
+		if (parse_events__branch_type(&type, elem->val.str))
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_type |= type;
+	return 0;
+}
+
+static int process_term_list(struct parse_events__term *term,
+			     process_term_list_cb cb, void *arg)
+{
+	struct parse_events__term_elem *elem;
+
+	list_for_each_entry(elem, &term->val.list, list)
+		if (cb(elem, arg))
+			return -EINVAL;
+
+	return 0;
+}
+
+static int branch_type(struct parse_events__term *term, u64 *_type)
+{
+	u64 type = 0;
+
+	switch (term->type_val) {
+	case PARSE_EVENTS__TERM_TYPE_NUM:
+		type = term->val.num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_STR:
+		if (parse_events__branch_type(&type, term->val.str))
+			return -EINVAL;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_LIST:
+		if (process_term_list(term, branch_type_cb, &type))
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_type = type;
+	return 0;
+}
+
 static int config_term(struct perf_event_attr *attr,
 		       struct parse_events__term *term)
 {
@@ -617,10 +710,9 @@ do {								\
 		attr->sample_period = term->val.num;
 		break;
 	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-		/*
-		 * TODO uncomment when the field is available
-		 * attr->branch_sample_type = term->val.num;
-		 */
+		attr->sample_type |= PERF_SAMPLE_BRANCH_STACK;
+		if (branch_type(term, (u64 *)&attr->branch_sample_type))
+			return -EINVAL;
 		break;
 	default:
 		return -EINVAL;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index cabcbc1..8bb673d 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -83,6 +83,7 @@ int parse_events__term_list(struct parse_events__term **_term,
 			    struct list_head *list);
 int parse_events__term_elem(struct parse_events__term_elem **_e,
 			    int type_val, char *str, long num);
+int parse_events__branch_type(u64 *_type, char *str);
 void parse_events__free_terms(struct list_head *terms);
 int parse_events_modifier(struct list_head *list __used, char *str __used);
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/8] perf, tool: Move parse event automated tests to separated object
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
                   ` (4 preceding siblings ...)
  2012-04-04 20:21 ` [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  2012-04-04 20:21 ` [PATCH 7/8] perf, tool: Add support for displaying event parser debug info Jiri Olsa
  2012-04-04 20:21 ` [PATCH 8/8] perf, tool: Use allocated list for each parsed event Jiri Olsa
  7 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

Moving event parsing specific tests into separated file:
  util/parse-events-test.c

Also changing the code a bit to ease running separate tests.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile                 |    1 +
 tools/perf/builtin-test.c           |  575 +----------------------------------
 tools/perf/util/parse-events-test.c |  588 +++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events.h      |    3 +
 4 files changed, 593 insertions(+), 574 deletions(-)
 create mode 100644 tools/perf/util/parse-events-test.c

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 820371f..7546dd5 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -353,6 +353,7 @@ LIB_OBJS += $(OUTPUT)util/help.o
 LIB_OBJS += $(OUTPUT)util/levenshtein.o
 LIB_OBJS += $(OUTPUT)util/parse-options.o
 LIB_OBJS += $(OUTPUT)util/parse-events.o
+LIB_OBJS += $(OUTPUT)util/parse-events-test.o
 LIB_OBJS += $(OUTPUT)util/path.o
 LIB_OBJS += $(OUTPUT)util/rbtree.o
 LIB_OBJS += $(OUTPUT)util/bitmap.o
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 2e4dc0a..7c61eef 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -604,579 +604,6 @@ out_free_threads:
 #undef nsyscalls
 }
 
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
-	if (!(cond)) { \
-		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
-		return -1; \
-	} \
-} while (0)
-
-static int test__checkevent_tracepoint(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong sample_type",
-		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-		evsel->attr.sample_type);
-	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
-	return 0;
-}
-
-static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-
-	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
-	list_for_each_entry(evsel, &evlist->entries, node) {
-		TEST_ASSERT_VAL("wrong type",
-			PERF_TYPE_TRACEPOINT == evsel->attr.type);
-		TEST_ASSERT_VAL("wrong sample_type",
-			(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
-			== evsel->attr.sample_type);
-		TEST_ASSERT_VAL("wrong sample_period",
-			1 == evsel->attr.sample_period);
-	}
-	return 0;
-}
-
-static int test__checkevent_raw(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_numeric(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",
-			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",
-			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong period",
-			100000 == evsel->attr.sample_period);
-	TEST_ASSERT_VAL("wrong config1",
-			0 == evsel->attr.config1);
-	TEST_ASSERT_VAL("wrong config2",
-			1 == evsel->attr.config2);
-	return 0;
-}
-
-static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",
-			PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_genhw(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
-	return 0;
-}
-
-static int test__checkevent_breakpoint(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
-					 evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
-					evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type",
-			HW_BREAKPOINT_X == evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type",
-			PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type",
-			HW_BREAKPOINT_R == evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len",
-			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type",
-			PERF_TYPE_BREAKPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong bp_type",
-			HW_BREAKPOINT_W == evsel->attr.bp_type);
-	TEST_ASSERT_VAL("wrong bp_len",
-			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
-	return 0;
-}
-
-static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_tracepoint(evlist);
-}
-
-static int
-test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-
-	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
-	list_for_each_entry(evsel, &evlist->entries, node) {
-		TEST_ASSERT_VAL("wrong exclude_user",
-				!evsel->attr.exclude_user);
-		TEST_ASSERT_VAL("wrong exclude_kernel",
-				evsel->attr.exclude_kernel);
-		TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-		TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-	}
-
-	return test__checkevent_tracepoint_multi(evlist);
-}
-
-static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_raw(evlist);
-}
-
-static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_numeric(evlist);
-}
-
-static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_symbolic_alias(evlist);
-}
-
-static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_genhw(evlist);
-}
-
-static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint(evlist);
-}
-
-static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint_x(evlist);
-}
-
-static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint_r(evlist);
-}
-
-static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return test__checkevent_breakpoint_w(evlist);
-}
-
-static int test__checkevent_pmu(struct perf_evlist *evlist)
-{
-
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1);
-	TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2);
-	TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period);
-
-	return 0;
-}
-
-static int test__checkevent_list(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-
-	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
-
-	/* r1 */
-	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
-	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
-	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	/* syscalls:sys_enter_open:k */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong sample_type",
-		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-		evsel->attr.sample_type);
-	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-	/* 1:1:hp */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-	return 0;
-}
-
-static int test__checkevent_pmu_name(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	/* cpu/config=1,name=krava1/u */
-	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
-
-	/* cpu/config=2/" */
-	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
-	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "cpu"));
-
-	return 0;
-}
-
-static int test__checkevent_pmu_branch_type(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel = list_entry(evlist->entries.next,
-					      struct perf_evsel, node);
-
-	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong config2", 2 == evsel->attr.config2);
-
-#define BT (PERF_SAMPLE_BRANCH_USER | \
-	    PERF_SAMPLE_BRANCH_HV | \
-	    PERF_SAMPLE_BRANCH_ANY_RETURN)
-
-	TEST_ASSERT_VAL("wrong sample_type",
-		PERF_SAMPLE_BRANCH_STACK && evsel->attr.sample_type);
-	TEST_ASSERT_VAL("wrong branch_type",
-		BT == evsel->attr.branch_sample_type);
-
-#undef BT
-	return 0;
-}
-
-static struct test__event_st {
-	const char *name;
-	__u32 type;
-	int (*check)(struct perf_evlist *evlist);
-} test__events[] = {
-	{
-		.name  = "syscalls:sys_enter_open",
-		.check = test__checkevent_tracepoint,
-	},
-	{
-		.name  = "syscalls:*",
-		.check = test__checkevent_tracepoint_multi,
-	},
-	{
-		.name  = "r1a",
-		.check = test__checkevent_raw,
-	},
-	{
-		.name  = "1:1",
-		.check = test__checkevent_numeric,
-	},
-	{
-		.name  = "instructions",
-		.check = test__checkevent_symbolic_name,
-	},
-	{
-		.name  = "cycles/period=100000,config2/",
-		.check = test__checkevent_symbolic_name_config,
-	},
-	{
-		.name  = "faults",
-		.check = test__checkevent_symbolic_alias,
-	},
-	{
-		.name  = "L1-dcache-load-miss",
-		.check = test__checkevent_genhw,
-	},
-	{
-		.name  = "mem:0",
-		.check = test__checkevent_breakpoint,
-	},
-	{
-		.name  = "mem:0:x",
-		.check = test__checkevent_breakpoint_x,
-	},
-	{
-		.name  = "mem:0:r",
-		.check = test__checkevent_breakpoint_r,
-	},
-	{
-		.name  = "mem:0:w",
-		.check = test__checkevent_breakpoint_w,
-	},
-	{
-		.name  = "syscalls:sys_enter_open:k",
-		.check = test__checkevent_tracepoint_modifier,
-	},
-	{
-		.name  = "syscalls:*:u",
-		.check = test__checkevent_tracepoint_multi_modifier,
-	},
-	{
-		.name  = "r1a:kp",
-		.check = test__checkevent_raw_modifier,
-	},
-	{
-		.name  = "1:1:hp",
-		.check = test__checkevent_numeric_modifier,
-	},
-	{
-		.name  = "instructions:h",
-		.check = test__checkevent_symbolic_name_modifier,
-	},
-	{
-		.name  = "faults:u",
-		.check = test__checkevent_symbolic_alias_modifier,
-	},
-	{
-		.name  = "L1-dcache-load-miss:kp",
-		.check = test__checkevent_genhw_modifier,
-	},
-	{
-		.name  = "mem:0:u",
-		.check = test__checkevent_breakpoint_modifier,
-	},
-	{
-		.name  = "mem:0:x:k",
-		.check = test__checkevent_breakpoint_x_modifier,
-	},
-	{
-		.name  = "mem:0:r:hp",
-		.check = test__checkevent_breakpoint_r_modifier,
-	},
-	{
-		.name  = "mem:0:w:up",
-		.check = test__checkevent_breakpoint_w_modifier,
-	},
-	{
-		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
-		.check = test__checkevent_pmu,
-	},
-	{
-		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
-		.check = test__checkevent_list,
-	},
-	{
-		.name  = "cpu/config=1,name=krava/u,cpu/config=2/u",
-		.check = test__checkevent_pmu_name,
-	},
-	{
-		.name  = "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u",
-		.check = test__checkevent_pmu_branch_type,
-	},
-};
-
-#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
-
-static int test__parse_events(void)
-{
-	struct perf_evlist *evlist;
-	u_int i;
-	int ret = 0;
-
-	for (i = 0; i < TEST__EVENTS_CNT; i++) {
-		struct test__event_st *e = &test__events[i];
-
-		evlist = perf_evlist__new(NULL, NULL);
-		if (evlist == NULL)
-			break;
-
-		ret = parse_events(evlist, e->name, 0);
-		if (ret) {
-			pr_debug("failed to parse event '%s', err %d\n",
-				 e->name, ret);
-			break;
-		}
-
-		ret = e->check(evlist);
-		perf_evlist__delete(evlist);
-		if (ret)
-			break;
-	}
-
-	return ret;
-}
-
 static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
 					 size_t *sizep)
 {
@@ -1697,7 +1124,7 @@ static struct test {
 	},
 	{
 		.desc = "parse events tests",
-		.func = test__parse_events,
+		.func = parse_events__test,
 	},
 #if defined(__x86_64__) || defined(__i386__)
 	{
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
new file mode 100644
index 0000000..73ff0af
--- /dev/null
+++ b/tools/perf/util/parse-events-test.c
@@ -0,0 +1,588 @@
+
+#include "parse-events.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "../../../include/linux/hw_breakpoint.h"
+
+#define TEST_ASSERT_VAL(text, cond) \
+do { \
+	if (!(cond)) { \
+		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
+		return -1; \
+	} \
+} while (0)
+
+static int test__checkevent_tracepoint(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+		evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	return 0;
+}
+
+static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		TEST_ASSERT_VAL("wrong type",
+			PERF_TYPE_TRACEPOINT == evsel->attr.type);
+		TEST_ASSERT_VAL("wrong sample_type",
+			(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
+			== evsel->attr.sample_type);
+		TEST_ASSERT_VAL("wrong sample_period",
+			1 == evsel->attr.sample_period);
+	}
+	return 0;
+}
+
+static int test__checkevent_raw(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_numeric(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong period",
+			100000 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong config1",
+			0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2",
+			1 == evsel->attr.config2);
+	return 0;
+}
+
+static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_genhw(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
+	return 0;
+}
+
+static int test__checkevent_breakpoint(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
+					 evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
+					evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type",
+			HW_BREAKPOINT_X == evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type",
+			PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type",
+			HW_BREAKPOINT_R == evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len",
+			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type",
+			PERF_TYPE_BREAKPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong bp_type",
+			HW_BREAKPOINT_W == evsel->attr.bp_type);
+	TEST_ASSERT_VAL("wrong bp_len",
+			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+	return 0;
+}
+
+static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_tracepoint(evlist);
+}
+
+static int
+test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		TEST_ASSERT_VAL("wrong exclude_user",
+				!evsel->attr.exclude_user);
+		TEST_ASSERT_VAL("wrong exclude_kernel",
+				evsel->attr.exclude_kernel);
+		TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+		TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	}
+
+	return test__checkevent_tracepoint_multi(evlist);
+}
+
+static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_raw(evlist);
+}
+
+static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_numeric(evlist);
+}
+
+static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_symbolic_alias(evlist);
+}
+
+static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_genhw(evlist);
+}
+
+static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint(evlist);
+}
+
+static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_x(evlist);
+}
+
+static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_r(evlist);
+}
+
+static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_w(evlist);
+}
+
+static int test__checkevent_pmu(struct perf_evlist *evlist)
+{
+
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2);
+	TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period);
+
+	return 0;
+}
+
+static int test__checkevent_list(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* r1 */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* syscalls:sys_enter_open:k */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+		evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* 1:1:hp */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return 0;
+}
+
+static int test__checkevent_pmu_name(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	/* cpu/config=1,name=krava1/u */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+
+	/* cpu/config=2/" */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "cpu"));
+
+	return 0;
+}
+
+static int test__checkevent_pmu_branch_type(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config2", 2 == evsel->attr.config2);
+
+#define BT (PERF_SAMPLE_BRANCH_USER | \
+	    PERF_SAMPLE_BRANCH_HV | \
+	    PERF_SAMPLE_BRANCH_ANY_RETURN)
+
+	TEST_ASSERT_VAL("wrong sample_type",
+		PERF_SAMPLE_BRANCH_STACK && evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong branch_type",
+		BT == evsel->attr.branch_sample_type);
+
+#undef BT
+	return 0;
+}
+
+static struct test__event_st {
+	const char *name;
+	__u32 type;
+	int (*check)(struct perf_evlist *evlist);
+} test__events[] = {
+	[0] = {
+		.name  = "syscalls:sys_enter_open",
+		.check = test__checkevent_tracepoint,
+	},
+	[1] = {
+		.name  = "syscalls:*",
+		.check = test__checkevent_tracepoint_multi,
+	},
+	[2] = {
+		.name  = "r1a",
+		.check = test__checkevent_raw,
+	},
+	[3] = {
+		.name  = "1:1",
+		.check = test__checkevent_numeric,
+	},
+	[4] = {
+		.name  = "instructions",
+		.check = test__checkevent_symbolic_name,
+	},
+	[5] = {
+		.name  = "cycles/period=100000,config2/",
+		.check = test__checkevent_symbolic_name_config,
+	},
+	[6] = {
+		.name  = "faults",
+		.check = test__checkevent_symbolic_alias,
+	},
+	[7] = {
+		.name  = "L1-dcache-load-miss",
+		.check = test__checkevent_genhw,
+	},
+	[8] = {
+		.name  = "mem:0",
+		.check = test__checkevent_breakpoint,
+	},
+	[9] = {
+		.name  = "mem:0:x",
+		.check = test__checkevent_breakpoint_x,
+	},
+	[10] = {
+		.name  = "mem:0:r",
+		.check = test__checkevent_breakpoint_r,
+	},
+	[11] = {
+		.name  = "mem:0:w",
+		.check = test__checkevent_breakpoint_w,
+	},
+	[12] = {
+		.name  = "syscalls:sys_enter_open:k",
+		.check = test__checkevent_tracepoint_modifier,
+	},
+	[13] = {
+		.name  = "syscalls:*:u",
+		.check = test__checkevent_tracepoint_multi_modifier,
+	},
+	[14] = {
+		.name  = "r1a:kp",
+		.check = test__checkevent_raw_modifier,
+	},
+	[15] = {
+		.name  = "1:1:hp",
+		.check = test__checkevent_numeric_modifier,
+	},
+	[16] = {
+		.name  = "instructions:h",
+		.check = test__checkevent_symbolic_name_modifier,
+	},
+	[17] = {
+		.name  = "faults:u",
+		.check = test__checkevent_symbolic_alias_modifier,
+	},
+	[18] = {
+		.name  = "L1-dcache-load-miss:kp",
+		.check = test__checkevent_genhw_modifier,
+	},
+	[19] = {
+		.name  = "mem:0:u",
+		.check = test__checkevent_breakpoint_modifier,
+	},
+	[20] = {
+		.name  = "mem:0:x:k",
+		.check = test__checkevent_breakpoint_x_modifier,
+	},
+	[21] = {
+		.name  = "mem:0:r:hp",
+		.check = test__checkevent_breakpoint_r_modifier,
+	},
+	[22] = {
+		.name  = "mem:0:w:up",
+		.check = test__checkevent_breakpoint_w_modifier,
+	},
+	[23] = {
+		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
+		.check = test__checkevent_pmu,
+	},
+	[24] = {
+		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
+		.check = test__checkevent_list,
+	},
+	[25] = {
+		.name  = "cpu/config=1,name=krava/u,cpu/config=2/u",
+		.check = test__checkevent_pmu_name,
+	},
+	[26] = {
+		.name  = "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u",
+		.check = test__checkevent_pmu_branch_type,
+	},
+};
+
+#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
+
+static int test(struct test__event_st *e)
+{
+	struct perf_evlist *evlist;
+	int ret;
+
+	evlist = perf_evlist__new(NULL, NULL);
+	if (evlist == NULL)
+		return -ENOMEM;
+
+	ret = parse_events(evlist, e->name, 0);
+	if (ret) {
+		pr_debug("failed to parse event '%s', err %d\n",
+			 e->name, ret);
+		return ret;
+	}
+
+	ret = e->check(evlist);
+	perf_evlist__delete(evlist);
+
+	return ret;
+}
+
+int parse_events__test(void)
+{
+	u_int i;
+	int ret = 0;
+
+	for (i = 0; i < TEST__EVENTS_CNT; i++) {
+		struct test__event_st *e = &test__events[i];
+
+		pr_debug("running test %d '%s'\n", i, e->name);
+		ret = test(e);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8bb673d..66e08f4 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -5,6 +5,8 @@
  */
 
 #include <linux/list.h>
+#include <stdbool.h>
+#include "types.h"
 #include "../../../include/linux/perf_event.h"
 
 struct list_head;
@@ -105,6 +107,7 @@ void parse_events_update_lists(struct list_head *list_event,
 void parse_events_error(struct list_head *list_all,
 			struct list_head *list_event,
 			int *idx, char const *msg);
+int parse_events__test(void);
 
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/8] perf, tool: Add support for displaying event parser debug info
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
                   ` (5 preceding siblings ...)
  2012-04-04 20:21 ` [PATCH 6/8] perf, tool: Move parse event automated tests to separated object Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  2012-04-04 20:21 ` [PATCH 8/8] perf, tool: Use allocated list for each parsed event Jiri Olsa
  7 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

Adding PARSER_DEBUG Makefile variable to enable building event
scanner/parser with debug enabled. This results in verbose
output right out of the scanner/parser.

It's usefull for debuging the event parser. Keeping this only
for event parser so far.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile            |   12 +++++++++---
 tools/perf/util/parse-events.c |    6 ++++++
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7546dd5..33bec3a 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -116,7 +116,13 @@ ifndef PERF_DEBUG
   CFLAGS_OPTIMIZE = -O6
 endif
 
-CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+ifdef PARSER_DEBUG
+	PARSER_DEBUG_BISON  := -t
+	PARSER_DEBUG_FLEX   := -d
+	PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
+endif
+
+CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
 EXTLIBS = -lpthread -lrt -lelf -lm
 ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 ALL_LDFLAGS = $(LDFLAGS)
@@ -238,8 +244,8 @@ FLEX = $(CROSS_COMPILE)flex
 BISON= $(CROSS_COMPILE)bison
 
 event-parser:
-	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c
-	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
+	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
 
 $(OUTPUT)util/parse-events-flex.c: event-parser
 $(OUTPUT)util/parse-events-bison.c: event-parser
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 076b1f8..b6136fd 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,6 +23,9 @@ struct event_symbol {
 	const char	*alias;
 };
 
+#ifdef PARSER_DEBUG
+extern int parse_events_debug;
+#endif
 int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
 		       int *idx);
 
@@ -863,6 +866,9 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 
 	buffer = parse_events__scan_string(str);
 
+#ifdef PARSER_DEBUG
+	parse_events_debug = 1;
+#endif
 	ret = parse_events_parse(&list, &list_tmp, &idx);
 
 	parse_events__flush_buffer(buffer);
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 8/8] perf, tool: Use allocated list for each parsed event
  2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
                   ` (6 preceding siblings ...)
  2012-04-04 20:21 ` [PATCH 7/8] perf, tool: Add support for displaying event parser debug info Jiri Olsa
@ 2012-04-04 20:21 ` Jiri Olsa
  7 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2012-04-04 20:21 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

Switch from using static temporary event list into dynamically
allocated one. This way we dont need to pass temp list to the
parse_events_parse which makes the interface more clear.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/parse-events.c |   39 ++++++++++++++---------
 tools/perf/util/parse-events.h |   16 +++------
 tools/perf/util/parse-events.y |   69 ++++++++++++++++++++++++++++++---------
 3 files changed, 83 insertions(+), 41 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b6136fd..d4abd00 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -26,8 +26,7 @@ struct event_symbol {
 #ifdef PARSER_DEBUG
 extern int parse_events_debug;
 #endif
-int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
-		       int *idx);
+int parse_events_parse(struct list_head *list, int *idx);
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -358,20 +357,30 @@ const char *__event_name(int type, u64 config)
 	return "unknown";
 }
 
-static int add_event(struct list_head *list, int *idx,
+static int add_event(struct list_head **_list, int *idx,
 		     struct perf_event_attr *attr, char *name)
 {
 	struct perf_evsel *evsel;
+	struct list_head *list = *_list;
+
+	if (!list) {
+		list = malloc(sizeof(*list));
+		if (!list)
+			return -ENOMEM;
+		INIT_LIST_HEAD(list);
+	}
 
 	event_attr_init(attr);
 
 	evsel = perf_evsel__new(attr, (*idx)++);
-	if (!evsel)
+	if (!evsel) {
+		free(list);
 		return -ENOMEM;
-
-	list_add_tail(&evsel->node, list);
+	}
 
 	evsel->name = strdup(name);
+	list_add_tail(&evsel->node, list);
+	*_list = list;
 	return 0;
 }
 
@@ -393,7 +402,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
 	return -1;
 }
 
-int parse_events_add_cache(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)
 {
 	struct perf_event_attr attr;
@@ -454,7 +463,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
 	return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint(struct list_head *list, int *idx,
+static int add_tracepoint(struct list_head **list, int *idx,
 			  char *sys_name, char *evt_name)
 {
 	struct perf_event_attr attr;
@@ -491,7 +500,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
 	return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint_multi(struct list_head *list, int *idx,
+static int add_tracepoint_multi(struct list_head **list, int *idx,
 				char *sys_name, char *evt_name)
 {
 	char evt_path[MAXPATHLEN];
@@ -522,7 +531,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,
 	return ret;
 }
 
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
 				char *sys, char *event)
 {
 	int ret;
@@ -566,7 +575,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 	return 0;
 }
 
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
 				void *ptr, char *type)
 {
 	struct perf_event_attr attr;
@@ -738,7 +747,7 @@ static int config_attr(struct perf_event_attr *attr,
 	return 0;
 }
 
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
 			     unsigned long type, unsigned long config,
 			     struct list_head *head_config)
 {
@@ -756,7 +765,7 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
 			 (char *) __event_name(type, config));
 }
 
-int parse_events_add_pmu(struct list_head *list, int *idx,
+int parse_events_add_pmu(struct list_head **list, int *idx,
 			 char *name, struct list_head *head_config)
 {
 	struct perf_event_attr attr;
@@ -791,7 +800,7 @@ void parse_events_update_lists(struct list_head *list_event,
 	 * list, for next event definition.
 	 */
 	list_splice_tail(list_event, list_all);
-	INIT_LIST_HEAD(list_event);
+	free(list_event);
 }
 
 int parse_events_modifier(struct list_head *list, char *str)
@@ -869,7 +878,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 #ifdef PARSER_DEBUG
 	parse_events_debug = 1;
 #endif
-	ret = parse_events_parse(&list, &list_tmp, &idx);
+	ret = parse_events_parse(&list, &idx);
 
 	parse_events__flush_buffer(buffer);
 	parse_events__delete_buffer(buffer);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 66e08f4..8651757 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -87,25 +87,21 @@ int parse_events__term_elem(struct parse_events__term_elem **_e,
 			    int type_val, char *str, long num);
 int parse_events__branch_type(u64 *_type, char *str);
 void parse_events__free_terms(struct list_head *terms);
-int parse_events_modifier(struct list_head *list __used, char *str __used);
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_modifier(struct list_head *list, char *str);
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
 				char *sys, char *event);
-int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
-			 unsigned long config1, unsigned long config2,
-			 char *mod);
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
 			     unsigned long type, unsigned long config,
 			     struct list_head *head_config);
-int parse_events_add_cache(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,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
 				void *ptr, char *type);
-int parse_events_add_pmu(struct list_head *list, int *idx,
+int parse_events_add_pmu(struct list_head **list, int *idx,
 			 char *pmu , struct list_head *head_config);
 void parse_events_update_lists(struct list_head *list_event,
 			       struct list_head *list_all);
 void parse_events_error(struct list_head *list_all,
-			struct list_head *list_event,
 			int *idx, char const *msg);
 int parse_events__test(void);
 
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index ef3ee2d..5899a0e 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,7 +1,6 @@
 
 %name-prefix "parse_events_"
 %parse-param {struct list_head *list_all}
-%parse-param {struct list_head *list_event}
 %parse-param {int *idx}
 
 %{
@@ -43,6 +42,14 @@ do { \
 %type <term> event_term
 %type <head> event_term_list
 %type <elem> event_term_elem
+%type <head> event_pmu
+%type <head> event_legacy_symbol
+%type <head> event_legacy_cache
+%type <head> event_legacy_mem
+%type <head> event_legacy_tracepoint
+%type <head> event_legacy_numeric
+%type <head> event_legacy_raw
+%type <head> event_def
 
 %union
 {
@@ -65,13 +72,13 @@ event_def PE_MODIFIER_EVENT
 	 * (there could be more events added for multiple tracepoint
 	 * definitions via '*?'.
 	 */
-	ABORT_ON(parse_events_modifier(list_event, $2));
-	parse_events_update_lists(list_event, list_all);
+	ABORT_ON(parse_events_modifier($1, $2));
+	parse_events_update_lists($1, list_all);
 }
 |
 event_def
 {
-	parse_events_update_lists(list_event, list_all);
+	parse_events_update_lists($1, list_all);
 }
 
 event_def: event_pmu |
@@ -85,71 +92,102 @@ event_def: event_pmu |
 event_pmu:
 PE_NAME '/' event_config '/'
 {
-	ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
 	parse_events__free_terms($3);
+	$$ = list;
 }
 
 event_legacy_symbol:
 PE_VALUE_SYM '/' event_config '/'
 {
+	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
+	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
 	parse_events__free_terms($3);
+	$$ = list;
 }
 |
 PE_VALUE_SYM sep_slash_dc
 {
+	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
+	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
+	$$ = list;
 }
 
 event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
-	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
+	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
-	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
+	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE
 {
-	ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
+	$$ = list;
 }
 
 event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
-	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
+	$$ = list;
 }
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
-	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
+	$$ = list;
 }
 
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
-	ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
+	$$ = list;
 }
 
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-	ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
+	$$ = list;
 }
 
 event_legacy_raw:
 PE_RAW
 {
-	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
+	struct list_head *list = NULL;
+
+	ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
+	$$ = list;
 }
 
 event_config:
@@ -284,7 +322,6 @@ sep_slash_dc: '/' | ':' |
 %%
 
 void parse_events_error(struct list_head *list_all __used,
-			struct list_head *list_event __used,
 			int *idx __used,
 			char const *msg __used)
 {
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values
  2012-04-04 20:21 ` [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values Jiri Olsa
@ 2012-04-05  4:50   ` Stephane Eranian
  2012-04-05  8:59     ` Jiri Olsa
  0 siblings, 1 reply; 13+ messages in thread
From: Stephane Eranian @ 2012-04-05  4:50 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, David Ahern

On Wed, Apr 4, 2012 at 1:21 PM, Jiri Olsa <jolsa@redhat.com> wrote:
> Adding a support to specify branch_type as a hardcoded term
> inside the pmu event definition.
>
> It is possible to specify pmu event like:
>  "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u"
>
> Following string values could be used as value for branch_type:
>  u (PERF_SAMPLE_BRANCH_USER)
>  k (PERF_SAMPLE_BRANCH_KERNEL)
>  hv (PERF_SAMPLE_BRANCH_HV)
>  any (PERF_SAMPLE_BRANCH_ANY)
>  any_call (PERF_SAMPLE_BRANCH_ANY_CALL)
>  any_ret (PERF_SAMPLE_BRANCH_ANY_RETURN)
>  ind_call (PERF_SAMPLE_BRANCH_IND_CALL)
>
> Also a number could be specified as value.
>
Although it would be nice to have, the current kernel sampling
buffer layout + perf would not be able to parse the RECORD_SAMPLE
if you were to sample different things for different events:

 perf record -e
cpu/event=0xc0,umask=1:branch_type=any/,cpu/event=0x3c,umask=0x1/

Perf report/annotate would not be able to distinguish a RECORD_SAMPLE
generated by the first or the second event. That's because the RECORD_SAMPLE
fixed header does not contain enough info to determine which event caused the
record to be generated. You need to event ID to decode the sample. The event ID
gives you the attr struct which gives you the attr->sample_type which drives the
layout of the RECORD_SAMPLE variable size body. The event ID is currently
saved "somewhere" in the variable-size body of the sample. You have  a chicken
and egg problem here.

Next week, I will post a patch to extend the existing format to support sampling
on multiple events with different sample_type bitmasks.



> CC: Stephane Eranian <eranian@google.com>
>
> Signed-off-by: Jiri Olsa <jolsa@redhat.com>
> ---
>  tools/perf/builtin-record.c    |   31 +-----------
>  tools/perf/builtin-test.c      |   27 +++++++++++
>  tools/perf/util/parse-events.c |  100 ++++++++++++++++++++++++++++++++++++++--
>  tools/perf/util/parse-events.h |    1 +
>  4 files changed, 127 insertions(+), 32 deletions(-)
>
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index be4e1ee..87fc68d 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -641,27 +641,6 @@ out_delete_session:
>        return err;
>  }
>
> -#define BRANCH_OPT(n, m) \
> -       { .name = n, .mode = (m) }
> -
> -#define BRANCH_END { .name = NULL }
> -
> -struct branch_mode {
> -       const char *name;
> -       int mode;
> -};
> -
> -static const struct branch_mode branch_modes[] = {
> -       BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
> -       BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
> -       BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
> -       BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
> -       BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
> -       BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
> -       BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
> -       BRANCH_END
> -};
> -
>  static int
>  parse_branch_stack(const struct option *opt, const char *str, int unset)
>  {
> @@ -671,7 +650,6 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
>         PERF_SAMPLE_BRANCH_HV)
>
>        uint64_t *mode = (uint64_t *)opt->value;
> -       const struct branch_mode *br;
>        char *s, *os = NULL, *p;
>        int ret = -1;
>
> @@ -692,21 +670,18 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
>                        return -1;
>
>                for (;;) {
> +                       u64 bmode;
>                        p = strchr(s, ',');
>                        if (p)
>                                *p = '\0';
>
> -                       for (br = branch_modes; br->name; br++) {
> -                               if (!strcasecmp(s, br->name))
> -                                       break;
> -                       }
> -                       if (!br->name) {
> +                       if (parse_events__branch_type(&bmode, s)) {
>                                ui__warning("unknown branch filter %s,"
>                                            " check man page\n", s);
>                                goto error;
>                        }
>
> -                       *mode |= br->mode;
> +                       *mode |= bmode;
>
>                        if (!p)
>                                break;
> diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
> index d522cf4..2e4dc0a 100644
> --- a/tools/perf/builtin-test.c
> +++ b/tools/perf/builtin-test.c
> @@ -1008,6 +1008,29 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
>        return 0;
>  }
>
> +static int test__checkevent_pmu_branch_type(struct perf_evlist *evlist)
> +{
> +       struct perf_evsel *evsel = list_entry(evlist->entries.next,
> +                                             struct perf_evsel, node);
> +
> +       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
> +       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
> +       TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
> +       TEST_ASSERT_VAL("wrong config2", 2 == evsel->attr.config2);
> +
> +#define BT (PERF_SAMPLE_BRANCH_USER | \
> +           PERF_SAMPLE_BRANCH_HV | \
> +           PERF_SAMPLE_BRANCH_ANY_RETURN)
> +
> +       TEST_ASSERT_VAL("wrong sample_type",
> +               PERF_SAMPLE_BRANCH_STACK && evsel->attr.sample_type);
> +       TEST_ASSERT_VAL("wrong branch_type",
> +               BT == evsel->attr.branch_sample_type);
> +
> +#undef BT
> +       return 0;
> +}
> +
>  static struct test__event_st {
>        const char *name;
>        __u32 type;
> @@ -1117,6 +1140,10 @@ static struct test__event_st {
>                .name  = "cpu/config=1,name=krava/u,cpu/config=2/u",
>                .check = test__checkevent_pmu_name,
>        },
> +       {
> +               .name  = "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u",
> +               .check = test__checkevent_pmu_branch_type,
> +       },
>  };
>
>  #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index c349cf3..076b1f8 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -590,6 +590,99 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
>        return add_event(list, idx, &attr, name);
>  }
>
> +#define BRANCH_OPT(n, m) { .name = n, .mode = (m) }
> +#define BRANCH_END { .name = NULL }
> +
> +struct branch_mode {
> +       const char *name;
> +       int mode;
> +};
> +
> +static const struct branch_mode branch_modes[] = {
> +       BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
> +       BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
> +       BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
> +       BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
> +       BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
> +       BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
> +       BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
> +       BRANCH_END
> +};
> +
> +int parse_events__branch_type(u64 *_type, char *str)
> +{
> +       const struct branch_mode *br;
> +
> +       for (br = branch_modes; br->name; br++) {
> +               if (!strcasecmp(str, br->name)) {
> +                       *_type = br->mode;
> +                       return 0;
> +               }
> +       }
> +
> +       return -EINVAL;
> +}
> +
> +typedef int (process_term_list_cb)(struct parse_events__term_elem *elem,
> +                                  void *arg);
> +
> +static int branch_type_cb(struct parse_events__term_elem *elem, void *arg)
> +{
> +       u64 *_type = arg;
> +       u64 type;
> +
> +       switch (elem->type_val) {
> +       case PARSE_EVENTS__TERM_TYPE_NUM:
> +               type = elem->val.num;
> +               break;
> +       case PARSE_EVENTS__TERM_TYPE_STR:
> +               if (parse_events__branch_type(&type, elem->val.str))
> +                       return -EINVAL;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       *_type |= type;
> +       return 0;
> +}
> +
> +static int process_term_list(struct parse_events__term *term,
> +                            process_term_list_cb cb, void *arg)
> +{
> +       struct parse_events__term_elem *elem;
> +
> +       list_for_each_entry(elem, &term->val.list, list)
> +               if (cb(elem, arg))
> +                       return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static int branch_type(struct parse_events__term *term, u64 *_type)
> +{
> +       u64 type = 0;
> +
> +       switch (term->type_val) {
> +       case PARSE_EVENTS__TERM_TYPE_NUM:
> +               type = term->val.num;
> +               break;
> +       case PARSE_EVENTS__TERM_TYPE_STR:
> +               if (parse_events__branch_type(&type, term->val.str))
> +                       return -EINVAL;
> +               break;
> +       case PARSE_EVENTS__TERM_TYPE_LIST:
> +               if (process_term_list(term, branch_type_cb, &type))
> +                       return -EINVAL;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       *_type = type;
> +       return 0;
> +}
> +
>  static int config_term(struct perf_event_attr *attr,
>                       struct parse_events__term *term)
>  {
> @@ -617,10 +710,9 @@ do {                                                               \
>                attr->sample_period = term->val.num;
>                break;
>        case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
> -               /*
> -                * TODO uncomment when the field is available
> -                * attr->branch_sample_type = term->val.num;
> -                */
> +               attr->sample_type |= PERF_SAMPLE_BRANCH_STACK;
> +               if (branch_type(term, (u64 *)&attr->branch_sample_type))
> +                       return -EINVAL;
>                break;
>        default:
>                return -EINVAL;
> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> index cabcbc1..8bb673d 100644
> --- a/tools/perf/util/parse-events.h
> +++ b/tools/perf/util/parse-events.h
> @@ -83,6 +83,7 @@ int parse_events__term_list(struct parse_events__term **_term,
>                            struct list_head *list);
>  int parse_events__term_elem(struct parse_events__term_elem **_e,
>                            int type_val, char *str, long num);
> +int parse_events__branch_type(u64 *_type, char *str);
>  void parse_events__free_terms(struct list_head *terms);
>  int parse_events_modifier(struct list_head *list __used, char *str __used);
>  int parse_events_add_tracepoint(struct list_head *list, int *idx,
> --
> 1.7.7.6
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values
  2012-04-05  4:50   ` Stephane Eranian
@ 2012-04-05  8:59     ` Jiri Olsa
  2012-04-05 17:06       ` Stephane Eranian
  0 siblings, 1 reply; 13+ messages in thread
From: Jiri Olsa @ 2012-04-05  8:59 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, David Ahern

On Wed, Apr 04, 2012 at 09:50:12PM -0700, Stephane Eranian wrote:
> On Wed, Apr 4, 2012 at 1:21 PM, Jiri Olsa <jolsa@redhat.com> wrote:
> > Adding a support to specify branch_type as a hardcoded term
> > inside the pmu event definition.
> >
> > It is possible to specify pmu event like:
> >  "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u"
> >
> > Following string values could be used as value for branch_type:
> >  u (PERF_SAMPLE_BRANCH_USER)
> >  k (PERF_SAMPLE_BRANCH_KERNEL)
> >  hv (PERF_SAMPLE_BRANCH_HV)
> >  any (PERF_SAMPLE_BRANCH_ANY)
> >  any_call (PERF_SAMPLE_BRANCH_ANY_CALL)
> >  any_ret (PERF_SAMPLE_BRANCH_ANY_RETURN)
> >  ind_call (PERF_SAMPLE_BRANCH_IND_CALL)
> >
> > Also a number could be specified as value.
> >
> Although it would be nice to have, the current kernel sampling
> buffer layout + perf would not be able to parse the RECORD_SAMPLE
> if you were to sample different things for different events:
> 
>  perf record -e
> cpu/event=0xc0,umask=1:branch_type=any/,cpu/event=0x3c,umask=0x1/
hi,
for some reason I thought there might be sense to have multiple branch
types enabled in a single event.. I misread the code probably

> 
> Perf report/annotate would not be able to distinguish a RECORD_SAMPLE
> generated by the first or the second event. That's because the RECORD_SAMPLE
> fixed header does not contain enough info to determine which event caused the
> record to be generated. You need to event ID to decode the sample. The event ID
> gives you the attr struct which gives you the attr->sample_type which drives the
> layout of the RECORD_SAMPLE variable size body. The event ID is currently
> saved "somewhere" in the variable-size body of the sample. You have  a chicken
> and egg problem here.

yep, I'm aware of this.. cool you're preparing fix

thanks,
jirka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values
  2012-04-05  8:59     ` Jiri Olsa
@ 2012-04-05 17:06       ` Stephane Eranian
  0 siblings, 0 replies; 13+ messages in thread
From: Stephane Eranian @ 2012-04-05 17:06 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, David Ahern

On Thu, Apr 5, 2012 at 1:59 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> On Wed, Apr 04, 2012 at 09:50:12PM -0700, Stephane Eranian wrote:
>> On Wed, Apr 4, 2012 at 1:21 PM, Jiri Olsa <jolsa@redhat.com> wrote:
>> > Adding a support to specify branch_type as a hardcoded term
>> > inside the pmu event definition.
>> >
>> > It is possible to specify pmu event like:
>> >  "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u"
>> >
>> > Following string values could be used as value for branch_type:
>> >  u (PERF_SAMPLE_BRANCH_USER)
>> >  k (PERF_SAMPLE_BRANCH_KERNEL)
>> >  hv (PERF_SAMPLE_BRANCH_HV)
>> >  any (PERF_SAMPLE_BRANCH_ANY)
>> >  any_call (PERF_SAMPLE_BRANCH_ANY_CALL)
>> >  any_ret (PERF_SAMPLE_BRANCH_ANY_RETURN)
>> >  ind_call (PERF_SAMPLE_BRANCH_IND_CALL)
>> >
>> > Also a number could be specified as value.
>> >
>> Although it would be nice to have, the current kernel sampling
>> buffer layout + perf would not be able to parse the RECORD_SAMPLE
>> if you were to sample different things for different events:
>>
>>  perf record -e
>> cpu/event=0xc0,umask=1:branch_type=any/,cpu/event=0x3c,umask=0x1/
> hi,
> for some reason I thought there might be sense to have multiple branch
> types enabled in a single event.. I misread the code probably
>

You can combine the branch types but I don't see how
this could be really useful. As for priv levels, you can of course
combine them. If they are not specificied, then the levels of
the associated event are used.

>>
>> Perf report/annotate would not be able to distinguish a RECORD_SAMPLE
>> generated by the first or the second event. That's because the RECORD_SAMPLE
>> fixed header does not contain enough info to determine which event caused the
>> record to be generated. You need to event ID to decode the sample. The event ID
>> gives you the attr struct which gives you the attr->sample_type which drives the
>> layout of the RECORD_SAMPLE variable size body. The event ID is currently
>> saved "somewhere" in the variable-size body of the sample. You have  a chicken
>> and egg problem here.
>
> yep, I'm aware of this.. cool you're preparing fix
>
> thanks,
> jirka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [tip:perf/core] perf hists browser: Fix NULL deref in hists browsing code
  2012-04-04 20:21 ` [PATCH 1/8] perf, tool: Fix NULL deref in hists browsing code Jiri Olsa
@ 2012-04-13 18:04   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 13+ messages in thread
From: tip-bot for Jiri Olsa @ 2012-04-13 18:04 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa,
	fweisbec, tglx, cjashfor, mingo

Commit-ID:  8493fe1daf15324eb13a4cc2f94e258716daa568
Gitweb:     http://git.kernel.org/tip/8493fe1daf15324eb13a4cc2f94e258716daa568
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Wed, 4 Apr 2012 22:21:31 +0200
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 5 Apr 2012 18:58:45 -0300

perf hists browser: Fix NULL deref in hists browsing code

If there's an event with no samples in data file, the perf report
command can segfault after entering the event details menu.

Following steps reproduce the issue:

 # ./perf record -e syscalls:sys_enter_kexec_load,syscalls:sys_enter_mmap ls
 # ./perf report
 # enter '0 syscalls:sys_enter_kexec_load' menu
 # pres ENTER twice

Above steps are valid assuming ls wont run kexec.. ;)

The check for sellection to be NULL is missing. The fix makes sure it's
being check. Above steps now endup with menu being displayed allowing
'Exit' as the only option.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1333570898-10505-2-git-send-email-jolsa@redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/ui/browsers/hists.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index d7a1c4a..2f83e5d 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -125,6 +125,9 @@ static int callchain__count_rows(struct rb_root *chain)
 
 static bool map_symbol__toggle_fold(struct map_symbol *self)
 {
+	if (!self)
+		return false;
+
 	if (!self->has_children)
 		return false;
 

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2012-04-13 18:04 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-04 20:21 [PATCH 0/8] perf tool: event parsing enhancements/fixes Jiri Olsa
2012-04-04 20:21 ` [PATCH 1/8] perf, tool: Fix NULL deref in hists browsing code Jiri Olsa
2012-04-13 18:04   ` [tip:perf/core] perf hists browser: " tip-bot for Jiri Olsa
2012-04-04 20:21 ` [PATCH 2/8] perf, tool: Split term type into value type and term type Jiri Olsa
2012-04-04 20:21 ` [PATCH 3/8] perf, tool: Add list type for event term parsing Jiri Olsa
2012-04-04 20:21 ` [PATCH 4/8] perf, tool: Add hardcoded name term for pmu events Jiri Olsa
2012-04-04 20:21 ` [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values Jiri Olsa
2012-04-05  4:50   ` Stephane Eranian
2012-04-05  8:59     ` Jiri Olsa
2012-04-05 17:06       ` Stephane Eranian
2012-04-04 20:21 ` [PATCH 6/8] perf, tool: Move parse event automated tests to separated object Jiri Olsa
2012-04-04 20:21 ` [PATCH 7/8] perf, tool: Add support for displaying event parser debug info Jiri Olsa
2012-04-04 20:21 ` [PATCH 8/8] perf, tool: Use allocated list for each parsed event Jiri Olsa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.