linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/3] perf tool: Add new event group management
@ 2011-12-15 15:30 Jiri Olsa
  2011-12-15 15:30 ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Jiri Olsa
                   ` (2 more replies)
  0 siblings, 3 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-15 15:30 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel

hi,
adding support for creating event groups based on the way they
are specified on the command line.

As reading through some lkml postings like:
http://marc.info/?t=130105133700002&r=1&w=2
http://marc.info/?t=129065042800002&r=1&w=2

it seems decided to use bison/flex for event parsing first,
and do the group management on the top of it.. and thats what
I'm trying to do in this patchset.

Since this is quite hot code I expect some discussion/reposts ;),
so sending it first as RFC..

attached patches:
  1/3 perf, tool: Add parser generator for events parsing
  2/3 perf, tool: Add new event group management
  3/3 perf, tool: Add more automated tests for event parsing

thanks for comments,
jirka
---
 tools/perf/Makefile                  |   23 ++
 tools/perf/builtin-record.c          |    8 +-
 tools/perf/builtin-stat.c            |   10 +-
 tools/perf/builtin-test.c            |  245 ++++++++++++++++++-
 tools/perf/builtin-top.c             |    8 +-
 tools/perf/perf.h                    |    2 +-
 tools/perf/util/evsel.c              |   28 ++-
 tools/perf/util/evsel.h              |    9 +-
 tools/perf/util/group.c              |   23 ++
 tools/perf/util/group.h              |   25 ++
 tools/perf/util/parse-events-bison.y |  119 +++++++++
 tools/perf/util/parse-events-flex.l  |  111 ++++++++
 tools/perf/util/parse-events.c       |  465 ++++++++++++----------------------
 tools/perf/util/parse-events.h       |    9 +
 tools/perf/util/python.c             |    4 +
 tools/perf/util/top.h                |    2 +-
 16 files changed, 760 insertions(+), 331 deletions(-)

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

* [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-15 15:30 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
@ 2011-12-15 15:30 ` Jiri Olsa
  2011-12-16 14:02   ` Peter Zijlstra
  2011-12-20 17:37   ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Arnaldo Carvalho de Melo
  2011-12-15 15:30 ` [PATCH 2/3] perf, tool: Add new event group management Jiri Olsa
  2011-12-15 15:30 ` [PATCH 3/3] perf, tool: Add more automated tests for event parsing Jiri Olsa
  2 siblings, 2 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-15 15:30 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Changing event parsing to use flex/bison parse generator.
The event syntax stays as it is.

grammar description:

events: events ',' event | event

event:  event_tracepoint |
        event_raw |
        event_numeric |
        event_symbolic |
        event_generic_hw |
        event_breakpoint

event_tracepoint:       PE_NAME_TP ':' PE_NAME_TP modifier
event_raw:              PE_SEP_RAW PE_VALUE modifier
event_numeric:          PE_VALUE ':' PE_VALUE modifier
event_symbolic:         PE_NAME_SYM modifier
event_generic_hw:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier |
                        PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier |
                        PE_NAME_CACHE_TYPE modifier
event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
modifier:               PE_MODIFIER_EVENT | empty

PE_NAME_SYM:            cpu-cycles|cycles                              |
                        stalled-cycles-frontend|idle-cycles-frontend   |
                        stalled-cycles-backend|idle-cycles-backend     |
                        instructions                                   |
                        cache-references                               |
                        cache-misses                                   |
                        branch-instructions|branches                   |
                        branch-misses                                  |
                        bus-cycles                                     |
                        cpu-clock                                      |
                        task-clock                                     |
                        page-faults|faults                             |
                        minor-faults                                   |
                        major-faults                                   |
                        context-switches|cs                            |
                        cpu-migrations|migrations                      |
                        alignment-faults                               |
                        emulation-faults

PE_NAME_CACHE_TYPE:     L1-dcache|l1-d|l1d|L1-data             |
                        L1-icache|l1-i|l1i|L1-instruction      |
                        LLC|L2                                 |
                        dTLB|d-tlb|Data-TLB                    |
                        iTLB|i-tlb|Instruction-TLB             |
                        branch|branches|bpu|btb|bpc            |
                        node

PE_NAME_CACHE_OP_RESULT: load|loads|read                       |
                        store|stores|write                     |
                        prefetch|prefetches                    |
                        speculative-read|speculative-load      |
                        refs|Reference|ops|access              |
                        misses|miss

PE_SEP_RAW:             'r'
PE_SEP_BP:              'mem'
PE_MODIFIER_EVENT:      :[ukhp]{1,2}
PE_MODIFIER_BPTYPE:     :[rwx]{1,3}
PE_NAME_TP:             [a-zA-Z_*?]+
PE_VALUE:               number

Added flex/bison files for event grammar parsing. Added
flex/bison Makefile rules plus few special dependencies.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile                  |   21 ++
 tools/perf/util/parse-events-bison.y |  119 +++++++++
 tools/perf/util/parse-events-flex.l  |  111 ++++++++
 tools/perf/util/parse-events.c       |  459 +++++++++++-----------------------
 tools/perf/util/parse-events.h       |    9 +
 5 files changed, 411 insertions(+), 308 deletions(-)
 create mode 100644 tools/perf/util/parse-events-bison.y
 create mode 100644 tools/perf/util/parse-events-flex.l

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index ac86d67..ef6b621 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -47,6 +47,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
+FLEX = $(CROSS_COMPILE)flex
+BISON= $(CROSS_COMPILE)bison
 
 # Additional ARCH settings for x86
 ifeq ($(ARCH),i386)
@@ -341,6 +343,8 @@ LIB_OBJS += $(OUTPUT)util/session.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
+LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
+LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -627,6 +631,8 @@ ifndef V
 	QUIET_LINK     = @echo '   ' LINK $@;
 	QUIET_MKDIR    = @echo '   ' MKDIR $@;
 	QUIET_GEN      = @echo '   ' GEN $@;
+	QUIET_FLEX     = @echo '   ' FLEX $@;
+	QUIET_BISON    = @echo '   ' BISON $@;
 endif
 endif
 
@@ -713,6 +719,10 @@ $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
 $(OUTPUT)%.o: %.S
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+$(OUTPUT)%.c: %.l
+	$(QUIET_FLEX)$(FLEX) --header-file=$*.h -t $< > $@
+$(OUTPUT)%.c: %.y
+	$(QUIET_BISON)$(BISON) -v $< -d -o $@
 
 $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
@@ -739,6 +749,16 @@ $(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+
+.SECONDARY: util/parse-events-flex.c util/parse-events-flex.h
+.SECONDARY: util/parse-events-bison.c util/parse-events-bison.h
+
+util/parse-events.o: util/parse-events-flex.c
+util/parse-events-flex.c: util/parse-events-bison.c
+
+$(OUTPUT)util/parse-events-flex.o: util/parse-events-flex.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
@@ -910,6 +930,7 @@ clean:
 	$(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
 	$(RM) $(ALL_PROGRAMS) perf
 	$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
+	$(RM) util/parse-events-flex.[ch] util/parse-events-bison.[cho]*
 	$(MAKE) -C Documentation/ clean
 	$(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
 	$(python-clean)
diff --git a/tools/perf/util/parse-events-bison.y b/tools/perf/util/parse-events-bison.y
new file mode 100644
index 0000000..403cbf6
--- /dev/null
+++ b/tools/perf/util/parse-events-bison.y
@@ -0,0 +1,119 @@
+
+%name-prefix "parse_events_"
+
+%{
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+%}
+
+%token PE_VALUE
+%token PE_MODIFIER_BPTYPE PE_MODIFIER_EVENT
+%token PE_NAME_TP PE_NAME_SYM
+%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
+%token PE_SEP_RAW PE_SEP_BP
+%token PE_ERROR
+%type <l> PE_VALUE
+%type <s> PE_NAME_TP
+%type <s> PE_NAME_SYM
+%type <s> PE_NAME_CACHE_TYPE
+%type <s> PE_NAME_CACHE_OP_RESULT
+%type <s> PE_MODIFIER_EVENT
+%type <s> modifier
+%type <s> PE_MODIFIER_BPTYPE
+%type <s> event_breakpoint_type
+
+%union
+{
+	char *s;
+	long l;
+}
+
+%%
+
+events: events ',' event | event
+
+event:  event_tracepoint |
+	event_raw |
+	event_numeric |
+	event_symbolic |
+	event_generic_hw |
+	event_breakpoint
+
+event_tracepoint: PE_NAME_TP ':' PE_NAME_TP modifier
+{
+	ABORT_ON(parse_events_add_tracepoint($1, $3, $4));
+}
+
+event_raw: PE_SEP_RAW PE_VALUE modifier
+{
+	ABORT_ON(parse_events_add_raw($2, $3));
+}
+
+event_numeric: PE_VALUE ':' PE_VALUE modifier
+{
+	ABORT_ON(parse_events_add_numeric($1, $3, $4));
+}
+
+event_symbolic: PE_NAME_SYM modifier
+{
+	ABORT_ON(parse_events_add_symbolic($1, $2));
+}
+
+event_generic_hw:
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier
+{
+	ABORT_ON(parse_events_add_generic_hw($1, $3, $5, $6));
+}
+|
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier
+{
+	ABORT_ON(parse_events_add_generic_hw($1, $3, NULL, $4));
+}
+|
+PE_NAME_CACHE_TYPE modifier
+{
+	ABORT_ON(parse_events_add_generic_hw($1, NULL, NULL, $2));
+}
+
+event_breakpoint: PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
+{
+	ABORT_ON(parse_events_add_breakpoint((void *) $3, $4, $5))
+}
+
+event_breakpoint_type: PE_MODIFIER_BPTYPE
+{
+	$$ = $1
+}
+|
+{
+	$$ = NULL;
+}
+
+modifier: PE_MODIFIER_EVENT
+{
+	$$ = $1;
+}
+|
+{
+	$$ = NULL;
+}
+
+%%
+
+void parse_events_error(char const *msg __used)
+{
+}
diff --git a/tools/perf/util/parse-events-flex.l b/tools/perf/util/parse-events-flex.l
new file mode 100644
index 0000000..84b9b0e
--- /dev/null
+++ b/tools/perf/util/parse-events-flex.l
@@ -0,0 +1,111 @@
+
+%option prefix="parse_events_"
+
+%{
+#include <errno.h>
+#include "parse-events-bison.h"
+
+enum {
+	VALUE_DEC,
+	VALUE_HEX,
+};
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtol(parse_events_text, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.l = num;
+	return PE_VALUE;
+}
+
+static int __str(char *s, int token)
+{
+	parse_events_lval.s = strdup(s);
+	return token;
+}
+
+static int str(int token)
+{
+	return __str(parse_events_text, token);
+}
+
+static int mod(int token)
+{
+	return __str(parse_events_text + 1, token);
+}
+
+%}
+
+num_dec		[0-9]+
+num_hex		0x[a-fA-F0-9]+
+name_tp		[a-zA-Z_*?]+
+
+%x BP
+
+%%
+
+cpu-cycles|cycles				|
+stalled-cycles-frontend|idle-cycles-frontend	|
+stalled-cycles-backend|idle-cycles-backend	|
+instructions					|
+cache-references				|
+cache-misses					|
+branch-instructions|branches			|
+branch-misses					|
+bus-cycles					|
+cpu-clock					|
+task-clock					|
+page-faults|faults				|
+minor-faults					|
+major-faults					|
+context-switches|cs				|
+cpu-migrations|migrations			|
+alignment-faults				|
+emulation-faults				{ return str(PE_NAME_SYM); }
+
+L1-dcache|l1-d|l1d|L1-data		|
+L1-icache|l1-i|l1i|L1-instruction	|
+LLC|L2					|
+dTLB|d-tlb|Data-TLB			|
+iTLB|i-tlb|Instruction-TLB		|
+branch|branches|bpu|btb|bpc		|
+node					{ return str(PE_NAME_CACHE_TYPE); }
+
+load|loads|read				|
+store|stores|write			|
+prefetch|prefetches			|
+speculative-read|speculative-load	|
+refs|Reference|ops|access		|
+misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
+
+{num_dec}		{ return value(10); }
+{num_hex}		{ return value(16); }
+
+r			{ return PE_SEP_RAW; }
+
+mem			{ BEGIN(BP); return PE_SEP_BP; }
+<BP>:[rwx]{1,3}		{ return mod(PE_MODIFIER_BPTYPE); }
+<BP>:[ukhp]{1,2}	{ return mod(PE_MODIFIER_EVENT); }
+<BP>:			{ return ':'; }
+<BP>{num_dec}		{ return value(10); }
+<BP>{num_hex}		{ return value(16); }
+<BP><<EOF>>		{ BEGIN(INITIAL); }
+<BP>.			{ BEGIN(INITIAL); }
+
+:[ukhp]{1,2}		{ return mod(PE_MODIFIER_EVENT); }
+{name_tp}		{ return str(PE_NAME_TP); }
+-			{ return '-'; }
+,			{ return ','; }
+:			{ return ':'; }
+
+%%
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 586ab3f..b9c4189 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,9 @@
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
+#include "parse-events-flex.h"
+
+#define MAX_NAME_LEN 100
 
 struct event_symbol {
 	u8		type;
@@ -19,11 +22,9 @@ struct event_symbol {
 	const char	*alias;
 };
 
-enum event_result {
-	EVT_FAILED,
-	EVT_HANDLED,
-	EVT_HANDLED_ALL
-};
+int parse_events_parse(void);
+
+static struct perf_evlist *__evlist;
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -352,7 +353,31 @@ const char *__event_name(int type, u64 config)
 	return "unknown";
 }
 
-static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
+static void
+parse_event_modifier(char *mod, struct perf_event_attr *attr);
+
+static int add_event(struct perf_event_attr *attr, char *name, char *mod)
+{
+	struct perf_evsel *evsel;
+	int len = strlen(name);
+
+	parse_event_modifier(mod, attr);
+
+	evsel = perf_evsel__new(attr, __evlist->nr_entries);
+	if (!evsel)
+		return -ENOMEM;
+
+	perf_evlist__add(__evlist, evsel);
+
+	evsel->name = zalloc(len);
+	if (!evsel->name)
+		return -ENOMEM;
+
+	strncpy(evsel->name, name, len);
+	return 0;
+}
+
+static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
 {
 	int i, j;
 	int n, longest = -1;
@@ -360,58 +385,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
 	for (i = 0; i < size; i++) {
 		for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
 			n = strlen(names[i][j]);
-			if (n > longest && !strncasecmp(*str, names[i][j], n))
+			if (n > longest && !strncasecmp(str, names[i][j], n))
 				longest = n;
 		}
-		if (longest > 0) {
-			*str += longest;
+		if (longest > 0)
 			return i;
-		}
 	}
 
 	return -1;
 }
 
-static enum event_result
-parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
+int parse_events_add_generic_hw(char *type, char *op_result1, char *op_result2,
+				char *mod)
 {
-	const char *s = *str;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	int cache_type = -1, cache_op = -1, cache_result = -1;
+	char *op_result[2] = { op_result1, op_result2 };
+	int i, n;
 
-	cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
 	/*
 	 * No fallback - if we cannot get a clear cache type
 	 * then bail out:
 	 */
+	cache_type = parse_aliases(type, hw_cache,
+				   PERF_COUNT_HW_CACHE_MAX);
 	if (cache_type == -1)
-		return EVT_FAILED;
+		return -EINVAL;
 
-	while ((cache_op == -1 || cache_result == -1) && *s == '-') {
-		++s;
+	n = snprintf(name, MAX_NAME_LEN, "%s", type);
+
+	for (i = 0; (i < 2) && (op_result[i]); i++) {
+		char *str = op_result[i];
+
+		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
 		if (cache_op == -1) {
-			cache_op = parse_aliases(&s, hw_cache_op,
-						PERF_COUNT_HW_CACHE_OP_MAX);
+			cache_op = parse_aliases(str, hw_cache_op,
+						 PERF_COUNT_HW_CACHE_OP_MAX);
 			if (cache_op >= 0) {
 				if (!is_cache_op_valid(cache_type, cache_op))
-					return EVT_FAILED;
+					return -EINVAL;
 				continue;
 			}
 		}
 
 		if (cache_result == -1) {
-			cache_result = parse_aliases(&s, hw_cache_result,
+			cache_result = parse_aliases(str, hw_cache_result,
 						PERF_COUNT_HW_CACHE_RESULT_MAX);
 			if (cache_result >= 0)
 				continue;
 		}
-
-		/*
-		 * Can't parse this as a cache op or result, so back up
-		 * to the '-'.
-		 */
-		--s;
-		break;
 	}
 
 	/*
@@ -426,20 +450,16 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
 	if (cache_result == -1)
 		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
 
-	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
-	attr->type = PERF_TYPE_HW_CACHE;
-
-	*str = s;
-	return EVT_HANDLED;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
+	attr.type = PERF_TYPE_HW_CACHE;
+	return add_event(&attr, name, mod);
 }
 
-static enum event_result
-parse_single_tracepoint_event(char *sys_name,
-			      const char *evt_name,
-			      unsigned int evt_length,
-			      struct perf_event_attr *attr,
-			      const char **strp)
+static int add_tracepoint(char *sys_name, char *evt_name, char *mod)
 {
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	char evt_path[MAXPATHLEN];
 	char id_buf[4];
 	u64 id;
@@ -450,130 +470,78 @@ parse_single_tracepoint_event(char *sys_name,
 
 	fd = open(evt_path, O_RDONLY);
 	if (fd < 0)
-		return EVT_FAILED;
+		return -1;
 
 	if (read(fd, id_buf, sizeof(id_buf)) < 0) {
 		close(fd);
-		return EVT_FAILED;
+		return -1;
 	}
 
 	close(fd);
 	id = atoll(id_buf);
-	attr->config = id;
-	attr->type = PERF_TYPE_TRACEPOINT;
-	*strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
-
-	attr->sample_type |= PERF_SAMPLE_RAW;
-	attr->sample_type |= PERF_SAMPLE_TIME;
-	attr->sample_type |= PERF_SAMPLE_CPU;
 
-	attr->sample_period = 1;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = id;
+	attr.type = PERF_TYPE_TRACEPOINT;
+	attr.sample_type |= PERF_SAMPLE_RAW;
+	attr.sample_type |= PERF_SAMPLE_TIME;
+	attr.sample_type |= PERF_SAMPLE_CPU;
+	attr.sample_period = 1;
 
-
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
+	return add_event(&attr, name, mod);
 }
 
-/* sys + ':' + event + ':' + flags*/
-#define MAX_EVOPT_LEN	(MAX_EVENT_LENGTH * 2 + 2 + 128)
-static enum event_result
-parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
-				const char *evt_exp, char *flags)
+static int add_tracepoint_multi(char *sys_name, char *evt_name, char *mod)
 {
 	char evt_path[MAXPATHLEN];
 	struct dirent *evt_ent;
 	DIR *evt_dir;
+	int ret = 0;
 
 	snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
 	evt_dir = opendir(evt_path);
-
 	if (!evt_dir) {
 		perror("Can't open event dir");
-		return EVT_FAILED;
+		return -1;
 	}
 
-	while ((evt_ent = readdir(evt_dir))) {
-		char event_opt[MAX_EVOPT_LEN + 1];
-		int len;
-
+	while (!ret && (evt_ent = readdir(evt_dir))) {
 		if (!strcmp(evt_ent->d_name, ".")
 		    || !strcmp(evt_ent->d_name, "..")
 		    || !strcmp(evt_ent->d_name, "enable")
 		    || !strcmp(evt_ent->d_name, "filter"))
 			continue;
 
-		if (!strglobmatch(evt_ent->d_name, evt_exp))
+		if (!strglobmatch(evt_ent->d_name, evt_name))
 			continue;
 
-		len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
-			       evt_ent->d_name, flags ? ":" : "",
-			       flags ?: "");
-		if (len < 0)
-			return EVT_FAILED;
-
-		if (parse_events(evlist, event_opt, 0))
-			return EVT_FAILED;
+		ret = add_tracepoint(sys_name, evt_ent->d_name, mod);
 	}
 
-	return EVT_HANDLED_ALL;
+	return ret;
 }
 
-static enum event_result
-parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
-		       struct perf_event_attr *attr)
+int parse_events_add_tracepoint(char *sys, char *event, char *mod)
 {
-	const char *evt_name;
-	char *flags = NULL, *comma_loc;
-	char sys_name[MAX_EVENT_LENGTH];
-	unsigned int sys_length, evt_length;
-
-	if (debugfs_valid_mountpoint(tracing_events_path))
-		return 0;
+	int ret;
 
-	evt_name = strchr(*strp, ':');
-	if (!evt_name)
-		return EVT_FAILED;
-
-	sys_length = evt_name - *strp;
-	if (sys_length >= MAX_EVENT_LENGTH)
-		return 0;
+	ret = debugfs_valid_mountpoint(tracing_events_path);
+	if (ret)
+		return ret;
 
-	strncpy(sys_name, *strp, sys_length);
-	sys_name[sys_length] = '\0';
-	evt_name = evt_name + 1;
-
-	comma_loc = strchr(evt_name, ',');
-	if (comma_loc) {
-		/* take the event name up to the comma */
-		evt_name = strndup(evt_name, comma_loc - evt_name);
-	}
-	flags = strchr(evt_name, ':');
-	if (flags) {
-		/* split it out: */
-		evt_name = strndup(evt_name, flags - evt_name);
-		flags++;
-	}
-
-	evt_length = strlen(evt_name);
-	if (evt_length >= MAX_EVENT_LENGTH)
-		return EVT_FAILED;
-	if (strpbrk(evt_name, "*?")) {
-		*strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
-		return parse_multiple_tracepoint_event(evlist, sys_name,
-						       evt_name, flags);
-	} else {
-		return parse_single_tracepoint_event(sys_name, evt_name,
-						     evt_length, attr, strp);
-	}
+	return strpbrk(event, "*?") ?
+	       add_tracepoint_multi(sys, event, mod) :
+	       add_tracepoint(sys, event, mod);
 }
 
-static enum event_result
-parse_breakpoint_type(const char *type, const char **strp,
-		      struct perf_event_attr *attr)
+static int
+parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
 	int i;
 
 	for (i = 0; i < 3; i++) {
-		if (!type[i])
+		if (!type || !type[i])
 			break;
 
 		switch (type[i]) {
@@ -587,65 +555,40 @@ parse_breakpoint_type(const char *type, const char **strp,
 			attr->bp_type |= HW_BREAKPOINT_X;
 			break;
 		default:
-			return EVT_FAILED;
+			return -EINVAL;
 		}
 	}
+
 	if (!attr->bp_type) /* Default */
 		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
 
-	*strp = type + i;
-
-	return EVT_HANDLED;
+	return 0;
 }
 
-static enum event_result
-parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_breakpoint(void *ptr, char *type, char *mod)
 {
-	const char *target;
-	const char *type;
-	char *endaddr;
-	u64 addr;
-	enum event_result err;
-
-	target = strchr(*strp, ':');
-	if (!target)
-		return EVT_FAILED;
-
-	if (strncmp(*strp, "mem", target - *strp) != 0)
-		return EVT_FAILED;
-
-	target++;
-
-	addr = strtoull(target, &endaddr, 0);
-	if (target == endaddr)
-		return EVT_FAILED;
-
-	attr->bp_addr = addr;
-	*strp = endaddr;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 
-	type = strchr(target, ':');
+	memset(&attr, 0, sizeof(attr));
+	attr.bp_addr = (u64) ptr;
 
-	/* If no type is defined, just rw as default */
-	if (!type) {
-		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
-	} else {
-		err = parse_breakpoint_type(++type, strp, attr);
-		if (err == EVT_FAILED)
-			return EVT_FAILED;
-	}
+	if (parse_breakpoint_type(type, &attr))
+		return -EINVAL;
 
 	/*
 	 * We should find a nice way to override the access length
 	 * Provide some defaults for now
 	 */
-	if (attr->bp_type == HW_BREAKPOINT_X)
-		attr->bp_len = sizeof(long);
+	if (attr.bp_type == HW_BREAKPOINT_X)
+		attr.bp_len = sizeof(long);
 	else
-		attr->bp_len = HW_BREAKPOINT_LEN_4;
+		attr.bp_len = HW_BREAKPOINT_LEN_4;
 
-	attr->type = PERF_TYPE_BREAKPOINT;
+	attr.type = PERF_TYPE_BREAKPOINT;
 
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
+	return add_event(&attr, name, mod);
 }
 
 static int check_events(const char *str, unsigned int i)
@@ -665,85 +608,59 @@ static int check_events(const char *str, unsigned int i)
 	return 0;
 }
 
-static enum event_result
-parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_symbolic(char *symbol, char *mod)
 {
-	const char *str = *strp;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	unsigned int i;
-	int n;
 
 	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-		n = check_events(str, i);
-		if (n > 0) {
-			attr->type = event_symbols[i].type;
-			attr->config = event_symbols[i].config;
-			*strp = str + n;
-			return EVT_HANDLED;
-		}
+		if (!check_events(symbol, i))
+			continue;
+		memset(&attr, 0, sizeof(attr));
+		attr.type = event_symbols[i].type;
+		attr.config = event_symbols[i].config;
+		snprintf(name, MAX_NAME_LEN, "%s", event_symbols[i].symbol);
+		return add_event(&attr, name, mod);
 	}
-	return EVT_FAILED;
+
+	return -EINVAL;
 }
 
-static enum event_result
-parse_raw_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_raw(long code, char *mod)
 {
-	const char *str = *strp;
-	u64 config;
-	int n;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 
-	if (*str != 'r')
-		return EVT_FAILED;
-	n = hex2u64(str + 1, &config);
-	if (n > 0) {
-		const char *end = str + n + 1;
-		if (*end != '\0' && *end != ',' && *end != ':')
-			return EVT_FAILED;
-
-		*strp = end;
-		attr->type = PERF_TYPE_RAW;
-		attr->config = config;
-		return EVT_HANDLED;
-	}
-	return EVT_FAILED;
+	memset(&attr, 0, sizeof(attr));
+	attr.type = PERF_TYPE_RAW;
+	attr.config = code;
+
+	snprintf(name, MAX_NAME_LEN, "r%lx", code);
+	return add_event(&attr, name, mod);
 }
 
-static enum event_result
-parse_numeric_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_numeric(long type, long config, char *mod)
 {
-	const char *str = *strp;
-	char *endp;
-	unsigned long type;
-	u64 config;
-
-	type = strtoul(str, &endp, 0);
-	if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
-		str = endp + 1;
-		config = strtoul(str, &endp, 0);
-		if (endp > str) {
-			attr->type = type;
-			attr->config = config;
-			*strp = endp;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
+
+	memset(&attr, 0, sizeof(attr));
+	attr.type = type;
+	attr.config = config;
+
+	snprintf(name, MAX_NAME_LEN, "%lx:%lx", type, config);
+	return add_event(&attr, name, mod);
 }
 
-static int
-parse_event_modifier(const char **strp, struct perf_event_attr *attr)
+static void
+parse_event_modifier(char *str, struct perf_event_attr *attr)
 {
-	const char *str = *strp;
 	int exclude = 0;
 	int eu = 0, ek = 0, eh = 0, precise = 0;
 
-	if (!*str)
-		return 0;
-
-	if (*str == ',')
-		return 0;
-
-	if (*str++ != ':')
-		return -1;
+	if (str == NULL)
+		return;
 
 	while (*str) {
 		if (*str == 'u') {
@@ -765,108 +682,36 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
 
 		++str;
 	}
-	if (str < *strp + 2)
-		return -1;
-
-	*strp = str;
 
 	attr->exclude_user   = eu;
 	attr->exclude_kernel = ek;
 	attr->exclude_hv     = eh;
 	attr->precise_ip     = precise;
-
-	return 0;
+	return;
 }
 
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static enum event_result
-parse_event_symbols(struct perf_evlist *evlist, const char **str,
-		    struct perf_event_attr *attr)
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
-	enum event_result ret;
-
-	ret = parse_tracepoint_event(evlist, str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
-
-	ret = parse_raw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	YY_BUFFER_STATE buffer;
+	int ret;
 
-	ret = parse_numeric_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	__evlist = evlist;
 
-	ret = parse_symbolic_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	buffer = parse_events__scan_string(str);
 
-	ret = parse_generic_hw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	ret = parse_events_parse();
 
-	ret = parse_breakpoint_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	parse_events__flush_buffer(buffer);
+	parse_events__delete_buffer(buffer);
 
-	fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
-	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
-	return EVT_FAILED;
-
-modifier:
-	if (parse_event_modifier(str, attr) < 0) {
-		fprintf(stderr, "invalid event modifier: '%s'\n", *str);
-		fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
-
-		return EVT_FAILED;
+	if (ret) {
+		fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
+		fprintf(stderr, "Run 'perf list' for a list of valid events\n");
 	}
 
 	return ret;
 }
 
-int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
-{
-	struct perf_event_attr attr;
-	enum event_result ret;
-	const char *ostr;
-
-	for (;;) {
-		ostr = str;
-		memset(&attr, 0, sizeof(attr));
-		ret = parse_event_symbols(evlist, &str, &attr);
-		if (ret == EVT_FAILED)
-			return -1;
-
-		if (!(*str == 0 || *str == ',' || isspace(*str)))
-			return -1;
-
-		if (ret != EVT_HANDLED_ALL) {
-			struct perf_evsel *evsel;
-			evsel = perf_evsel__new(&attr, evlist->nr_entries);
-			if (evsel == NULL)
-				return -1;
-			perf_evlist__add(evlist, evsel);
-
-			evsel->name = calloc(str - ostr + 1, 1);
-			if (!evsel->name)
-				return -1;
-			strncpy(evsel->name, ostr, str - ostr);
-		}
-
-		if (*str == 0)
-			break;
-		if (*str == ',')
-			++str;
-		while (isspace(*str))
-			++str;
-	}
-
-	return 0;
-}
-
 int parse_events_option(const struct option *opt, const char *str,
 			int unset __used)
 {
@@ -1039,8 +884,6 @@ int print_hwcache_events(const char *event_glob)
 	return printed;
 }
 
-#define MAX_NAME_LEN 100
-
 /*
  * Print the help text for the event symbols:
  */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7e0cbe7..fa3ac7f 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,15 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
 
+int parse_events_add_tracepoint(char *sys, char *event, char *mod);
+int parse_events_add_raw(long code, char *mod);
+int parse_events_add_numeric(long type, long config, char *mod);
+int parse_events_add_symbolic(char *symbol, char *mod);
+int parse_events_add_generic_hw(char *type, char *op_result1, char *op_result2,
+				char *mod);
+int parse_events_add_breakpoint(void *ptr, char *type, char *mod);
+void parse_events_error(char const *msg);
+
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
 void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
-- 
1.7.4


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

* [PATCH 2/3] perf, tool: Add new event group management
  2011-12-15 15:30 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
  2011-12-15 15:30 ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Jiri Olsa
@ 2011-12-15 15:30 ` Jiri Olsa
  2011-12-20 17:47   ` Arnaldo Carvalho de Melo
  2011-12-15 15:30 ` [PATCH 3/3] perf, tool: Add more automated tests for event parsing Jiri Olsa
  2 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2011-12-15 15:30 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

The current event grouping is basic. If you specify the '--group'
option for record/stat/top command, all the specified events become
members of a single group with the first event as a group leader.

This patch adds a functionality that allows to create event groups
based on the way they are specified on the command line. Extending
the '--group/-g' option power while preserving the current behaviour.

It is now possible to use '--group/-g' option with 'parsed' value,
which will create groups based on the command line events layout.

With the '--group/-g parsed' option specified, all events separated
by ',' within a single '-e' option now become members of a group with
the first event specified as a group leader. Another '-e' option with
multiple events creates separate group.

All groups are created with regards to threads and cpus. Thus
recording an event group within a 2 threads on server with
4 CPUs will create 8 separate groups.

Examples (first event in brackets is group leader):

  # 1 group (cpu-clock,task-clock)
  perf record --group -e cpu-clock,task-clock ls
  perf record --group parsed -e cpu-clock,task-clock ls

  # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
  perf record --group parsed -e cpu-clock,task-clock \
   -e minor-faults,major-faults ls

  # 1 group (cpu-clock,task-clock,minor-faults,major-faults)
  perf record --group -e cpu-clock,task-clock \
   -e minor-faults,major-faults ls

  # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
  perf record --group parsed -e cpu-clock,task-clock \
   -e minor-faults,major-faults -e instructions ls

  # 1 group (cpu-clock,task-clock,minor-faults,major-faults,instructions)
  perf record --group -e cpu-clock,task-clock \
   -e minor-faults,major-faults -e instructions ls

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile            |    2 ++
 tools/perf/builtin-record.c    |    8 +++++---
 tools/perf/builtin-stat.c      |   10 ++++++----
 tools/perf/builtin-top.c       |    8 +++++---
 tools/perf/perf.h              |    2 +-
 tools/perf/util/evsel.c        |   28 ++++++++++++++++++++++------
 tools/perf/util/evsel.h        |    9 +++++----
 tools/perf/util/group.c        |   23 +++++++++++++++++++++++
 tools/perf/util/group.h        |   25 +++++++++++++++++++++++++
 tools/perf/util/parse-events.c |    6 ++++++
 tools/perf/util/python.c       |    4 ++++
 tools/perf/util/top.h          |    2 +-
 12 files changed, 105 insertions(+), 22 deletions(-)
 create mode 100644 tools/perf/util/group.c
 create mode 100644 tools/perf/util/group.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index ef6b621..c54b595 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -299,6 +299,7 @@ LIB_H += util/cpumap.h
 LIB_H += util/top.h
 LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
+LIB_H += util/group.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -356,6 +357,7 @@ LIB_OBJS += $(OUTPUT)util/util.o
 LIB_OBJS += $(OUTPUT)util/xyarray.o
 LIB_OBJS += $(OUTPUT)util/cpumap.o
 LIB_OBJS += $(OUTPUT)util/cgroup.o
+LIB_OBJS += $(OUTPUT)util/group.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 766fa0a..581c72d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -26,6 +26,7 @@
 #include "util/symbol.h"
 #include "util/cpumap.h"
 #include "util/thread_map.h"
+#include "util/group.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -202,7 +203,7 @@ static void perf_record__open(struct perf_record *rec)
 		 */
 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
 
-		if (opts->group && pos != first)
+		if (group_is_single(opts->group) && pos != first)
 			group_fd = first->fd;
 retry_sample_id:
 		attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
@@ -688,8 +689,9 @@ const struct option record_options[] = {
 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
 		     "number of mmap data pages"),
-	OPT_BOOLEAN(0, "group", &record.opts.group,
-		    "put the counters into a counter group"),
+	OPT_CALLBACK_DEFAULT(0, "group", &record.opts.group, "[parsed]",
+		     "put the counters into a counter group",
+		     parse_group, PERF_GROUP_NONE),
 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
 		    "do call-graph (stack chain/backtrace) recording"),
 	OPT_INCR('v', "verbose", &verbose,
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index cc53de3..c28c852 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -55,6 +55,7 @@
 #include "util/cpumap.h"
 #include "util/thread.h"
 #include "util/thread_map.h"
+#include "util/group.h"
 
 #include <sys/prctl.h>
 #include <math.h>
@@ -193,7 +194,7 @@ static int			big_num_opt			=  -1;
 static const char		*cpu_list;
 static const char		*csv_sep			= NULL;
 static bool			csv_output			= false;
-static bool			group				= false;
+static int			group;
 static const char		*output_name			= NULL;
 static FILE			*output				= NULL;
 static int			output_fd;
@@ -284,7 +285,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
 	struct perf_event_attr *attr = &evsel->attr;
 	struct xyarray *group_fd = NULL;
 
-	if (group && evsel != first)
+	if (group_is_single(group) && evsel != first)
 		group_fd = first->fd;
 
 	if (scale)
@@ -1068,8 +1069,9 @@ static const struct option options[] = {
 		    "stat events on existing thread id"),
 	OPT_BOOLEAN('a', "all-cpus", &system_wide,
 		    "system-wide collection from all CPUs"),
-	OPT_BOOLEAN('g', "group", &group,
-		    "put the counters into a counter group"),
+	OPT_CALLBACK_DEFAULT('g', "group", &group, "[parsed]",
+		    "put the counters into a counter group",
+		    parse_group, PERF_GROUP_NONE),
 	OPT_BOOLEAN('c', "scale", &scale,
 		    "scale/normalize counters"),
 	OPT_INCR('v', "verbose", &verbose,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c3836b9..c1f205c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -38,6 +38,7 @@
 #include "util/cpumap.h"
 #include "util/xyarray.h"
 #include "util/sort.h"
+#include "util/group.h"
 
 #include "util/debug.h"
 
@@ -830,7 +831,7 @@ static void perf_top__start_counters(struct perf_top *top)
 		struct perf_event_attr *attr = &counter->attr;
 		struct xyarray *group_fd = NULL;
 
-		if (top->group && counter != first)
+		if (group_is_single(top->group) && counter != first)
 			group_fd = first->fd;
 
 		attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
@@ -1120,8 +1121,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
 			    "dump the symbol table used for profiling"),
 	OPT_INTEGER('f', "count-filter", &top.count_filter,
 		    "only display functions with more events than this"),
-	OPT_BOOLEAN('g', "group", &top.group,
-			    "put the counters into a counter group"),
+	OPT_CALLBACK_DEFAULT('g', "group", &top.group, "[parsed]",
+		    "put the counters into a counter group",
+		    parse_group, PERF_GROUP_NONE),
 	OPT_BOOLEAN('i', "inherit", &top.inherit,
 		    "child tasks inherit counters"),
 	OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index ea804f5..b2aa37a 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -189,7 +189,7 @@ struct perf_record_opts {
 	pid_t	     target_pid;
 	pid_t	     target_tid;
 	bool	     call_graph;
-	bool	     group;
+	int	     group;
 	bool	     inherit_stat;
 	bool	     no_delay;
 	bool	     no_inherit;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 4a8c8b0..280286a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -14,6 +14,7 @@
 #include "util.h"
 #include "cpumap.h"
 #include "thread_map.h"
+#include "group.h"
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@@ -284,8 +285,17 @@ int __perf_evsel__read(struct perf_evsel *evsel,
 	return 0;
 }
 
+static int perf_evsel_group(struct perf_evsel *evsel,
+			    int cpu, int thread)
+{
+	if (evsel->group_leader)
+		return FD(evsel->group_leader, cpu, thread);
+
+	return -1;
+}
+
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-			      struct thread_map *threads, bool group,
+			      struct thread_map *threads, int group,
 			      struct xyarray *group_fds)
 {
 	int cpu, thread;
@@ -302,13 +312,19 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 	}
 
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
-		int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
+		int group_fd = -1;
+
+		if (group_is_single(group))
+			group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
 
 		for (thread = 0; thread < threads->nr; thread++) {
 
 			if (!evsel->cgrp)
 				pid = threads->map[thread];
 
+			if (group_is_parsed(group))
+				group_fd = perf_evsel_group(evsel, cpu, thread);
+
 			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
 								     pid,
 								     cpus->map[cpu],
@@ -318,7 +334,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 				goto out_close;
 			}
 
-			if (group && group_fd == -1)
+			if (group_is_single(group) && group_fd == -1)
 				group_fd = FD(evsel, cpu, thread);
 		}
 	}
@@ -363,7 +379,7 @@ static struct {
 };
 
 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-		     struct thread_map *threads, bool group,
+		     struct thread_map *threads, int group,
 		     struct xyarray *group_fd)
 {
 	if (cpus == NULL) {
@@ -378,7 +394,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 }
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
-			     struct cpu_map *cpus, bool group,
+			     struct cpu_map *cpus, int group,
 			     struct xyarray *group_fd)
 {
 	return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
@@ -386,7 +402,7 @@ int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
 }
 
 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
-				struct thread_map *threads, bool group,
+				struct thread_map *threads, int group,
 				struct xyarray *group_fd)
 {
 	return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 326b8e4..db9ee0b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -66,6 +66,7 @@ struct perf_evsel {
 		void		*data;
 	} handler;
 	bool 			supported;
+	struct perf_evsel	*group_leader;
 };
 
 struct cpu_map;
@@ -90,14 +91,14 @@ void perf_evsel__free_id(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
-			     struct cpu_map *cpus, bool group,
+			     struct cpu_map *cpus, int group,
 			     struct xyarray *group_fds);
 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
-				struct thread_map *threads, bool group,
+				struct thread_map *threads, int group,
 				struct xyarray *group_fds);
 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-		     struct thread_map *threads, bool group,
-		     struct xyarray *group_fds);
+		     struct thread_map *threads, int group,
+		     struct xyarray *group_fd);
 void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
 
 #define perf_evsel__match(evsel, t, c)		\
diff --git a/tools/perf/util/group.c b/tools/perf/util/group.c
new file mode 100644
index 0000000..89468a9
--- /dev/null
+++ b/tools/perf/util/group.c
@@ -0,0 +1,23 @@
+
+#include <linux/compiler.h>
+#include "types.h"
+#include "util.h"
+#include "parse-options.h"
+#include "group.h"
+
+int parse_group(const struct option *opt, const char *str,
+		int unset __used)
+{
+	int *group_opt = (int *) opt->value;
+
+	if (!str)
+		*group_opt = PERF_GROUP_SINGLE;
+	else if (!strcmp(str, "parsed"))
+		*group_opt = PERF_GROUP_PARSED;
+	else {
+		fprintf(stderr, "unknown group option value\n");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/tools/perf/util/group.h b/tools/perf/util/group.h
new file mode 100644
index 0000000..ad80015
--- /dev/null
+++ b/tools/perf/util/group.h
@@ -0,0 +1,25 @@
+#ifndef __GROUP_H__
+#define __GROUP_H__
+
+struct option;
+
+enum perf_group_opt {
+	PERF_GROUP_NONE,
+	PERF_GROUP_SINGLE,
+	PERF_GROUP_PARSED
+};
+
+int parse_group(const struct option *opt, const char *str,
+		int unset);
+
+static inline bool group_is_single(int group)
+{
+	return group == PERF_GROUP_SINGLE;
+}
+
+static inline bool group_is_parsed(int group)
+{
+	return group == PERF_GROUP_PARSED;
+}
+
+#endif /* __GROUP_H__ */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b9c4189..b7913c3 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -25,6 +25,7 @@ struct event_symbol {
 int parse_events_parse(void);
 
 static struct perf_evlist *__evlist;
+static struct perf_evsel *group_leader;
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -373,6 +374,10 @@ static int add_event(struct perf_event_attr *attr, char *name, char *mod)
 	if (!evsel->name)
 		return -ENOMEM;
 
+	evsel->group_leader = group_leader;
+	if (!group_leader)
+		group_leader = evsel;
+
 	strncpy(evsel->name, name, len);
 	return 0;
 }
@@ -696,6 +701,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 	int ret;
 
 	__evlist = evlist;
+	group_leader = NULL;
 
 	buffer = parse_events__scan_string(str);
 
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9dd47a4..b91a43b 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -7,6 +7,7 @@
 #include "event.h"
 #include "cpumap.h"
 #include "thread_map.h"
+#include "group.h"
 
 /* Define PyVarObject_HEAD_INIT for python 2.5 */
 #ifndef PyVarObject_HEAD_INIT
@@ -828,6 +829,9 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
 		return NULL;
 
+	if (group)
+		group = PERF_GROUP_SINGLE;
+
 	if (perf_evlist__open(evlist, group) < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index a248f3c..f545bc6 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -32,7 +32,7 @@ struct perf_top {
 	bool		   kptr_restrict_warned;
 	bool		   vmlinux_warned;
 	bool		   inherit;
-	bool		   group;
+	int		   group;
 	bool		   sample_id_all_avail;
 	bool		   dump_symtab;
 	const char	   *cpu_list;
-- 
1.7.4


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

* [PATCH 3/3] perf, tool: Add more automated tests for event parsing
  2011-12-15 15:30 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
  2011-12-15 15:30 ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Jiri Olsa
  2011-12-15 15:30 ` [PATCH 2/3] perf, tool: Add new event group management Jiri Olsa
@ 2011-12-15 15:30 ` Jiri Olsa
  2011-12-20 17:38   ` Arnaldo Carvalho de Melo
  2011-12-21  8:47   ` [tip:perf/core] perf test: " tip-bot for Jiri Olsa
  2 siblings, 2 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-15 15:30 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding automated tests for event parsing to include testing
for modifier, ',' operator and group_leader.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c |  245 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 244 insertions(+), 1 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 6173f78..0cdb4c9 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -603,7 +603,7 @@ out_free_threads:
 
 #define TEST_ASSERT_VAL(text, cond) \
 do { \
-	if (!cond) { \
+	if (!(cond)) { \
 		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
 		return -1; \
 	} \
@@ -759,6 +759,201 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
 	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_list(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+	struct perf_evsel *group_leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* r1 */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	group_leader = evsel;
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == 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);
+	TEST_ASSERT_VAL("wrong group_leader", !evsel->group_leader);
+
+	/* 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);
+	TEST_ASSERT_VAL("wrong group_leader",
+			evsel->group_leader == group_leader);
+
+	/* 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);
+	TEST_ASSERT_VAL("wrong group_leader",
+			evsel->group_leader == group_leader);
+
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -808,6 +1003,54 @@ static struct test__event_st {
 		.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  = "r1: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  = "r1,syscalls:sys_enter_open:k,1:1:hp",
+		.check = test__checkevent_list,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
-- 
1.7.4


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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-15 15:30 ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Jiri Olsa
@ 2011-12-16 14:02   ` Peter Zijlstra
  2011-12-16 14:03     ` Peter Zijlstra
                       ` (2 more replies)
  2011-12-20 17:37   ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Arnaldo Carvalho de Melo
  1 sibling, 3 replies; 91+ messages in thread
From: Peter Zijlstra @ 2011-12-16 14:02 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Thu, 2011-12-15 at 16:30 +0100, Jiri Olsa wrote:
> events: events ',' event | event
> 
> event:  event_tracepoint |
>         event_raw |
>         event_numeric |
>         event_symbolic |
>         event_generic_hw |
>         event_breakpoint
> 
> event_tracepoint:       PE_NAME_TP ':' PE_NAME_TP modifier
> event_raw:              PE_SEP_RAW PE_VALUE modifier
> event_numeric:          PE_VALUE ':' PE_VALUE modifier
> event_symbolic:         PE_NAME_SYM modifier
> event_generic_hw:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier |
>                         PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier |
>                         PE_NAME_CACHE_TYPE modifier
> event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
> event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
> modifier:               PE_MODIFIER_EVENT | empty

This isn't complete, we need means of specifying
perf_event_attr::config[12] when specifying a raw event.


> PE_NAME_SYM:            cpu-cycles|cycles                              |
>                         stalled-cycles-frontend|idle-cycles-frontend   |
>                         stalled-cycles-backend|idle-cycles-backend     |
>                         instructions                                   |
>                         cache-references                               |
>                         cache-misses                                   |
>                         branch-instructions|branches                   |
>                         branch-misses                                  |
>                         bus-cycles                                     |
>                         cpu-clock                                      |
>                         task-clock                                     |
>                         page-faults|faults                             |
>                         minor-faults                                   |
>                         major-faults                                   |
>                         context-switches|cs                            |
>                         cpu-migrations|migrations                      |
>                         alignment-faults                               |
>                         emulation-faults

It might make sense to allow means of custom symbol -> raw mappings.

> PE_NAME_CACHE_TYPE:     L1-dcache|l1-d|l1d|L1-data             |
>                         L1-icache|l1-i|l1i|L1-instruction      |
>                         LLC|L2                                 |
>                         dTLB|d-tlb|Data-TLB                    |
>                         iTLB|i-tlb|Instruction-TLB             |
>                         branch|branches|bpu|btb|bpc            |
>                         node
> 
> PE_NAME_CACHE_OP_RESULT: load|loads|read                       |
>                         store|stores|write                     |
>                         prefetch|prefetches                    |
>                         speculative-read|speculative-load      |
>                         refs|Reference|ops|access              |
>                         misses|miss
> 
> PE_SEP_RAW:             'r'
> PE_SEP_BP:              'mem'
> PE_MODIFIER_EVENT:      :[ukhp]{1,2}

You can actually have more than 2 modifiers, eg. "upp". 

[u] | [k] | [h] | [p]{,3} would be more correct I think.

> PE_MODIFIER_BPTYPE:     :[rwx]{1,3}
> PE_NAME_TP:             [a-zA-Z_*?]+
> PE_VALUE:               number
> 
> Added flex/bison files for event grammar parsing. Added
> flex/bison Makefile rules plus few special dependencies. 

It might be good to include the .c output of flex/bison so that we can
build perf without a hard dependency on them -- only people changing the
parser will need them.

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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-16 14:02   ` Peter Zijlstra
@ 2011-12-16 14:03     ` Peter Zijlstra
  2011-12-20 10:31       ` Jiri Olsa
  2011-12-19 14:37     ` Jiri Olsa
  2011-12-20 10:29     ` [PATCHv2 0/2] perf tool: " Jiri Olsa
  2 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2011-12-16 14:03 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Fri, 2011-12-16 at 15:02 +0100, Peter Zijlstra wrote:
> > event_tracepoint:       PE_NAME_TP ':' PE_NAME_TP modifier
> > event_raw:              PE_SEP_RAW PE_VALUE modifier
> > event_numeric:          PE_VALUE ':' PE_VALUE modifier
> > event_symbolic:         PE_NAME_SYM modifier
> > event_generic_hw:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier |
> >                         PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier |
> >                         PE_NAME_CACHE_TYPE modifier
> > event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
> > event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
> > modifier:               PE_MODIFIER_EVENT | empty
> 
> This isn't complete, we need means of specifying
> perf_event_attr::config[12] when specifying a raw event. 

Also, it might make sense to think about how to specify sysfs events
(which don't exist yet).

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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-16 14:02   ` Peter Zijlstra
  2011-12-16 14:03     ` Peter Zijlstra
@ 2011-12-19 14:37     ` Jiri Olsa
  2011-12-20 10:29     ` [PATCHv2 0/2] perf tool: " Jiri Olsa
  2 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-19 14:37 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Fri, Dec 16, 2011 at 03:02:39PM +0100, Peter Zijlstra wrote:
> On Thu, 2011-12-15 at 16:30 +0100, Jiri Olsa wrote:

SNIP

> > event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
> > event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
> > modifier:               PE_MODIFIER_EVENT | empty
> 
> This isn't complete, we need means of specifying
> perf_event_attr::config[12] when specifying a raw event.
ok

> 
> 

SNIP

> >                         cpu-migrations|migrations                      |
> >                         alignment-faults                               |
> >                         emulation-faults
> 
> It might make sense to allow means of custom symbol -> raw mappings.
>
right, will save some code..

> > PE_NAME_CACHE_TYPE:     L1-dcache|l1-d|l1d|L1-data             |
> >                         L1-icache|l1-i|l1i|L1-instruction      |
> >                         LLC|L2                                 |
> >                         dTLB|d-tlb|Data-TLB                    |
> >                         iTLB|i-tlb|Instruction-TLB             |
> >                         branch|branches|bpu|btb|bpc            |
> >                         node
> > 
> > PE_NAME_CACHE_OP_RESULT: load|loads|read                       |
> >                         store|stores|write                     |
> >                         prefetch|prefetches                    |
> >                         speculative-read|speculative-load      |
> >                         refs|Reference|ops|access              |
> >                         misses|miss
> > 
> > PE_SEP_RAW:             'r'
> > PE_SEP_BP:              'mem'
> > PE_MODIFIER_EVENT:      :[ukhp]{1,2}
> 
> You can actually have more than 2 modifiers, eg. "upp". 
> 
> [u] | [k] | [h] | [p]{,3} would be more correct I think.
yay, the boundaries are indeed [0,3], I thought it was bool..

	* precise_ip:
	*
	*  0 - SAMPLE_IP can have arbitrary
	*  skid
	*  1 - SAMPLE_IP must have constant
	*  skid
	*  2 - SAMPLE_IP requested to have 0
	*  skid
	*  3 - SAMPLE_IP must have 0 skid
	*

> 
> > PE_MODIFIER_BPTYPE:     :[rwx]{1,3}
> > PE_NAME_TP:             [a-zA-Z_*?]+
> > PE_VALUE:               number
> > 
> > Added flex/bison files for event grammar parsing. Added
> > flex/bison Makefile rules plus few special dependencies. 
> 
> It might be good to include the .c output of flex/bison so that we can
> build perf without a hard dependency on them -- only people changing the
> parser will need them.
ok

thanks,
jirka

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

* [PATCHv2 0/2] perf tool: parser generator for events parsing
  2011-12-16 14:02   ` Peter Zijlstra
  2011-12-16 14:03     ` Peter Zijlstra
  2011-12-19 14:37     ` Jiri Olsa
@ 2011-12-20 10:29     ` Jiri Olsa
  2011-12-20 10:29       ` [PATCHv2 1/2] perf, tool: Add " Jiri Olsa
  2011-12-20 10:29       ` [PATCHv2 2/2] perf, tool: Add more automated tests for event parsing Jiri Olsa
  2 siblings, 2 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-20 10:29 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel

hi,
adding an event parser generator to handle the '-e' option data.
I strip this version of the event grouping enhancement, so it's
more straightforward. I'll send those patches later.

Attached patches:
  - 1/2 perf, tool: Add parser generator for events parsing
  - 2/2 perf, tool: Add more automated tests for event parsing

v2 changes:
  1/2 perf, tool: Add parser generator for events parsing
   - added a way to specify config[12] for raw events
   - added direct symbol -> raw mapping in parser itself
   - fixed modifier syntax to allow all correct precise
     values
   - added generated parser as part of the patch, however..
     flex and bison dont care about the linux kernel
     coding standard, checkpatch.pl complains quite a lot:

       total: 728 errors, 1316 warnings, 5379 lines checked

     after I tried cleanpatch scripts I've got:

       total: 664 errors, 1287 warnings, 5382 lines checked

     so I'm not sure it's worth to do that (the cleanup),
     considering it needs to be regenerated each time we change
     the parser grammar.
   - added 'event-parser' Makefile target to generate
     the parser out of the flex/bison sources

thanks,
jirka
---
 tools/perf/Makefile                  |   18 +
 tools/perf/builtin-test.c            |  276 +++++-
 tools/perf/util/parse-events-bison.c | 1743 ++++++++++++++++++++++++++
 tools/perf/util/parse-events-bison.h |   78 ++
 tools/perf/util/parse-events-flex.c  | 2256 ++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events-flex.h  |  317 +++++
 tools/perf/util/parse-events.c       |  475 +++-----
 tools/perf/util/parse-events.h       |   10 +
 tools/perf/util/parse-events.l       |  114 ++
 tools/perf/util/parse-events.y       |  131 ++
 10 files changed, 5094 insertions(+), 324 deletions(-)

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

* [PATCHv2 1/2] perf, tool: Add parser generator for events parsing
  2011-12-20 10:29     ` [PATCHv2 0/2] perf tool: " Jiri Olsa
@ 2011-12-20 10:29       ` Jiri Olsa
  2011-12-20 10:29       ` [PATCHv2 2/2] perf, tool: Add more automated tests for event parsing Jiri Olsa
  1 sibling, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-20 10:29 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Changing event parsing to use flex/bison parse generator.
The event syntax stays as it was. Added a way to specify
config[12] for raw events.

grammar description:

events: events ',' event | event

event:  event_tracepoint |
        event_raw |
        event_numeric |
        event_symbolic |
        event_generic_hw |
        event_breakpoint

event_tracepoint:       PE_NAME_TP ':' PE_NAME_TP modifier
event_raw:              PE_SEP_RAW PE_VALUE modifier |
                        PE_SEP_RAW PE_VALUE '-' PE_VALUE modifier
                        PE_SEP_RAW PE_VALUE '-' PE_VALUE '-' PE_VALUE modifier
event_numeric:          PE_VALUE ':' PE_VALUE modifier
event_symbolic:         PE_NAME_SYM modifier
event_generic_hw:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier |
                        PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier |
                        PE_NAME_CACHE_TYPE modifier
event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
modifier:               PE_MODIFIER_EVENT | empty

PE_NAME_SYM:            cpu-cycles|cycles                              |
                        stalled-cycles-frontend|idle-cycles-frontend   |
                        stalled-cycles-backend|idle-cycles-backend     |
                        instructions                                   |
                        cache-references                               |
                        cache-misses                                   |
                        branch-instructions|branches                   |
                        branch-misses                                  |
                        bus-cycles                                     |
                        cpu-clock                                      |
                        task-clock                                     |
                        page-faults|faults                             |
                        minor-faults                                   |
                        major-faults                                   |
                        context-switches|cs                            |
                        cpu-migrations|migrations                      |
                        alignment-faults                               |
                        emulation-faults

PE_NAME_CACHE_TYPE:     L1-dcache|l1-d|l1d|L1-data             |
                        L1-icache|l1-i|l1i|L1-instruction      |
                        LLC|L2                                 |
                        dTLB|d-tlb|Data-TLB                    |
                        iTLB|i-tlb|Instruction-TLB             |
                        branch|branches|bpu|btb|bpc            |
                        node

PE_NAME_CACHE_OP_RESULT: load|loads|read                       |
                        store|stores|write                     |
                        prefetch|prefetches                    |
                        speculative-read|speculative-load      |
                        refs|Reference|ops|access              |
                        misses|miss

PE_SEP_RAW:             'r'
PE_SEP_BP:              'mem'
PE_MODIFIER_EVENT:      :[ukhp]{1,4}
PE_MODIFIER_BPTYPE:     :[rwx]{1,3}
PE_NAME_TP:             [a-zA-Z_*?]+
PE_VALUE:               number

Added flex/bison files for event grammar parsing. The generated
parser is part of the patch. Added makefile rule 'event-parser'
to generate the parser code out of the bison/flex sources.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile                  |   18 +
 tools/perf/util/parse-events-bison.c | 1743 ++++++++++++++++++++++++++
 tools/perf/util/parse-events-bison.h |   78 ++
 tools/perf/util/parse-events-flex.c  | 2256 ++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events-flex.h  |  317 +++++
 tools/perf/util/parse-events.c       |  475 +++-----
 tools/perf/util/parse-events.h       |   10 +
 tools/perf/util/parse-events.l       |  114 ++
 tools/perf/util/parse-events.y       |  131 ++
 9 files changed, 4819 insertions(+), 323 deletions(-)
 create mode 100644 tools/perf/util/parse-events-bison.c
 create mode 100644 tools/perf/util/parse-events-bison.h
 create mode 100644 tools/perf/util/parse-events-flex.c
 create mode 100644 tools/perf/util/parse-events-flex.h
 create mode 100644 tools/perf/util/parse-events.l
 create mode 100644 tools/perf/util/parse-events.y

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index ac86d67..a78a48c 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -47,6 +47,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
+FLEX = $(CROSS_COMPILE)flex
+BISON= $(CROSS_COMPILE)bison
 
 # Additional ARCH settings for x86
 ifeq ($(ARCH),i386)
@@ -341,6 +343,8 @@ LIB_OBJS += $(OUTPUT)util/session.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
+LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
+LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -627,6 +631,8 @@ ifndef V
 	QUIET_LINK     = @echo '   ' LINK $@;
 	QUIET_MKDIR    = @echo '   ' MKDIR $@;
 	QUIET_GEN      = @echo '   ' GEN $@;
+	QUIET_FLEX     = @echo '   ' FLEX $@;
+	QUIET_BISON    = @echo '   ' BISON $@;
 endif
 endif
 
@@ -707,6 +713,9 @@ $(OUTPUT)perf.o perf.spec \
 	$(SCRIPTS) \
 	: $(OUTPUT)PERF-VERSION-FILE
 
+.SUFFIXES:
+.SUFFIXES: .o .c .S .s
+
 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
 $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
@@ -739,6 +748,10 @@ $(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+
+$(OUTPUT)util/parse-events-flex.o: util/parse-events-flex.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
@@ -775,6 +788,7 @@ help:
 	@echo '  html		- make html documentation'
 	@echo '  info		- make GNU info documentation (access with info <foo>)'
 	@echo '  pdf		- make pdf documentation'
+	@echo '  event-parser	- make event parser code'
 	@echo '  TAGS		- use etags to make tag information for source browsing'
 	@echo '  tags		- use ctags to make tag information for source browsing'
 	@echo '  cscope	- use cscope to make interactive browsing database'
@@ -825,6 +839,10 @@ cscope:
 	$(RM) cscope*
 	$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
 
+event-parser:
+	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o util/parse-events-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=util/parse-events-flex.h -t util/parse-events.l > util/parse-events-flex.c
+
 ### Detect prefix changes
 TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
              $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
new file mode 100644
index 0000000..ebc39b8
--- /dev/null
+++ b/tools/perf/util/parse-events-bison.c
@@ -0,0 +1,1743 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.4.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse         parse_events_parse
+#define yylex           parse_events_lex
+#define yyerror         parse_events_error
+#define yylval          parse_events_lval
+#define yychar          parse_events_char
+#define yydebug         parse_events_debug
+#define yynerrs         parse_events_nerrs
+
+
+/* Copy the first part of user declarations.  */
+
+/* Line 189 of yacc.c  */
+#line 4 "util/parse-events.y"
+
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+
+
+/* Line 189 of yacc.c  */
+#line 100 "util/parse-events-bison.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PE_VALUE = 258,
+     PE_VALUE_SYM = 259,
+     PE_MODIFIER_BPTYPE = 260,
+     PE_MODIFIER_EVENT = 261,
+     PE_NAME_TP = 262,
+     PE_NAME_CACHE_TYPE = 263,
+     PE_NAME_CACHE_OP_RESULT = 264,
+     PE_SEP_RAW = 265,
+     PE_SEP_BP = 266,
+     PE_ERROR = 267
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c  */
+#line 39 "util/parse-events.y"
+
+	char *str;
+	unsigned long num;
+
+
+
+/* Line 214 of yacc.c  */
+#line 155 "util/parse-events-bison.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 264 of yacc.c  */
+#line 167 "util/parse-events-bison.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  23
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   45
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  16
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  11
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  23
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  46
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   267
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    13,    15,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    14,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     7,     9,    11,    13,    15,    17,    19,
+      21,    26,    30,    36,    44,    49,    52,    59,    64,    67,
+      73,    75,    76,    78
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      17,     0,    -1,    17,    13,    18,    -1,    18,    -1,    19,
+      -1,    20,    -1,    21,    -1,    22,    -1,    23,    -1,    24,
+      -1,     7,    14,     7,    26,    -1,    10,     3,    26,    -1,
+      10,     3,    15,     3,    26,    -1,    10,     3,    15,     3,
+      15,     3,    26,    -1,     3,    14,     3,    26,    -1,     4,
+      26,    -1,     8,    15,     9,    15,     9,    26,    -1,     8,
+      15,     9,    26,    -1,     8,    26,    -1,    11,    14,     3,
+      25,    26,    -1,     5,    -1,    -1,     6,    -1,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,    45,    45,    45,    47,    48,    49,    50,    51,    52,
+      54,    60,    65,    70,    75,    80,    89,    94,    99,   104,
+     109,   114,   118,   123
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "PE_VALUE", "PE_VALUE_SYM",
+  "PE_MODIFIER_BPTYPE", "PE_MODIFIER_EVENT", "PE_NAME_TP",
+  "PE_NAME_CACHE_TYPE", "PE_NAME_CACHE_OP_RESULT", "PE_SEP_RAW",
+  "PE_SEP_BP", "PE_ERROR", "','", "':'", "'-'", "$accept", "events",
+  "event", "event_tracepoint", "event_raw", "event_numeric",
+  "event_symbolic", "event_generic_hw", "event_breakpoint",
+  "event_breakpoint_type", "modifier", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,    44,    58,    45
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    16,    17,    17,    18,    18,    18,    18,    18,    18,
+      19,    20,    20,    20,    21,    22,    23,    23,    23,    24,
+      25,    25,    26,    26
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     3,     1,     1,     1,     1,     1,     1,     1,
+       4,     3,     5,     7,     4,     2,     6,     4,     2,     5,
+       1,     0,     1,     0
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,     0,    23,     0,    23,     0,     0,     0,     3,     4,
+       5,     6,     7,     8,     9,     0,    22,    15,     0,     0,
+      18,    23,     0,     1,     0,    23,    23,    23,     0,    11,
+      21,     2,    14,    10,     0,    17,    23,    20,    23,    23,
+       0,    12,    19,    16,    23,    13
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     7,     8,     9,    10,    11,    12,    13,    14,    38,
+      17
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -13
+static const yytype_int8 yypact[] =
+{
+      34,   -12,    -1,    -7,    -3,     5,     2,     1,   -13,   -13,
+     -13,   -13,   -13,   -13,   -13,     7,   -13,   -13,     4,    10,
+     -13,    -2,    17,   -13,    34,    -1,    -1,     0,    21,   -13,
+      20,   -13,   -13,   -13,    18,   -13,     3,   -13,    -1,    -1,
+      23,   -13,   -13,   -13,    -1,   -13
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -13,   -13,     6,   -13,   -13,   -13,   -13,   -13,   -13,   -13,
+      -4
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+      20,    23,    15,    16,    16,    16,    16,    18,    21,    16,
+      25,    26,    19,    28,    24,    34,    22,    29,    40,    27,
+      30,    32,    33,    35,    36,    37,    44,    39,     0,     0,
+      31,     0,    41,     0,    42,    43,     0,     1,     2,     0,
+      45,     3,     4,     0,     5,     6
+};
+
+static const yytype_int8 yycheck[] =
+{
+       4,     0,    14,     6,     6,     6,     6,    14,     3,     6,
+       3,     7,    15,    15,    13,    15,    14,    21,    15,     9,
+       3,    25,    26,    27,     3,     5,     3,     9,    -1,    -1,
+      24,    -1,    36,    -1,    38,    39,    -1,     3,     4,    -1,
+      44,     7,     8,    -1,    10,    11
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,     4,     7,     8,    10,    11,    17,    18,    19,
+      20,    21,    22,    23,    24,    14,     6,    26,    14,    15,
+      26,     3,    14,     0,    13,     3,     7,     9,    15,    26,
+       3,    18,    26,    26,    15,    26,     3,     5,    25,     9,
+      15,    26,    26,    26,     3,    26
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  However,
+   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
+   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+   discussed.  */
+
+#define YYFAIL		goto yyerrlab
+#if defined YYFAIL
+  /* This is here to suppress warnings from the GCC cpp's
+     -Wunused-macros.  Normally we don't worry about that warning, but
+     some users do, and we want to make it easy for users to remove
+     YYFAIL uses, which will produce warnings from Bison 2.5.  */
+#endif
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 10:
+
+/* Line 1464 of yacc.c  */
+#line 55 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_tracepoint((yyvsp[(1) - (4)].str), (yyvsp[(3) - (4)].str), (yyvsp[(4) - (4)].str)));
+;}
+    break;
+
+  case 11:
+
+/* Line 1464 of yacc.c  */
+#line 61 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_raw((yyvsp[(2) - (3)].num), 0, 0, (yyvsp[(3) - (3)].str)));
+;}
+    break;
+
+  case 12:
+
+/* Line 1464 of yacc.c  */
+#line 66 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_raw((yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].num), 0, (yyvsp[(5) - (5)].str)));
+;}
+    break;
+
+  case 13:
+
+/* Line 1464 of yacc.c  */
+#line 71 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_raw((yyvsp[(2) - (7)].num), (yyvsp[(4) - (7)].num), (yyvsp[(6) - (7)].num), (yyvsp[(7) - (7)].str)));
+;}
+    break;
+
+  case 14:
+
+/* Line 1464 of yacc.c  */
+#line 76 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric((yyvsp[(1) - (4)].num), (yyvsp[(3) - (4)].num), (yyvsp[(4) - (4)].str)));
+;}
+    break;
+
+  case 15:
+
+/* Line 1464 of yacc.c  */
+#line 81 "util/parse-events.y"
+    {
+	int type = (yyvsp[(1) - (2)].num) >> 16;
+	int config = (yyvsp[(1) - (2)].num) & 255;
+
+	ABORT_ON(parse_events_add_numeric(type, config, (yyvsp[(2) - (2)].str)));
+;}
+    break;
+
+  case 16:
+
+/* Line 1464 of yacc.c  */
+#line 90 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_generic_hw((yyvsp[(1) - (6)].str), (yyvsp[(3) - (6)].str), (yyvsp[(5) - (6)].str), (yyvsp[(6) - (6)].str)));
+;}
+    break;
+
+  case 17:
+
+/* Line 1464 of yacc.c  */
+#line 95 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_generic_hw((yyvsp[(1) - (4)].str), (yyvsp[(3) - (4)].str), NULL, (yyvsp[(4) - (4)].str)));
+;}
+    break;
+
+  case 18:
+
+/* Line 1464 of yacc.c  */
+#line 100 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_generic_hw((yyvsp[(1) - (2)].str), NULL, NULL, (yyvsp[(2) - (2)].str)));
+;}
+    break;
+
+  case 19:
+
+/* Line 1464 of yacc.c  */
+#line 105 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_breakpoint((void *) (yyvsp[(3) - (5)].num), (yyvsp[(4) - (5)].str), (yyvsp[(5) - (5)].str)))
+;}
+    break;
+
+  case 20:
+
+/* Line 1464 of yacc.c  */
+#line 110 "util/parse-events.y"
+    {
+	(yyval.str) = (yyvsp[(1) - (1)].str)
+;}
+    break;
+
+  case 21:
+
+/* Line 1464 of yacc.c  */
+#line 114 "util/parse-events.y"
+    {
+	(yyval.str) = NULL;
+;}
+    break;
+
+  case 22:
+
+/* Line 1464 of yacc.c  */
+#line 119 "util/parse-events.y"
+    {
+	(yyval.str) = (yyvsp[(1) - (1)].str);
+;}
+    break;
+
+  case 23:
+
+/* Line 1464 of yacc.c  */
+#line 123 "util/parse-events.y"
+    {
+	(yyval.str) = NULL;
+;}
+    break;
+
+
+
+/* Line 1464 of yacc.c  */
+#line 1526 "util/parse-events-bison.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (yymsg);
+	  }
+	else
+	  {
+	    yyerror (YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+/* Line 1684 of yacc.c  */
+#line 127 "util/parse-events.y"
+
+
+void parse_events_error(char const *msg __used)
+{
+}
+
diff --git a/tools/perf/util/parse-events-bison.h b/tools/perf/util/parse-events-bison.h
new file mode 100644
index 0000000..977dbdc
--- /dev/null
+++ b/tools/perf/util/parse-events-bison.h
@@ -0,0 +1,78 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PE_VALUE = 258,
+     PE_VALUE_SYM = 259,
+     PE_MODIFIER_BPTYPE = 260,
+     PE_MODIFIER_EVENT = 261,
+     PE_NAME_TP = 262,
+     PE_NAME_CACHE_TYPE = 263,
+     PE_NAME_CACHE_OP_RESULT = 264,
+     PE_SEP_RAW = 265,
+     PE_SEP_BP = 266,
+     PE_ERROR = 267
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1685 of yacc.c  */
+#line 39 "util/parse-events.y"
+
+	char *str;
+	unsigned long num;
+
+
+
+/* Line 1685 of yacc.c  */
+#line 70 "util/parse-events-bison.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE parse_events_lval;
+
+
diff --git a/tools/perf/util/parse-events-flex.c b/tools/perf/util/parse-events-flex.c
new file mode 100644
index 0000000..62eeb9c
--- /dev/null
+++ b/tools/perf/util/parse-events-flex.c
@@ -0,0 +1,2256 @@
+
+#line 3 "<stdout>"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer parse_events__create_buffer
+#define yy_delete_buffer parse_events__delete_buffer
+#define yy_flex_debug parse_events__flex_debug
+#define yy_init_buffer parse_events__init_buffer
+#define yy_flush_buffer parse_events__flush_buffer
+#define yy_load_buffer_state parse_events__load_buffer_state
+#define yy_switch_to_buffer parse_events__switch_to_buffer
+#define yyin parse_events_in
+#define yyleng parse_events_leng
+#define yylex parse_events_lex
+#define yylineno parse_events_lineno
+#define yyout parse_events_out
+#define yyrestart parse_events_restart
+#define yytext parse_events_text
+#define yywrap parse_events_wrap
+#define yyalloc parse_events_alloc
+#define yyrealloc parse_events_realloc
+#define yyfree parse_events_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE parse_events_restart(parse_events_in  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int parse_events_leng;
+
+extern FILE *parse_events_in, *parse_events_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up parse_events_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up parse_events_text again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via parse_events_restart()), so that the user can continue scanning by
+	 * just pointing parse_events_in at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when parse_events_text is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int parse_events_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow parse_events_wrap()'s to do buffer switches
+ * instead of setting up a fresh parse_events_in.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void parse_events_restart (FILE *input_file  );
+void parse_events__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE parse_events__create_buffer (FILE *file,int size  );
+void parse_events__delete_buffer (YY_BUFFER_STATE b  );
+void parse_events__flush_buffer (YY_BUFFER_STATE b  );
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void parse_events_pop_buffer_state (void );
+
+static void parse_events_ensure_buffer_stack (void );
+static void parse_events__load_buffer_state (void );
+static void parse_events__init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER parse_events__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE parse_events__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE parse_events__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE parse_events__scan_bytes (yyconst char *bytes,int len  );
+
+void *parse_events_alloc (yy_size_t  );
+void *parse_events_realloc (void *,yy_size_t  );
+void parse_events_free (void *  );
+
+#define yy_new_buffer parse_events__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        parse_events_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        parse_events_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *parse_events_in = (FILE *) 0, *parse_events_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int parse_events_lineno;
+
+int parse_events_lineno = 1;
+
+extern char *parse_events_text;
+#define yytext_ptr parse_events_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up parse_events_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	parse_events_leng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 47
+#define YY_END_OF_BUFFER 48
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[433] =
+    {   0,
+        0,    0,    0,    0,   48,   47,   43,   45,   44,   32,
+       32,   46,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   34,   43,
+       43,   43,   41,   39,   39,   38,   43,   32,    0,   42,
+       43,   43,    0,   21,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   15,   43,    0,   43,   43,
+       43,    0,   43,   43,   43,    0,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   39,
+        0,   37,   36,   33,   42,   43,   43,    0,   21,   43,
+       43,   43,   24,   43,   43,   43,   43,   43,   43,    0,
+
+       43,   43,   43,    0,   43,   43,   43,    0,   19,   20,
+       43,   43,   35,   43,   43,   43,   43,   30,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   40,   37,   36,
+       42,   43,   43,    0,    0,   43,   43,   43,   43,    0,
+       43,   43,    0,   43,    0,   22,   43,   43,    0,   23,
+       43,   43,   26,   43,   43,   43,   31,   25,   43,   43,
+       26,   43,   43,   43,   43,   43,   37,   36,   42,    0,
+       43,    0,    0,    0,    0,   43,   43,   43,   43,    0,
+       43,   43,    0,    0,   43,   22,   43,   43,   23,    0,
+       43,   43,   43,   43,   43,    0,   43,   43,   43,   27,
+
+        0,   27,   37,    0,   43,    0,    0,    0,    0,   43,
+       43,   24,    0,    0,   43,    0,    0,    0,    1,   43,
+       12,    0,   43,    0,   43,    0,   31,    0,   43,   43,
+       43,    0,    0,   43,    0,    0,    0,   43,   43,    0,
+       43,    0,    0,    0,   43,    0,    0,    0,   43,    0,
+       43,    0,   43,    0,    0,   43,   43,   43,    0,   43,
+        0,    0,    0,   43,   43,    0,    0,    7,    0,    0,
+        0,    0,    0,    0,    0,   43,    0,   43,    0,   43,
+        0,    0,   28,   43,    0,    0,   43,    0,   43,    0,
+        0,    0,    0,    0,    0,   10,    0,    0,   43,    0,
+
+       43,    0,   43,    0,    0,   43,   43,    0,    0,   43,
+        0,    0,    0,    0,    9,    0,    0,    0,    1,    0,
+        0,    0,   43,    0,   16,    0,    0,   28,   43,    0,
+       11,   43,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   43,    0,    0,   12,   43,    0,    0,    0,
+        0,    0,    0,    6,    0,    0,    0,    0,    0,    4,
+       14,   13,    0,    0,    0,    0,    0,    0,    8,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,   16,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+       17,    0,    5,   15,   18,    0,    0,   29,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        7,    3,    0,    0,    0,    2,    0,    0,    0,    0,
+        0,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    2,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    3,    1,    4,    5,    1,    1,    6,    7,    8,
+        9,    9,    9,    9,    9,    9,    9,   10,    1,    1,
+        1,    1,    3,    1,   11,   12,   13,   14,   11,   11,
+        3,    3,   15,    3,    3,   16,    3,    3,    3,    3,
+        3,   17,    3,   18,    3,    3,    3,    3,    3,    3,
+        1,    1,    1,    1,    3,    1,   19,   20,   21,   22,
+
+       23,   24,   25,   26,   27,   28,   29,   30,   31,   32,
+       33,   34,    3,   35,   36,   37,   38,   39,   40,   41,
+       42,    3,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[43] =
+    {   0,
+        1,    1,    2,    1,    1,    3,    3,    3,    3,    1,
+        4,    4,    4,    4,    2,    2,    2,    2,    4,    4,
+        4,    4,    4,    4,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2
+    } ;
+
+static yyconst flex_int16_t yy_base[437] =
+    {   0,
+        0,    0,   41,   50,  527,  528,    0,  528,  528,   55,
+       59,   43,  507,  493,   37,  501,   25,   36,   56,   73,
+      492,  503,   75,   69,   60,  488,  486,   65,  496,   48,
+      499,  482,  528,   97,  102,  113,    0,  106,    0,   90,
+      479,  479,  509,  528,  500,  488,  490,  483,   80,  490,
+      488,  471,  485,  473,  466,    0,  482,  465,  485,  462,
+      461,  461,  481,  466,  459,  118,  475,  465,  461,   63,
+      469,  454,  464,  465,   98,  464,  101,  450,  458,  123,
+        0,  123,   86,    0,  129,  465,  446,  114,    0,  459,
+      458,  455,    0,  447,  473,  451,  439,  470,  444,  443,
+
+      460,  441,  440,  439,  456,  444,  429,  137,  528,  528,
+      443,  431,    0,  428,  429,  425,  437,    0,  436,  434,
+      435,  420,  434,  424,  418,  423,  414,    0,  136,  131,
+      147,  445,  414,  114,  147,  413,  411,  414,  424,  423,
+      420,  419,  125,  418,  420,    0,  420,  401,  417,    0,
+      431,  400,  398,  398,  413,  396,  407,    0,  424,  405,
+        0,  389,  396,  402,  419,  400,  149,  528,  528,  404,
+      383,  383,  400,  399,  381,  393,  379,  383,  387,  370,
+      406,  369,   95,  382,  372,  528,  370,  370,  528,  384,
+      366,  398,  365,  396,  364,  375,  361,  367,  373,  359,
+
+      373,    0,  528,  377,  371,  372,  369,  368,  351,  355,
+      363,  172,  364,  149,  347,  350,  361,  356,    0,  353,
+        0,  337,  357,  353,  349,  351,    0,  355,  352,  353,
+      349,  340,  357,  331,  341,  340,  330,  343,  331,  155,
+      326,  331,  333,  336,  353,  336,  326,  320,  321,  332,
+      315,  332,  317,  330,  310,  321,  309,  340,  311,  316,
+      319,  318,  302,  316,  301,  305,  309,    0,  312,  298,
+      309,  296,  302,  307,  310,  296,  297,  299,  287,  292,
+      285,  292,  298,  293,  298,  297,  284,  295,  310,  278,
+      277,  276,  275,  287,  269,  528,  272,  270,  301,  282,
+
+      271,  273,  266,  271,  263,  263,  259,  255,  267,  263,
+      257,  269,  255,  255,  528,  267,  254,  261,  528,  260,
+      262,  249,  252,  246,    0,  245,  245,    0,  257,  258,
+      528,  273,  250,  257,  240,  251,  237,  249,  234,  237,
+      250,  263,  231,  230,  229,  528,  259,  233,  244,  228,
+      222,  221,  222,  528,  225,  235,  223,  216,  168,    0,
+      528,  528,  159,  230,  236,  219,  220,  228,  528,  227,
+      221,  210,  215,  225,  208,  209,  218,  204,  227,  201,
+      200,  213,  212,  528,  197,  212,  199,  212,  211,  224,
+      192,  200,  190,  189,  188,  194,  190,  199,  198,  173,
+
+      528,  186,  528,  528,  528,  195,  180,  528,  197,  180,
+      182,  181,  189,  190,  177,  173,  181,  164,  162,  158,
+      528,  528,  147,  137,  113,  528,  112,  120,   72,   54,
+       32,  528,  197,  200,  202,  204
+    } ;
+
+static yyconst flex_int16_t yy_def[437] =
+    {   0,
+      432,    1,  433,  433,  432,  432,  434,  432,  432,  432,
+      432,  432,  434,  434,  434,  434,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  434,
+      434,  434,  432,  432,  432,  432,  434,  432,  435,  432,
+      434,  434,  432,  432,  434,  434,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  432,  434,  434,
+      434,  432,  434,  434,  434,  432,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  432,
+      436,  432,  432,  435,  432,  434,  434,  432,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  432,
+
+      434,  434,  434,  432,  434,  434,  434,  432,  432,  432,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  436,  432,  432,
+      432,  434,  434,  432,  432,  434,  434,  434,  434,  432,
+      434,  434,  432,  434,  432,  434,  434,  434,  432,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  432,  432,  432,  432,
+      434,  432,  432,  432,  432,  434,  434,  434,  434,  432,
+      434,  434,  432,  432,  434,  432,  434,  434,  432,  432,
+      434,  434,  434,  434,  434,  432,  434,  434,  434,  434,
+
+      432,  434,  432,  432,  434,  432,  432,  432,  432,  434,
+      434,  434,  432,  432,  434,  432,  432,  432,  434,  434,
+      434,  432,  434,  432,  434,  432,  434,  432,  434,  434,
+      434,  432,  432,  434,  432,  432,  432,  434,  434,  432,
+      434,  432,  432,  432,  434,  432,  432,  432,  434,  432,
+      434,  432,  434,  432,  432,  434,  434,  434,  432,  434,
+      432,  432,  432,  434,  434,  432,  432,  434,  432,  432,
+      432,  432,  432,  432,  432,  434,  432,  434,  432,  434,
+      432,  432,  434,  434,  432,  432,  434,  432,  434,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  434,  432,
+
+      434,  432,  434,  432,  432,  434,  434,  432,  432,  434,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  434,  432,  434,  432,  432,  434,  434,  432,
+      432,  434,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  434,  432,  432,  432,  434,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  434,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,    0,  432,  432,  432,  432
+    } ;
+
+static yyconst flex_int16_t yy_nxt[571] =
+    {   0,
+        6,    6,    7,    8,    9,   10,   11,   11,   11,   12,
+        7,    7,    7,   13,   14,   15,   16,    7,   17,   18,
+       19,   20,   21,   22,    7,    7,   23,    7,    7,   24,
+       25,   26,   27,   28,   29,   30,   31,    7,    7,   32,
+        7,    7,    6,   43,   44,   47,   34,   35,   35,   35,
+       36,    6,   45,  426,   48,   34,   35,   35,   35,   36,
+       38,   38,   38,   38,   38,   38,   38,   38,   40,   49,
+       50,   40,   51,   52,   53,   66,   40,   58,   68,   62,
+       40,   76,   69,   73,   77,  431,   70,  114,   54,   55,
+       59,   56,   63,  422,  115,   39,   64,   57,  116,   74,
+
+       93,   67,   80,   80,   80,   80,   65,   80,   80,   80,
+       80,   38,   38,   38,   38,   85,  121,   93,   85,  124,
+      130,  122,  108,   85,  216,  130,  130,   85,   80,   80,
+       80,   80,  172,  125,  173,  134,  217,   81,   82,  109,
+      135,   82,  430,  429,  110,  183,   82,   83,  129,  428,
+       82,  129,   83,   83,  131,  184,  129,  131,  109,  427,
+      129,  167,  131,  110,  167,  168,  131,  174,  426,  167,
+      168,  168,  169,  167,  203,  169,  240,  203,  175,  243,
+      169,  266,  203,  244,  169,  267,  203,  374,  376,  425,
+      424,  375,  409,  377,  241,  423,  410,   33,   33,   33,
+
+       33,   37,  422,   37,   84,   84,  128,  128,  421,  420,
+      419,  418,  417,  416,  415,  414,  413,  412,  411,  408,
+      408,  407,  406,  405,  404,  403,  402,  401,  400,  399,
+      398,  397,  396,  395,  394,  393,  392,  391,  189,  390,
+      389,  388,  387,  386,  385,  384,  383,  382,  381,  380,
+      110,  379,  378,  373,  372,  371,  370,  369,  368,  367,
+      366,  365,  364,  363,  362,  361,  360,  359,  358,  357,
+      356,  355,  354,  353,  352,  351,  350,  349,  348,  347,
+      346,  345,  344,  343,  342,  341,  340,  339,  338,  337,
+      336,  335,  334,  333,  332,  331,  330,  329,  328,  327,
+
+      326,  325,  324,  323,  322,  321,  320,  319,  318,  317,
+      316,  315,  314,  313,  312,  311,  310,  309,  308,  307,
+      306,  305,  304,  303,  302,  301,  300,  299,  298,  297,
+      296,  295,  294,  293,  292,  291,  290,  289,  118,  288,
+      110,  109,  287,  286,  285,  284,  283,  282,  281,  280,
+      279,  278,  277,  276,  275,  274,  273,  272,  271,  270,
+      269,  268,  265,  264,  263,  262,  261,  260,  186,  259,
+      258,  257,  256,  255,  254,  253,  252,  251,  250,  249,
+      248,  247,  246,  245,  242,  239,  238,  237,  236,  235,
+      109,  234,  233,  232,  202,  231,  230,  229,  228,  227,
+
+      226,  225,  224,  223,  222,  221,  220,  219,  218,  215,
+      214,  213,  212,  211,  118,  210,  209,  208,  207,  206,
+      205,  204,  202,  201,  200,  199,  198,  197,  196,  195,
+      194,  193,  192,  161,  191,  190,  189,  188,  187,  186,
+      185,  182,  181,  180,  179,  178,  177,  176,  171,  170,
+      166,  165,  164,  163,  162,  118,  161,  160,  159,  158,
+      157,  156,  155,  154,  153,  152,  151,  150,  149,  148,
+      147,  146,  145,  144,  143,  142,  141,  140,  139,  138,
+      137,  136,  133,  132,  127,  126,  123,  120,  119,  118,
+      117,  113,  112,  111,  107,  106,  105,  104,  103,  102,
+
+      101,  100,   99,   98,   97,   96,   95,   93,   94,   92,
+       91,   90,   89,   88,   87,   86,   79,   78,   75,   72,
+       71,   61,   60,   46,   42,   41,  432,    5,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432
+    } ;
+
+static yyconst flex_int16_t yy_chk[571] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    3,   15,   15,   17,    3,    3,    3,    3,
+        3,    4,   15,  431,   17,    4,    4,    4,    4,    4,
+       10,   10,   10,   10,   11,   11,   11,   11,   12,   18,
+       18,   12,   18,   18,   19,   24,   12,   20,   25,   23,
+       12,   30,   25,   28,   30,  430,   25,   70,   19,   19,
+       20,   19,   23,  429,   70,   10,   23,   19,   70,   28,
+
+       49,   24,   34,   34,   34,   34,   23,   35,   35,   35,
+       35,   38,   38,   38,   38,   40,   75,   49,   40,   77,
+       83,   75,   66,   40,  183,   83,   83,   40,   80,   80,
+       80,   80,  134,   77,  134,   88,  183,   34,   36,   66,
+       88,   36,  428,  427,   66,  143,   36,   36,   82,  425,
+       36,   82,   36,   36,   85,  143,   82,   85,  108,  424,
+       82,  129,   85,  108,  129,  130,   85,  135,  423,  129,
+      130,  130,  131,  129,  167,  131,  212,  167,  135,  214,
+      131,  240,  167,  214,  131,  240,  167,  359,  363,  420,
+      419,  359,  400,  363,  212,  418,  400,  433,  433,  433,
+
+      433,  434,  417,  434,  435,  435,  436,  436,  416,  415,
+      414,  413,  412,  411,  410,  409,  407,  406,  402,  399,
+      398,  397,  396,  395,  394,  393,  392,  391,  390,  389,
+      388,  387,  386,  385,  383,  382,  381,  380,  379,  378,
+      377,  376,  375,  374,  373,  372,  371,  370,  368,  367,
+      366,  365,  364,  358,  357,  356,  355,  353,  352,  351,
+      350,  349,  348,  347,  345,  344,  343,  342,  341,  340,
+      339,  338,  337,  336,  335,  334,  333,  332,  330,  329,
+      327,  326,  324,  323,  322,  321,  320,  318,  317,  316,
+      314,  313,  312,  311,  310,  309,  308,  307,  306,  305,
+
+      304,  303,  302,  301,  300,  299,  298,  297,  295,  294,
+      293,  292,  291,  290,  289,  288,  287,  286,  285,  284,
+      283,  282,  281,  280,  279,  278,  277,  276,  275,  274,
+      273,  272,  271,  270,  269,  267,  266,  265,  264,  263,
+      262,  261,  260,  259,  258,  257,  256,  255,  254,  253,
+      252,  251,  250,  249,  248,  247,  246,  245,  244,  243,
+      242,  241,  239,  238,  237,  236,  235,  234,  233,  232,
+      231,  230,  229,  228,  226,  225,  224,  223,  222,  220,
+      218,  217,  216,  215,  213,  211,  210,  209,  208,  207,
+      206,  205,  204,  201,  200,  199,  198,  197,  196,  195,
+
+      194,  193,  192,  191,  190,  188,  187,  185,  184,  182,
+      181,  180,  179,  178,  177,  176,  175,  174,  173,  172,
+      171,  170,  166,  165,  164,  163,  162,  160,  159,  157,
+      156,  155,  154,  153,  152,  151,  149,  148,  147,  145,
+      144,  142,  141,  140,  139,  138,  137,  136,  133,  132,
+      127,  126,  125,  124,  123,  122,  121,  120,  119,  117,
+      116,  115,  114,  112,  111,  107,  106,  105,  104,  103,
+      102,  101,  100,   99,   98,   97,   96,   95,   94,   92,
+       91,   90,   87,   86,   79,   78,   76,   74,   73,   72,
+       71,   69,   68,   67,   65,   64,   63,   62,   61,   60,
+
+       59,   58,   57,   55,   54,   53,   52,   51,   50,   48,
+       47,   46,   45,   43,   42,   41,   32,   31,   29,   27,
+       26,   22,   21,   16,   14,   13,    5,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  432,  432
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int parse_events__flex_debug;
+int parse_events__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *parse_events_text;
+#line 1 "util/parse-events.l"
+#line 5 "util/parse-events.l"
+#include <errno.h>
+#include "../perf.h"
+#include "parse-events-bison.h"
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(parse_events_text, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.num = num;
+	return PE_VALUE;
+}
+
+static int __str(char *s, int token)
+{
+	parse_events_lval.str = strdup(s);
+	return token;
+}
+
+static int str(int token)
+{
+	return __str(parse_events_text, token);
+}
+
+static int mod(int token)
+{
+	return __str(parse_events_text + 1, token);
+}
+
+static int sym(int type, int config)
+{
+	parse_events_lval.num = (type << 16) + config;
+	return PE_VALUE_SYM;
+}
+
+
+#line 776 "<stdout>"
+
+#define INITIAL 0
+#define BP 1
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int parse_events_lex_destroy (void );
+
+int parse_events_get_debug (void );
+
+void parse_events_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE parse_events_get_extra (void );
+
+void parse_events_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *parse_events_get_in (void );
+
+void parse_events_set_in  (FILE * in_str  );
+
+FILE *parse_events_get_out (void );
+
+void parse_events_set_out  (FILE * out_str  );
+
+int parse_events_get_leng (void );
+
+char *parse_events_get_text (void );
+
+int parse_events_get_lineno (void );
+
+void parse_events_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int parse_events_wrap (void );
+#else
+extern int parse_events_wrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( parse_events_text, parse_events_leng, 1, parse_events_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		unsigned n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( parse_events_in )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( parse_events_in ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, parse_events_in))==0 && ferror(parse_events_in)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(parse_events_in); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int parse_events_lex (void);
+
+#define YY_DECL int parse_events_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after parse_events_text and parse_events_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 53 "util/parse-events.l"
+
+
+#line 962 "<stdout>"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! parse_events_in )
+			parse_events_in = stdin;
+
+		if ( ! parse_events_out )
+			parse_events_out = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			parse_events_ensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				parse_events__create_buffer(parse_events_in,YY_BUF_SIZE );
+		}
+
+		parse_events__load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of parse_events_text. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 433 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 528 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 55 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 56 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 57 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 58 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 59 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 60 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 61 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 62 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 63 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 64 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 65 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 66 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 67 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 68 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 69 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 70 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 71 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 72 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+	YY_BREAK
+case 19:
+#line 75 "util/parse-events.l"
+case 20:
+#line 76 "util/parse-events.l"
+case 21:
+#line 77 "util/parse-events.l"
+case 22:
+#line 78 "util/parse-events.l"
+case 23:
+#line 79 "util/parse-events.l"
+case 24:
+#line 80 "util/parse-events.l"
+case 25:
+YY_RULE_SETUP
+#line 80 "util/parse-events.l"
+{ return str(PE_NAME_CACHE_TYPE); }
+	YY_BREAK
+case 26:
+#line 83 "util/parse-events.l"
+case 27:
+#line 84 "util/parse-events.l"
+case 28:
+#line 85 "util/parse-events.l"
+case 29:
+#line 86 "util/parse-events.l"
+case 30:
+#line 87 "util/parse-events.l"
+case 31:
+YY_RULE_SETUP
+#line 87 "util/parse-events.l"
+{ return str(PE_NAME_CACHE_OP_RESULT); }
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 89 "util/parse-events.l"
+{ return value(10); }
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 90 "util/parse-events.l"
+{ return value(16); }
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 92 "util/parse-events.l"
+{ return PE_SEP_RAW; }
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 94 "util/parse-events.l"
+{ BEGIN(BP); return PE_SEP_BP; }
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 95 "util/parse-events.l"
+{ return mod(PE_MODIFIER_BPTYPE); }
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 96 "util/parse-events.l"
+{ return mod(PE_MODIFIER_EVENT); }
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 97 "util/parse-events.l"
+{ return ':'; }
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 98 "util/parse-events.l"
+{ return value(10); }
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 99 "util/parse-events.l"
+{ return value(16); }
+	YY_BREAK
+case YY_STATE_EOF(BP):
+#line 100 "util/parse-events.l"
+{ BEGIN(INITIAL); }
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 101 "util/parse-events.l"
+{ BEGIN(INITIAL); }
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 103 "util/parse-events.l"
+{ return mod(PE_MODIFIER_EVENT); }
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 104 "util/parse-events.l"
+{ return str(PE_NAME_TP); }
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 105 "util/parse-events.l"
+{ return '-'; }
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 106 "util/parse-events.l"
+{ return ','; }
+	YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 107 "util/parse-events.l"
+{ return ':'; }
+	YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 109 "util/parse-events.l"
+ECHO;
+	YY_BREAK
+#line 1251 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed parse_events_in at a new source and called
+			 * parse_events_lex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = parse_events_in;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( parse_events_wrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * parse_events_text, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of parse_events_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					parse_events_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			parse_events_restart(parse_events_in  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) parse_events_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 433 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    	register char *yy_cp = (yy_c_buf_p);
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 433 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 432);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up parse_events_text */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					parse_events_restart(parse_events_in );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( parse_events_wrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve parse_events_text */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void parse_events_restart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        parse_events_ensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE );
+	}
+
+	parse_events__init_buffer(YY_CURRENT_BUFFER,input_file );
+	parse_events__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void parse_events__switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		parse_events_pop_buffer_state();
+	 *		parse_events_push_buffer_state(new_buffer);
+     */
+	parse_events_ensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	parse_events__load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (parse_events_wrap()) processing, but the only time this flag
+	 * is looked at is after parse_events_wrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void parse_events__load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	parse_events_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE parse_events__create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) parse_events_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) parse_events_alloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	parse_events__init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with parse_events__create_buffer()
+ * 
+ */
+    void parse_events__delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		parse_events_free((void *) b->yy_ch_buf  );
+
+	parse_events_free((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a parse_events_restart() or at EOF.
+ */
+    static void parse_events__init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	parse_events__flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then parse_events__init_buffer was _probably_
+     * called from parse_events_restart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void parse_events__flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		parse_events__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	parse_events_ensure_buffer_stack();
+
+	/* This block is copied from parse_events__switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from parse_events__switch_to_buffer. */
+	parse_events__load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void parse_events_pop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	parse_events__delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		parse_events__load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void parse_events_ensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)parse_events_alloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in parse_events_ensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)parse_events_realloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in parse_events_ensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE parse_events__scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) parse_events_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	parse_events__switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to parse_events_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       parse_events__scan_bytes() instead.
+ */
+YY_BUFFER_STATE parse_events__scan_string (yyconst char * yystr )
+{
+    
+	return parse_events__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to parse_events_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE parse_events__scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) parse_events_alloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = parse_events__scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in parse_events__scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up parse_events_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		parse_events_text[parse_events_leng] = (yy_hold_char); \
+		(yy_c_buf_p) = parse_events_text + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		parse_events_leng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int parse_events_get_lineno  (void)
+{
+        
+    return parse_events_lineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *parse_events_get_in  (void)
+{
+        return parse_events_in;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *parse_events_get_out  (void)
+{
+        return parse_events_out;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int parse_events_get_leng  (void)
+{
+        return parse_events_leng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *parse_events_get_text  (void)
+{
+        return parse_events_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void parse_events_set_lineno (int  line_number )
+{
+    
+    parse_events_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see parse_events__switch_to_buffer
+ */
+void parse_events_set_in (FILE *  in_str )
+{
+        parse_events_in = in_str ;
+}
+
+void parse_events_set_out (FILE *  out_str )
+{
+        parse_events_out = out_str ;
+}
+
+int parse_events_get_debug  (void)
+{
+        return parse_events__flex_debug;
+}
+
+void parse_events_set_debug (int  bdebug )
+{
+        parse_events__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from parse_events_lex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    parse_events_in = stdin;
+    parse_events_out = stdout;
+#else
+    parse_events_in = (FILE *) 0;
+    parse_events_out = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * parse_events_lex_init()
+     */
+    return 0;
+}
+
+/* parse_events_lex_destroy is for both reentrant and non-reentrant scanners. */
+int parse_events_lex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		parse_events__delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		parse_events_pop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	parse_events_free((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * parse_events_lex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *parse_events_alloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *parse_events_realloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void parse_events_free (void * ptr )
+{
+	free( (char *) ptr );	/* see parse_events_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 109 "util/parse-events.l"
+
+
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
+
diff --git a/tools/perf/util/parse-events-flex.h b/tools/perf/util/parse-events-flex.h
new file mode 100644
index 0000000..3051d0e
--- /dev/null
+++ b/tools/perf/util/parse-events-flex.h
@@ -0,0 +1,317 @@
+#ifndef parse_events_HEADER_H
+#define parse_events_HEADER_H 1
+#define parse_events_IN_HEADER 1
+
+#line 6 "util/parse-events-flex.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int parse_events_leng;
+
+extern FILE *parse_events_in, *parse_events_out;
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void parse_events_restart (FILE *input_file  );
+void parse_events__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE parse_events__create_buffer (FILE *file,int size  );
+void parse_events__delete_buffer (YY_BUFFER_STATE b  );
+void parse_events__flush_buffer (YY_BUFFER_STATE b  );
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void parse_events_pop_buffer_state (void );
+
+YY_BUFFER_STATE parse_events__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE parse_events__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE parse_events__scan_bytes (yyconst char *bytes,int len  );
+
+void *parse_events_alloc (yy_size_t  );
+void *parse_events_realloc (void *,yy_size_t  );
+void parse_events_free (void *  );
+
+/* Begin user sect3 */
+
+extern int parse_events_lineno;
+
+extern char *parse_events_text;
+#define yytext_ptr parse_events_text
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define BP 1
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int parse_events_lex_destroy (void );
+
+int parse_events_get_debug (void );
+
+void parse_events_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE parse_events_get_extra (void );
+
+void parse_events_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *parse_events_get_in (void );
+
+void parse_events_set_in  (FILE * in_str  );
+
+FILE *parse_events_get_out (void );
+
+void parse_events_set_out  (FILE * out_str  );
+
+int parse_events_get_leng (void );
+
+char *parse_events_get_text (void );
+
+int parse_events_get_lineno (void );
+
+void parse_events_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int parse_events_wrap (void );
+#else
+extern int parse_events_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int parse_events_lex (void);
+
+#define YY_DECL int parse_events_lex (void)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 109 "util/parse-events.l"
+
+
+#line 316 "util/parse-events-flex.h"
+#undef parse_events_IN_HEADER
+#endif /* parse_events_HEADER_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 586ab3f..f42214a 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,9 @@
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
+#include "parse-events-flex.h"
+
+#define MAX_NAME_LEN 100
 
 struct event_symbol {
 	u8		type;
@@ -19,11 +22,9 @@ struct event_symbol {
 	const char	*alias;
 };
 
-enum event_result {
-	EVT_FAILED,
-	EVT_HANDLED,
-	EVT_HANDLED_ALL
-};
+int parse_events_parse(void);
+
+static struct perf_evlist *__evlist;
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -352,7 +353,32 @@ const char *__event_name(int type, u64 config)
 	return "unknown";
 }
 
-static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
+static int
+parse_event_modifier(char *mod, struct perf_event_attr *attr);
+
+static int add_event(struct perf_event_attr *attr, char *name, char *mod)
+{
+	struct perf_evsel *evsel;
+	int len = strlen(name);
+
+	if (parse_event_modifier(mod, attr))
+		return -EINVAL;
+
+	evsel = perf_evsel__new(attr, __evlist->nr_entries);
+	if (!evsel)
+		return -ENOMEM;
+
+	perf_evlist__add(__evlist, evsel);
+
+	evsel->name = zalloc(len);
+	if (!evsel->name)
+		return -ENOMEM;
+
+	strncpy(evsel->name, name, len);
+	return 0;
+}
+
+static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
 {
 	int i, j;
 	int n, longest = -1;
@@ -360,58 +386,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
 	for (i = 0; i < size; i++) {
 		for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
 			n = strlen(names[i][j]);
-			if (n > longest && !strncasecmp(*str, names[i][j], n))
+			if (n > longest && !strncasecmp(str, names[i][j], n))
 				longest = n;
 		}
-		if (longest > 0) {
-			*str += longest;
+		if (longest > 0)
 			return i;
-		}
 	}
 
 	return -1;
 }
 
-static enum event_result
-parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
+int parse_events_add_generic_hw(char *type, char *op_result1, char *op_result2,
+				char *mod)
 {
-	const char *s = *str;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	int cache_type = -1, cache_op = -1, cache_result = -1;
+	char *op_result[2] = { op_result1, op_result2 };
+	int i, n;
 
-	cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
 	/*
 	 * No fallback - if we cannot get a clear cache type
 	 * then bail out:
 	 */
+	cache_type = parse_aliases(type, hw_cache,
+				   PERF_COUNT_HW_CACHE_MAX);
 	if (cache_type == -1)
-		return EVT_FAILED;
+		return -EINVAL;
 
-	while ((cache_op == -1 || cache_result == -1) && *s == '-') {
-		++s;
+	n = snprintf(name, MAX_NAME_LEN, "%s", type);
+
+	for (i = 0; (i < 2) && (op_result[i]); i++) {
+		char *str = op_result[i];
+
+		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
 		if (cache_op == -1) {
-			cache_op = parse_aliases(&s, hw_cache_op,
-						PERF_COUNT_HW_CACHE_OP_MAX);
+			cache_op = parse_aliases(str, hw_cache_op,
+						 PERF_COUNT_HW_CACHE_OP_MAX);
 			if (cache_op >= 0) {
 				if (!is_cache_op_valid(cache_type, cache_op))
-					return EVT_FAILED;
+					return -EINVAL;
 				continue;
 			}
 		}
 
 		if (cache_result == -1) {
-			cache_result = parse_aliases(&s, hw_cache_result,
+			cache_result = parse_aliases(str, hw_cache_result,
 						PERF_COUNT_HW_CACHE_RESULT_MAX);
 			if (cache_result >= 0)
 				continue;
 		}
-
-		/*
-		 * Can't parse this as a cache op or result, so back up
-		 * to the '-'.
-		 */
-		--s;
-		break;
 	}
 
 	/*
@@ -426,20 +451,16 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
 	if (cache_result == -1)
 		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
 
-	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
-	attr->type = PERF_TYPE_HW_CACHE;
-
-	*str = s;
-	return EVT_HANDLED;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
+	attr.type = PERF_TYPE_HW_CACHE;
+	return add_event(&attr, name, mod);
 }
 
-static enum event_result
-parse_single_tracepoint_event(char *sys_name,
-			      const char *evt_name,
-			      unsigned int evt_length,
-			      struct perf_event_attr *attr,
-			      const char **strp)
+static int add_tracepoint(char *sys_name, char *evt_name, char *mod)
 {
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	char evt_path[MAXPATHLEN];
 	char id_buf[4];
 	u64 id;
@@ -450,130 +471,78 @@ parse_single_tracepoint_event(char *sys_name,
 
 	fd = open(evt_path, O_RDONLY);
 	if (fd < 0)
-		return EVT_FAILED;
+		return -1;
 
 	if (read(fd, id_buf, sizeof(id_buf)) < 0) {
 		close(fd);
-		return EVT_FAILED;
+		return -1;
 	}
 
 	close(fd);
 	id = atoll(id_buf);
-	attr->config = id;
-	attr->type = PERF_TYPE_TRACEPOINT;
-	*strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
-
-	attr->sample_type |= PERF_SAMPLE_RAW;
-	attr->sample_type |= PERF_SAMPLE_TIME;
-	attr->sample_type |= PERF_SAMPLE_CPU;
 
-	attr->sample_period = 1;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = id;
+	attr.type = PERF_TYPE_TRACEPOINT;
+	attr.sample_type |= PERF_SAMPLE_RAW;
+	attr.sample_type |= PERF_SAMPLE_TIME;
+	attr.sample_type |= PERF_SAMPLE_CPU;
+	attr.sample_period = 1;
 
-
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
+	return add_event(&attr, name, mod);
 }
 
-/* sys + ':' + event + ':' + flags*/
-#define MAX_EVOPT_LEN	(MAX_EVENT_LENGTH * 2 + 2 + 128)
-static enum event_result
-parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
-				const char *evt_exp, char *flags)
+static int add_tracepoint_multi(char *sys_name, char *evt_name, char *mod)
 {
 	char evt_path[MAXPATHLEN];
 	struct dirent *evt_ent;
 	DIR *evt_dir;
+	int ret = 0;
 
 	snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
 	evt_dir = opendir(evt_path);
-
 	if (!evt_dir) {
 		perror("Can't open event dir");
-		return EVT_FAILED;
+		return -1;
 	}
 
-	while ((evt_ent = readdir(evt_dir))) {
-		char event_opt[MAX_EVOPT_LEN + 1];
-		int len;
-
+	while (!ret && (evt_ent = readdir(evt_dir))) {
 		if (!strcmp(evt_ent->d_name, ".")
 		    || !strcmp(evt_ent->d_name, "..")
 		    || !strcmp(evt_ent->d_name, "enable")
 		    || !strcmp(evt_ent->d_name, "filter"))
 			continue;
 
-		if (!strglobmatch(evt_ent->d_name, evt_exp))
+		if (!strglobmatch(evt_ent->d_name, evt_name))
 			continue;
 
-		len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
-			       evt_ent->d_name, flags ? ":" : "",
-			       flags ?: "");
-		if (len < 0)
-			return EVT_FAILED;
-
-		if (parse_events(evlist, event_opt, 0))
-			return EVT_FAILED;
+		ret = add_tracepoint(sys_name, evt_ent->d_name, mod);
 	}
 
-	return EVT_HANDLED_ALL;
+	return ret;
 }
 
-static enum event_result
-parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
-		       struct perf_event_attr *attr)
+int parse_events_add_tracepoint(char *sys, char *event, char *mod)
 {
-	const char *evt_name;
-	char *flags = NULL, *comma_loc;
-	char sys_name[MAX_EVENT_LENGTH];
-	unsigned int sys_length, evt_length;
-
-	if (debugfs_valid_mountpoint(tracing_events_path))
-		return 0;
+	int ret;
 
-	evt_name = strchr(*strp, ':');
-	if (!evt_name)
-		return EVT_FAILED;
+	ret = debugfs_valid_mountpoint(tracing_events_path);
+	if (ret)
+		return ret;
 
-	sys_length = evt_name - *strp;
-	if (sys_length >= MAX_EVENT_LENGTH)
-		return 0;
-
-	strncpy(sys_name, *strp, sys_length);
-	sys_name[sys_length] = '\0';
-	evt_name = evt_name + 1;
-
-	comma_loc = strchr(evt_name, ',');
-	if (comma_loc) {
-		/* take the event name up to the comma */
-		evt_name = strndup(evt_name, comma_loc - evt_name);
-	}
-	flags = strchr(evt_name, ':');
-	if (flags) {
-		/* split it out: */
-		evt_name = strndup(evt_name, flags - evt_name);
-		flags++;
-	}
-
-	evt_length = strlen(evt_name);
-	if (evt_length >= MAX_EVENT_LENGTH)
-		return EVT_FAILED;
-	if (strpbrk(evt_name, "*?")) {
-		*strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
-		return parse_multiple_tracepoint_event(evlist, sys_name,
-						       evt_name, flags);
-	} else {
-		return parse_single_tracepoint_event(sys_name, evt_name,
-						     evt_length, attr, strp);
-	}
+	return strpbrk(event, "*?") ?
+	       add_tracepoint_multi(sys, event, mod) :
+	       add_tracepoint(sys, event, mod);
 }
 
-static enum event_result
-parse_breakpoint_type(const char *type, const char **strp,
-		      struct perf_event_attr *attr)
+static int
+parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
 	int i;
 
 	for (i = 0; i < 3; i++) {
-		if (!type[i])
+		if (!type || !type[i])
 			break;
 
 		switch (type[i]) {
@@ -587,164 +556,85 @@ parse_breakpoint_type(const char *type, const char **strp,
 			attr->bp_type |= HW_BREAKPOINT_X;
 			break;
 		default:
-			return EVT_FAILED;
+			return -EINVAL;
 		}
 	}
+
 	if (!attr->bp_type) /* Default */
 		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
 
-	*strp = type + i;
-
-	return EVT_HANDLED;
+	return 0;
 }
 
-static enum event_result
-parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_breakpoint(void *ptr, char *type, char *mod)
 {
-	const char *target;
-	const char *type;
-	char *endaddr;
-	u64 addr;
-	enum event_result err;
-
-	target = strchr(*strp, ':');
-	if (!target)
-		return EVT_FAILED;
-
-	if (strncmp(*strp, "mem", target - *strp) != 0)
-		return EVT_FAILED;
-
-	target++;
-
-	addr = strtoull(target, &endaddr, 0);
-	if (target == endaddr)
-		return EVT_FAILED;
-
-	attr->bp_addr = addr;
-	*strp = endaddr;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 
-	type = strchr(target, ':');
+	memset(&attr, 0, sizeof(attr));
+	attr.bp_addr = (u64) ptr;
 
-	/* If no type is defined, just rw as default */
-	if (!type) {
-		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
-	} else {
-		err = parse_breakpoint_type(++type, strp, attr);
-		if (err == EVT_FAILED)
-			return EVT_FAILED;
-	}
+	if (parse_breakpoint_type(type, &attr))
+		return -EINVAL;
 
 	/*
 	 * We should find a nice way to override the access length
 	 * Provide some defaults for now
 	 */
-	if (attr->bp_type == HW_BREAKPOINT_X)
-		attr->bp_len = sizeof(long);
+	if (attr.bp_type == HW_BREAKPOINT_X)
+		attr.bp_len = sizeof(long);
 	else
-		attr->bp_len = HW_BREAKPOINT_LEN_4;
+		attr.bp_len = HW_BREAKPOINT_LEN_4;
 
-	attr->type = PERF_TYPE_BREAKPOINT;
+	attr.type = PERF_TYPE_BREAKPOINT;
 
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
+	return add_event(&attr, name, mod);
 }
 
-static int check_events(const char *str, unsigned int i)
+static int add_event_val(unsigned long type, unsigned long config,
+			 unsigned long config1, unsigned long config2,
+			 char *mod)
 {
-	int n;
-
-	n = strlen(event_symbols[i].symbol);
-	if (!strncasecmp(str, event_symbols[i].symbol, n))
-		return n;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 
-	n = strlen(event_symbols[i].alias);
-	if (n) {
-		if (!strncasecmp(str, event_symbols[i].alias, n))
-			return n;
-	}
+	memset(&attr, 0, sizeof(attr));
+	attr.type = type;
+	attr.config = config;
+	attr.config1 = config1;
+	attr.config2 = config2;
 
-	return 0;
-}
+	if (type != PERF_TYPE_TRACEPOINT)
+		return add_event(&attr, (char *) __event_name(type, config),
+				 mod);
 
-static enum event_result
-parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
-{
-	const char *str = *strp;
-	unsigned int i;
-	int n;
-
-	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-		n = check_events(str, i);
-		if (n > 0) {
-			attr->type = event_symbols[i].type;
-			attr->config = event_symbols[i].config;
-			*strp = str + n;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
+	snprintf(name, MAX_NAME_LEN, "%lx:%lx", type, config);
+	return add_event(&attr, name, mod);
 }
 
-static enum event_result
-parse_raw_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_numeric(unsigned long type, unsigned long config,
+			     char *mod)
 {
-	const char *str = *strp;
-	u64 config;
-	int n;
-
-	if (*str != 'r')
-		return EVT_FAILED;
-	n = hex2u64(str + 1, &config);
-	if (n > 0) {
-		const char *end = str + n + 1;
-		if (*end != '\0' && *end != ',' && *end != ':')
-			return EVT_FAILED;
-
-		*strp = end;
-		attr->type = PERF_TYPE_RAW;
-		attr->config = config;
-		return EVT_HANDLED;
-	}
-	return EVT_FAILED;
+	return add_event_val(type, config, 0, 0, mod);
 }
 
-static enum event_result
-parse_numeric_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_raw(unsigned long config, unsigned long config1,
+			 unsigned long config2, char *mod)
 {
-	const char *str = *strp;
-	char *endp;
-	unsigned long type;
-	u64 config;
-
-	type = strtoul(str, &endp, 0);
-	if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
-		str = endp + 1;
-		config = strtoul(str, &endp, 0);
-		if (endp > str) {
-			attr->type = type;
-			attr->config = config;
-			*strp = endp;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
+	return add_event_val(PERF_TYPE_RAW, config,
+			     config1, config2, mod);
 }
 
 static int
-parse_event_modifier(const char **strp, struct perf_event_attr *attr)
+parse_event_modifier(char *str, struct perf_event_attr *attr)
 {
-	const char *str = *strp;
 	int exclude = 0;
 	int eu = 0, ek = 0, eh = 0, precise = 0;
 
-	if (!*str)
-		return 0;
-
-	if (*str == ',')
+	if (str == NULL)
 		return 0;
 
-	if (*str++ != ':')
-		return -1;
-
 	while (*str) {
 		if (*str == 'u') {
 			if (!exclude)
@@ -765,108 +655,49 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
 
 		++str;
 	}
-	if (str < *strp + 2)
-		return -1;
 
-	*strp = str;
+	/*
+	 * precise ip:
+	 *
+	 *  0 - SAMPLE_IP can have arbitrary skid
+	 *  1 - SAMPLE_IP must have constant skid
+	 *  2 - SAMPLE_IP requested to have 0 skid
+	 *  3 - SAMPLE_IP must have 0 skid
+	 *
+	 *  See also PERF_RECORD_MISC_EXACT_IP
+	 */
+	if (precise > 3)
+		return -EINVAL;
 
 	attr->exclude_user   = eu;
 	attr->exclude_kernel = ek;
 	attr->exclude_hv     = eh;
 	attr->precise_ip     = precise;
-
 	return 0;
 }
 
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static enum event_result
-parse_event_symbols(struct perf_evlist *evlist, const char **str,
-		    struct perf_event_attr *attr)
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
-	enum event_result ret;
-
-	ret = parse_tracepoint_event(evlist, str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
-
-	ret = parse_raw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
-
-	ret = parse_numeric_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
-
-	ret = parse_symbolic_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	YY_BUFFER_STATE buffer;
+	int ret;
 
-	ret = parse_generic_hw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	__evlist = evlist;
 
-	ret = parse_breakpoint_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	buffer = parse_events__scan_string(str);
 
-	fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
-	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
-	return EVT_FAILED;
+	ret = parse_events_parse();
 
-modifier:
-	if (parse_event_modifier(str, attr) < 0) {
-		fprintf(stderr, "invalid event modifier: '%s'\n", *str);
-		fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
+	parse_events__flush_buffer(buffer);
+	parse_events__delete_buffer(buffer);
 
-		return EVT_FAILED;
+	if (ret) {
+		fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
+		fprintf(stderr, "Run 'perf list' for a list of valid events\n");
 	}
 
 	return ret;
 }
 
-int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
-{
-	struct perf_event_attr attr;
-	enum event_result ret;
-	const char *ostr;
-
-	for (;;) {
-		ostr = str;
-		memset(&attr, 0, sizeof(attr));
-		ret = parse_event_symbols(evlist, &str, &attr);
-		if (ret == EVT_FAILED)
-			return -1;
-
-		if (!(*str == 0 || *str == ',' || isspace(*str)))
-			return -1;
-
-		if (ret != EVT_HANDLED_ALL) {
-			struct perf_evsel *evsel;
-			evsel = perf_evsel__new(&attr, evlist->nr_entries);
-			if (evsel == NULL)
-				return -1;
-			perf_evlist__add(evlist, evsel);
-
-			evsel->name = calloc(str - ostr + 1, 1);
-			if (!evsel->name)
-				return -1;
-			strncpy(evsel->name, ostr, str - ostr);
-		}
-
-		if (*str == 0)
-			break;
-		if (*str == ',')
-			++str;
-		while (isspace(*str))
-			++str;
-	}
-
-	return 0;
-}
-
 int parse_events_option(const struct option *opt, const char *str,
 			int unset __used)
 {
@@ -1039,8 +870,6 @@ int print_hwcache_events(const char *event_glob)
 	return printed;
 }
 
-#define MAX_NAME_LEN 100
-
 /*
  * Print the help text for the event symbols:
  */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7e0cbe7..fcd6088 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,16 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
 
+int parse_events_add_tracepoint(char *sys, char *event, char *mod);
+int parse_events_add_raw(unsigned long config, unsigned long config1,
+			 unsigned long config2, char *mod);
+int parse_events_add_numeric(unsigned long type, unsigned long config,
+			     char *mod);
+int parse_events_add_generic_hw(char *type, char *op_result1, char *op_result2,
+				char *mod);
+int parse_events_add_breakpoint(void *ptr, char *type, char *mod);
+void parse_events_error(char const *msg);
+
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
 void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
new file mode 100644
index 0000000..8cb72ba
--- /dev/null
+++ b/tools/perf/util/parse-events.l
@@ -0,0 +1,114 @@
+
+%option prefix="parse_events_"
+
+%{
+#include <errno.h>
+#include "../perf.h"
+#include "parse-events-bison.h"
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(parse_events_text, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.num = num;
+	return PE_VALUE;
+}
+
+static int __str(char *s, int token)
+{
+	parse_events_lval.str = strdup(s);
+	return token;
+}
+
+static int str(int token)
+{
+	return __str(parse_events_text, token);
+}
+
+static int mod(int token)
+{
+	return __str(parse_events_text + 1, token);
+}
+
+static int sym(int type, int config)
+{
+	parse_events_lval.num = (type << 16) + config;
+	return PE_VALUE_SYM;
+}
+
+%}
+
+num_dec		[0-9]+
+num_hex		0x[a-fA-F0-9]+
+name_tp		[a-zA-Z_*?]+
+modifier	:[ukhp]{1,4}
+
+%x BP
+
+%%
+
+cpu-cycles|cycles				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches			{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+cpu-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations			{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+
+L1-dcache|l1-d|l1d|L1-data		|
+L1-icache|l1-i|l1i|L1-instruction	|
+LLC|L2					|
+dTLB|d-tlb|Data-TLB			|
+iTLB|i-tlb|Instruction-TLB		|
+branch|branches|bpu|btb|bpc		|
+node					{ return str(PE_NAME_CACHE_TYPE); }
+
+load|loads|read				|
+store|stores|write			|
+prefetch|prefetches			|
+speculative-read|speculative-load	|
+refs|Reference|ops|access		|
+misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
+
+{num_dec}		{ return value(10); }
+{num_hex}		{ return value(16); }
+
+r			{ return PE_SEP_RAW; }
+
+mem			{ BEGIN(BP); return PE_SEP_BP; }
+<BP>:[rwx]{1,3}		{ return mod(PE_MODIFIER_BPTYPE); }
+<BP>{modifier}		{ return mod(PE_MODIFIER_EVENT); }
+<BP>:			{ return ':'; }
+<BP>{num_dec}		{ return value(10); }
+<BP>{num_hex}		{ return value(16); }
+<BP><<EOF>>		{ BEGIN(INITIAL); }
+<BP>.			{ BEGIN(INITIAL); }
+
+{modifier}		{ return mod(PE_MODIFIER_EVENT); }
+{name_tp}		{ return str(PE_NAME_TP); }
+-			{ return '-'; }
+,			{ return ','; }
+:			{ return ':'; }
+
+%%
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
new file mode 100644
index 0000000..10e8702
--- /dev/null
+++ b/tools/perf/util/parse-events.y
@@ -0,0 +1,131 @@
+
+%name-prefix "parse_events_"
+
+%{
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+%}
+
+%token PE_VALUE PE_VALUE_SYM
+%token PE_MODIFIER_BPTYPE PE_MODIFIER_EVENT
+%token PE_NAME_TP PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
+%token PE_SEP_RAW PE_SEP_BP
+%token PE_ERROR
+%type <num> PE_VALUE
+%type <num> PE_VALUE_SYM
+%type <str> PE_NAME_TP
+%type <str> PE_NAME_CACHE_TYPE
+%type <str> PE_NAME_CACHE_OP_RESULT
+%type <str> PE_MODIFIER_EVENT
+%type <str> modifier
+%type <str> PE_MODIFIER_BPTYPE
+%type <str> event_breakpoint_type
+
+%union
+{
+	char *str;
+	unsigned long num;
+}
+%%
+
+events: events ',' event | event
+
+event:  event_tracepoint |
+	event_raw |
+	event_numeric |
+	event_symbolic |
+	event_generic_hw |
+	event_breakpoint
+
+event_tracepoint: PE_NAME_TP ':' PE_NAME_TP modifier
+{
+	ABORT_ON(parse_events_add_tracepoint($1, $3, $4));
+}
+
+event_raw:
+PE_SEP_RAW PE_VALUE modifier
+{
+	ABORT_ON(parse_events_add_raw($2, 0, 0, $3));
+}
+|
+PE_SEP_RAW PE_VALUE '-' PE_VALUE modifier
+{
+	ABORT_ON(parse_events_add_raw($2, $4, 0, $5));
+}
+|
+PE_SEP_RAW PE_VALUE '-' PE_VALUE '-' PE_VALUE modifier
+{
+	ABORT_ON(parse_events_add_raw($2, $4, $6, $7));
+}
+
+event_numeric: PE_VALUE ':' PE_VALUE modifier
+{
+	ABORT_ON(parse_events_add_numeric($1, $3, $4));
+}
+
+event_symbolic: PE_VALUE_SYM modifier
+{
+	int type = $1 >> 16;
+	int config = $1 & 255;
+
+	ABORT_ON(parse_events_add_numeric(type, config, $2));
+}
+
+event_generic_hw:
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier
+{
+	ABORT_ON(parse_events_add_generic_hw($1, $3, $5, $6));
+}
+|
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier
+{
+	ABORT_ON(parse_events_add_generic_hw($1, $3, NULL, $4));
+}
+|
+PE_NAME_CACHE_TYPE modifier
+{
+	ABORT_ON(parse_events_add_generic_hw($1, NULL, NULL, $2));
+}
+
+event_breakpoint: PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
+{
+	ABORT_ON(parse_events_add_breakpoint((void *) $3, $4, $5))
+}
+
+event_breakpoint_type: PE_MODIFIER_BPTYPE
+{
+	$$ = $1
+}
+|
+{
+	$$ = NULL;
+}
+
+modifier: PE_MODIFIER_EVENT
+{
+	$$ = $1;
+}
+|
+{
+	$$ = NULL;
+}
+
+%%
+
+void parse_events_error(char const *msg __used)
+{
+}
-- 
1.7.4


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

* [PATCHv2 2/2] perf, tool: Add more automated tests for event parsing
  2011-12-20 10:29     ` [PATCHv2 0/2] perf tool: " Jiri Olsa
  2011-12-20 10:29       ` [PATCHv2 1/2] perf, tool: Add " Jiri Olsa
@ 2011-12-20 10:29       ` Jiri Olsa
  1 sibling, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-20 10:29 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding automated tests for event parsing to include testing
for modifier and ',' operator.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c |  276 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 275 insertions(+), 1 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 6173f78..c45e2ae 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -603,7 +603,7 @@ out_free_threads:
 
 #define TEST_ASSERT_VAL(text, cond) \
 do { \
-	if (!cond) { \
+	if (!(cond)) { \
 		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
 		return -1; \
 	} \
@@ -649,6 +649,34 @@ static int test__checkevent_raw(struct perf_evlist *evlist)
 	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 config", 0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config2);
+	return 0;
+}
+
+static int test__checkevent_raw_config1(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 config", 2 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config2);
+	return 0;
+}
+
+static int test__checkevent_raw_config12(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 config", 2 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config", 3 == evsel->attr.config2);
 	return 0;
 }
 
@@ -759,6 +787,196 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
 	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 == 2);
+
+	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_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 config", 2 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config", 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 struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -777,6 +995,14 @@ static struct test__event_st {
 		.check = test__checkevent_raw,
 	},
 	{
+		.name  = "r1-2",
+		.check = test__checkevent_raw_config1,
+	},
+	{
+		.name  = "r1-2-3",
+		.check = test__checkevent_raw_config12,
+	},
+	{
 		.name  = "1:1",
 		.check = test__checkevent_numeric,
 	},
@@ -808,6 +1034,54 @@ static struct test__event_st {
 		.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  = "r1: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:kpp",
+		.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  = "r1-2,syscalls:sys_enter_open:k,1:1:hp",
+		.check = test__checkevent_list,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
-- 
1.7.4


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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-16 14:03     ` Peter Zijlstra
@ 2011-12-20 10:31       ` Jiri Olsa
  2011-12-20 10:47         ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2011-12-20 10:31 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Fri, Dec 16, 2011 at 03:03:16PM +0100, Peter Zijlstra wrote:
> On Fri, 2011-12-16 at 15:02 +0100, Peter Zijlstra wrote:
> > > event_tracepoint:       PE_NAME_TP ':' PE_NAME_TP modifier
> > > event_raw:              PE_SEP_RAW PE_VALUE modifier
> > > event_numeric:          PE_VALUE ':' PE_VALUE modifier
> > > event_symbolic:         PE_NAME_SYM modifier
> > > event_generic_hw:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier |
> > >                         PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier |
> > >                         PE_NAME_CACHE_TYPE modifier
> > > event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
> > > event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
> > > modifier:               PE_MODIFIER_EVENT | empty
> > 
> > This isn't complete, we need means of specifying
> > perf_event_attr::config[12] when specifying a raw event. 
> 
> Also, it might make sense to think about how to specify sysfs events
> (which don't exist yet).

any idea/details/specifics how they might look like? ;)

jirka

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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-20 10:31       ` Jiri Olsa
@ 2011-12-20 10:47         ` Peter Zijlstra
  2011-12-20 11:30           ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2011-12-20 10:47 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Tue, 2011-12-20 at 11:31 +0100, Jiri Olsa wrote:
> On Fri, Dec 16, 2011 at 03:03:16PM +0100, Peter Zijlstra wrote:
> > On Fri, 2011-12-16 at 15:02 +0100, Peter Zijlstra wrote:
> > > > event_tracepoint:       PE_NAME_TP ':' PE_NAME_TP modifier
> > > > event_raw:              PE_SEP_RAW PE_VALUE modifier
> > > > event_numeric:          PE_VALUE ':' PE_VALUE modifier
> > > > event_symbolic:         PE_NAME_SYM modifier
> > > > event_generic_hw:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier |
> > > >                         PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier |
> > > >                         PE_NAME_CACHE_TYPE modifier
> > > > event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
> > > > event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
> > > > modifier:               PE_MODIFIER_EVENT | empty
> > > 
> > > This isn't complete, we need means of specifying
> > > perf_event_attr::config[12] when specifying a raw event. 
> > 
> > Also, it might make sense to think about how to specify sysfs events
> > (which don't exist yet).
> 
> any idea/details/specifics how they might look like? ;)

The current idea is that they'd live in a place like:

  /sys/bus/event_source/devices/$pmu/events/$event

and when you read them they contain a full event_raw style string so you
could do things like:

  perf record -e `cat $sysfsfile` or so

(or maybe without the 'r' prefix).

The idea was to have some $pmu:$event like syntax, but seeing that ':'
is already used quite a lot, there's maybe a more suitable separator.
Maybe '/' would do, yielding things like cpu/instructions.

Then again, it might make sense to restructure the syntax without
considerations for the status quo and see if we can come up with
something a little more consistent, the above event_* things are quite a
hodge podge, syntax wise.

While I appreciate that they are the result of organic growth, it
doesn't mean we shouldn't try and restructure stuff once in a while when
it makes sense.

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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-20 10:47         ` Peter Zijlstra
@ 2011-12-20 11:30           ` Peter Zijlstra
  2011-12-20 11:39             ` Peter Zijlstra
  2011-12-22 19:32             ` [PATCH 1/3] perf, tool: Add " Vince Weaver
  0 siblings, 2 replies; 91+ messages in thread
From: Peter Zijlstra @ 2011-12-20 11:30 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Tue, 2011-12-20 at 11:47 +0100, Peter Zijlstra wrote:

> > any idea/details/specifics how they might look like? ;)
> 
> The current idea is that they'd live in a place like:
> 
>   /sys/bus/event_source/devices/$pmu/events/$event
> 
> and when you read them they contain a full event_raw style string so you
> could do things like:
> 
>   perf record -e `cat $sysfsfile` or so
> 
> (or maybe without the 'r' prefix).
> 
> The idea was to have some $pmu:$event like syntax, but seeing that ':'
> is already used quite a lot, there's maybe a more suitable separator.
> Maybe '/' would do, yielding things like cpu/instructions.
> 
> Then again, it might make sense to restructure the syntax without
> considerations for the status quo and see if we can come up with
> something a little more consistent, the above event_* things are quite a
> hodge podge, syntax wise.
> 
> While I appreciate that they are the result of organic growth, it
> doesn't mean we shouldn't try and restructure stuff once in a while when
> it makes sense.

There's also the raw event format idea, where

 /sys/bus/event_source/devices/$pmu/format

contains a syntax description on how to construct raw events, for intel
(!p4) it would be something as simple as a bitfield definition:

event	config-0:7
umask	config-8:15
usr	config-16
os	config-17
edge	config-18
any	config-21
inv	config-23
cmask	config-24:31

nhm-dmnd_data_rd	config1-0
nhm-dmnd_rfo		config1-1
nhm-dmnd_ifetch		config1-2
...

(the real syntax will likely be a little more complex in order to be
able to express the various other architectures their raw input format).

This would allow us to write things like:

 perf record -e cpu/event=0x34,umask=0x01,inv,cmask=2

or to give an offcore example:

 perf record -e
cpu/offcore,nhm-dmnd_data_rd,nhm-non_dram,nhm-remote_dram,nhm-local_dram

Where cpu/events/offcore would contain: 0x01b7 to fill out config.

We should also extend this to allow per event setting of the period by
adding a ,period=10000 or so.

 perf record -e cpu/cycles,period=100000

should then give us a cycle counter with a fixed period of .1M cycles.

I think there's currently means to provide this period, but I don't
actually know the syntax for it.

But note, the above again uses ',' as separator, which will be much
confused with the group idea you already proposed. So we need some
consideration on how we all want to express this.




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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-20 11:30           ` Peter Zijlstra
@ 2011-12-20 11:39             ` Peter Zijlstra
  2011-12-21 16:16               ` new syntax for perf event Jiri Olsa
  2011-12-22 19:32             ` [PATCH 1/3] perf, tool: Add " Vince Weaver
  1 sibling, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2011-12-20 11:39 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Tue, 2011-12-20 at 12:30 +0100, Peter Zijlstra wrote:
> event   config-0:7
> umask   config-8:15
> usr     config-16
> os      config-17
> edge    config-18
> any     config-21
> inv     config-23
> cmask   config-24:31
> 
> nhm-dmnd_data_rd        config1-0
> nhm-dmnd_rfo            config1-1
> nhm-dmnd_ifetch         config1-2
> ...
> 
> (the real syntax will likely be a little more complex in order to be
> able to express the various other architectures their raw input format). 

for instance AMD would need:

event	config-0:7,32-35
guest	config-40
host	config-41

(assuming you read that as a mask from LSB to MSB)

And I still haven't actually read how the P4 works so I can't help out
there.

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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-15 15:30 ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Jiri Olsa
  2011-12-16 14:02   ` Peter Zijlstra
@ 2011-12-20 17:37   ` Arnaldo Carvalho de Melo
  2011-12-21  9:55     ` Jiri Olsa
  1 sibling, 1 reply; 91+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-12-20 17:37 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, cjashfor, linux-kernel

Em Thu, Dec 15, 2011 at 04:30:37PM +0100, Jiri Olsa escreveu:
> Changing event parsing to use flex/bison parse generator.
> The event syntax stays as it is.

Seems really cool, using the right tool for the task, comments:

. Can we avoid more globals? Like that __event_list one.
. All those ABORT_ON do what? die() like stuff? /me googles YYABORT...

----
YYABORT
Return immediately with value 1 (to report failure).
----

	Ok, so it gets propagated back and hopefully the we die() just
back at main() in tools/perf/perf.c, right?

. make help | perf

	Then running one of those targets and trying to build perf still
works? I guess so, but better check that.

	Having it added to some new "make perf-test" that does that +
'perf test' too would get you brownie points. Leave it for later/someone
else if you're busy/not looking for more work, of course 8-)

. We have some tests to parse events in 'perf test', right? From the top
of my head it was even ya that did that, guess those are ok/improved
(still need to look at the other patches in the backlog).

- Arnaldo
 
> grammar description:
> 
> events: events ',' event | event
> 
> event:  event_tracepoint |
>         event_raw |
>         event_numeric |
>         event_symbolic |
>         event_generic_hw |
>         event_breakpoint
> 
> event_tracepoint:       PE_NAME_TP ':' PE_NAME_TP modifier
> event_raw:              PE_SEP_RAW PE_VALUE modifier
> event_numeric:          PE_VALUE ':' PE_VALUE modifier
> event_symbolic:         PE_NAME_SYM modifier
> event_generic_hw:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier |
>                         PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier |
>                         PE_NAME_CACHE_TYPE modifier
> event_breakpoint:       PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
> event_breakpoint_type:  PE_MODIFIER_BPTYPE | empty
> modifier:               PE_MODIFIER_EVENT | empty
> 
> PE_NAME_SYM:            cpu-cycles|cycles                              |
>                         stalled-cycles-frontend|idle-cycles-frontend   |
>                         stalled-cycles-backend|idle-cycles-backend     |
>                         instructions                                   |
>                         cache-references                               |
>                         cache-misses                                   |
>                         branch-instructions|branches                   |
>                         branch-misses                                  |
>                         bus-cycles                                     |
>                         cpu-clock                                      |
>                         task-clock                                     |
>                         page-faults|faults                             |
>                         minor-faults                                   |
>                         major-faults                                   |
>                         context-switches|cs                            |
>                         cpu-migrations|migrations                      |
>                         alignment-faults                               |
>                         emulation-faults
> 
> PE_NAME_CACHE_TYPE:     L1-dcache|l1-d|l1d|L1-data             |
>                         L1-icache|l1-i|l1i|L1-instruction      |
>                         LLC|L2                                 |
>                         dTLB|d-tlb|Data-TLB                    |
>                         iTLB|i-tlb|Instruction-TLB             |
>                         branch|branches|bpu|btb|bpc            |
>                         node
> 
> PE_NAME_CACHE_OP_RESULT: load|loads|read                       |
>                         store|stores|write                     |
>                         prefetch|prefetches                    |
>                         speculative-read|speculative-load      |
>                         refs|Reference|ops|access              |
>                         misses|miss
> 
> PE_SEP_RAW:             'r'
> PE_SEP_BP:              'mem'
> PE_MODIFIER_EVENT:      :[ukhp]{1,2}
> PE_MODIFIER_BPTYPE:     :[rwx]{1,3}
> PE_NAME_TP:             [a-zA-Z_*?]+
> PE_VALUE:               number
> 
> Added flex/bison files for event grammar parsing. Added
> flex/bison Makefile rules plus few special dependencies.
> 
> Signed-off-by: Jiri Olsa <jolsa@redhat.com>
> ---
>  tools/perf/Makefile                  |   21 ++
>  tools/perf/util/parse-events-bison.y |  119 +++++++++
>  tools/perf/util/parse-events-flex.l  |  111 ++++++++
>  tools/perf/util/parse-events.c       |  459 +++++++++++-----------------------
>  tools/perf/util/parse-events.h       |    9 +
>  5 files changed, 411 insertions(+), 308 deletions(-)
>  create mode 100644 tools/perf/util/parse-events-bison.y
>  create mode 100644 tools/perf/util/parse-events-flex.l
> 
> diff --git a/tools/perf/Makefile b/tools/perf/Makefile
> index ac86d67..ef6b621 100644
> --- a/tools/perf/Makefile
> +++ b/tools/perf/Makefile
> @@ -47,6 +47,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
>  
>  CC = $(CROSS_COMPILE)gcc
>  AR = $(CROSS_COMPILE)ar
> +FLEX = $(CROSS_COMPILE)flex
> +BISON= $(CROSS_COMPILE)bison
>  
>  # Additional ARCH settings for x86
>  ifeq ($(ARCH),i386)
> @@ -341,6 +343,8 @@ LIB_OBJS += $(OUTPUT)util/session.o
>  LIB_OBJS += $(OUTPUT)util/thread.o
>  LIB_OBJS += $(OUTPUT)util/thread_map.o
>  LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
> +LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
> +LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
>  LIB_OBJS += $(OUTPUT)util/trace-event-read.o
>  LIB_OBJS += $(OUTPUT)util/trace-event-info.o
>  LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
> @@ -627,6 +631,8 @@ ifndef V
>  	QUIET_LINK     = @echo '   ' LINK $@;
>  	QUIET_MKDIR    = @echo '   ' MKDIR $@;
>  	QUIET_GEN      = @echo '   ' GEN $@;
> +	QUIET_FLEX     = @echo '   ' FLEX $@;
> +	QUIET_BISON    = @echo '   ' BISON $@;
>  endif
>  endif
>  
> @@ -713,6 +719,10 @@ $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
>  	$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
>  $(OUTPUT)%.o: %.S
>  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
> +$(OUTPUT)%.c: %.l
> +	$(QUIET_FLEX)$(FLEX) --header-file=$*.h -t $< > $@
> +$(OUTPUT)%.c: %.y
> +	$(QUIET_BISON)$(BISON) -v $< -d -o $@
>  
>  $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
>  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
> @@ -739,6 +749,16 @@ $(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
>  $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
>  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
>  
> +
> +.SECONDARY: util/parse-events-flex.c util/parse-events-flex.h
> +.SECONDARY: util/parse-events-bison.c util/parse-events-bison.h
> +
> +util/parse-events.o: util/parse-events-flex.c
> +util/parse-events-flex.c: util/parse-events-bison.c
> +
> +$(OUTPUT)util/parse-events-flex.o: util/parse-events-flex.c $(OUTPUT)PERF-CFLAGS
> +	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
> +
>  $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
>  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
>  
> @@ -910,6 +930,7 @@ clean:
>  	$(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
>  	$(RM) $(ALL_PROGRAMS) perf
>  	$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
> +	$(RM) util/parse-events-flex.[ch] util/parse-events-bison.[cho]*
>  	$(MAKE) -C Documentation/ clean
>  	$(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
>  	$(python-clean)
> diff --git a/tools/perf/util/parse-events-bison.y b/tools/perf/util/parse-events-bison.y
> new file mode 100644
> index 0000000..403cbf6
> --- /dev/null
> +++ b/tools/perf/util/parse-events-bison.y
> @@ -0,0 +1,119 @@
> +
> +%name-prefix "parse_events_"
> +
> +%{
> +
> +#define YYDEBUG 1
> +
> +#include <linux/compiler.h>
> +#include "types.h"
> +#include "util.h"
> +#include "parse-events.h"
> +
> +extern int parse_events_lex (void);
> +
> +#define ABORT_ON(val) \
> +do { \
> +	if (val) \
> +		YYABORT; \
> +} while (0)
> +
> +%}
> +
> +%token PE_VALUE
> +%token PE_MODIFIER_BPTYPE PE_MODIFIER_EVENT
> +%token PE_NAME_TP PE_NAME_SYM
> +%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
> +%token PE_SEP_RAW PE_SEP_BP
> +%token PE_ERROR
> +%type <l> PE_VALUE
> +%type <s> PE_NAME_TP
> +%type <s> PE_NAME_SYM
> +%type <s> PE_NAME_CACHE_TYPE
> +%type <s> PE_NAME_CACHE_OP_RESULT
> +%type <s> PE_MODIFIER_EVENT
> +%type <s> modifier
> +%type <s> PE_MODIFIER_BPTYPE
> +%type <s> event_breakpoint_type
> +
> +%union
> +{
> +	char *s;
> +	long l;
> +}
> +
> +%%
> +
> +events: events ',' event | event
> +
> +event:  event_tracepoint |
> +	event_raw |
> +	event_numeric |
> +	event_symbolic |
> +	event_generic_hw |
> +	event_breakpoint
> +
> +event_tracepoint: PE_NAME_TP ':' PE_NAME_TP modifier
> +{
> +	ABORT_ON(parse_events_add_tracepoint($1, $3, $4));
> +}
> +
> +event_raw: PE_SEP_RAW PE_VALUE modifier
> +{
> +	ABORT_ON(parse_events_add_raw($2, $3));
> +}
> +
> +event_numeric: PE_VALUE ':' PE_VALUE modifier
> +{
> +	ABORT_ON(parse_events_add_numeric($1, $3, $4));
> +}
> +
> +event_symbolic: PE_NAME_SYM modifier
> +{
> +	ABORT_ON(parse_events_add_symbolic($1, $2));
> +}
> +
> +event_generic_hw:
> +PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT modifier
> +{
> +	ABORT_ON(parse_events_add_generic_hw($1, $3, $5, $6));
> +}
> +|
> +PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT modifier
> +{
> +	ABORT_ON(parse_events_add_generic_hw($1, $3, NULL, $4));
> +}
> +|
> +PE_NAME_CACHE_TYPE modifier
> +{
> +	ABORT_ON(parse_events_add_generic_hw($1, NULL, NULL, $2));
> +}
> +
> +event_breakpoint: PE_SEP_BP ':' PE_VALUE event_breakpoint_type modifier
> +{
> +	ABORT_ON(parse_events_add_breakpoint((void *) $3, $4, $5))
> +}
> +
> +event_breakpoint_type: PE_MODIFIER_BPTYPE
> +{
> +	$$ = $1
> +}
> +|
> +{
> +	$$ = NULL;
> +}
> +
> +modifier: PE_MODIFIER_EVENT
> +{
> +	$$ = $1;
> +}
> +|
> +{
> +	$$ = NULL;
> +}
> +
> +%%
> +
> +void parse_events_error(char const *msg __used)
> +{
> +}
> diff --git a/tools/perf/util/parse-events-flex.l b/tools/perf/util/parse-events-flex.l
> new file mode 100644
> index 0000000..84b9b0e
> --- /dev/null
> +++ b/tools/perf/util/parse-events-flex.l
> @@ -0,0 +1,111 @@
> +
> +%option prefix="parse_events_"
> +
> +%{
> +#include <errno.h>
> +#include "parse-events-bison.h"
> +
> +enum {
> +	VALUE_DEC,
> +	VALUE_HEX,
> +};
> +
> +static int value(int base)
> +{
> +	long num;
> +
> +	errno = 0;
> +	num = strtol(parse_events_text, NULL, base);
> +	if (errno)
> +		return PE_ERROR;
> +
> +	parse_events_lval.l = num;
> +	return PE_VALUE;
> +}
> +
> +static int __str(char *s, int token)
> +{
> +	parse_events_lval.s = strdup(s);
> +	return token;
> +}
> +
> +static int str(int token)
> +{
> +	return __str(parse_events_text, token);
> +}
> +
> +static int mod(int token)
> +{
> +	return __str(parse_events_text + 1, token);
> +}
> +
> +%}
> +
> +num_dec		[0-9]+
> +num_hex		0x[a-fA-F0-9]+
> +name_tp		[a-zA-Z_*?]+
> +
> +%x BP
> +
> +%%
> +
> +cpu-cycles|cycles				|
> +stalled-cycles-frontend|idle-cycles-frontend	|
> +stalled-cycles-backend|idle-cycles-backend	|
> +instructions					|
> +cache-references				|
> +cache-misses					|
> +branch-instructions|branches			|
> +branch-misses					|
> +bus-cycles					|
> +cpu-clock					|
> +task-clock					|
> +page-faults|faults				|
> +minor-faults					|
> +major-faults					|
> +context-switches|cs				|
> +cpu-migrations|migrations			|
> +alignment-faults				|
> +emulation-faults				{ return str(PE_NAME_SYM); }
> +
> +L1-dcache|l1-d|l1d|L1-data		|
> +L1-icache|l1-i|l1i|L1-instruction	|
> +LLC|L2					|
> +dTLB|d-tlb|Data-TLB			|
> +iTLB|i-tlb|Instruction-TLB		|
> +branch|branches|bpu|btb|bpc		|
> +node					{ return str(PE_NAME_CACHE_TYPE); }
> +
> +load|loads|read				|
> +store|stores|write			|
> +prefetch|prefetches			|
> +speculative-read|speculative-load	|
> +refs|Reference|ops|access		|
> +misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
> +
> +{num_dec}		{ return value(10); }
> +{num_hex}		{ return value(16); }
> +
> +r			{ return PE_SEP_RAW; }
> +
> +mem			{ BEGIN(BP); return PE_SEP_BP; }
> +<BP>:[rwx]{1,3}		{ return mod(PE_MODIFIER_BPTYPE); }
> +<BP>:[ukhp]{1,2}	{ return mod(PE_MODIFIER_EVENT); }
> +<BP>:			{ return ':'; }
> +<BP>{num_dec}		{ return value(10); }
> +<BP>{num_hex}		{ return value(16); }
> +<BP><<EOF>>		{ BEGIN(INITIAL); }
> +<BP>.			{ BEGIN(INITIAL); }
> +
> +:[ukhp]{1,2}		{ return mod(PE_MODIFIER_EVENT); }
> +{name_tp}		{ return str(PE_NAME_TP); }
> +-			{ return '-'; }
> +,			{ return ','; }
> +:			{ return ':'; }
> +
> +%%
> +
> +int parse_events_wrap(void)
> +{
> +	return 1;
> +}
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index 586ab3f..b9c4189 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -11,6 +11,9 @@
>  #include "cache.h"
>  #include "header.h"
>  #include "debugfs.h"
> +#include "parse-events-flex.h"
> +
> +#define MAX_NAME_LEN 100
>  
>  struct event_symbol {
>  	u8		type;
> @@ -19,11 +22,9 @@ struct event_symbol {
>  	const char	*alias;
>  };
>  
> -enum event_result {
> -	EVT_FAILED,
> -	EVT_HANDLED,
> -	EVT_HANDLED_ALL
> -};
> +int parse_events_parse(void);
> +
> +static struct perf_evlist *__evlist;
>  
>  #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
>  #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
> @@ -352,7 +353,31 @@ const char *__event_name(int type, u64 config)
>  	return "unknown";
>  }
>  
> -static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
> +static void
> +parse_event_modifier(char *mod, struct perf_event_attr *attr);
> +
> +static int add_event(struct perf_event_attr *attr, char *name, char *mod)
> +{
> +	struct perf_evsel *evsel;
> +	int len = strlen(name);
> +
> +	parse_event_modifier(mod, attr);
> +
> +	evsel = perf_evsel__new(attr, __evlist->nr_entries);
> +	if (!evsel)
> +		return -ENOMEM;
> +
> +	perf_evlist__add(__evlist, evsel);
> +
> +	evsel->name = zalloc(len);
> +	if (!evsel->name)
> +		return -ENOMEM;
> +
> +	strncpy(evsel->name, name, len);
> +	return 0;
> +}
> +
> +static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
>  {
>  	int i, j;
>  	int n, longest = -1;
> @@ -360,58 +385,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
>  	for (i = 0; i < size; i++) {
>  		for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
>  			n = strlen(names[i][j]);
> -			if (n > longest && !strncasecmp(*str, names[i][j], n))
> +			if (n > longest && !strncasecmp(str, names[i][j], n))
>  				longest = n;
>  		}
> -		if (longest > 0) {
> -			*str += longest;
> +		if (longest > 0)
>  			return i;
> -		}
>  	}
>  
>  	return -1;
>  }
>  
> -static enum event_result
> -parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
> +int parse_events_add_generic_hw(char *type, char *op_result1, char *op_result2,
> +				char *mod)
>  {
> -	const char *s = *str;
> +	struct perf_event_attr attr;
> +	char name[MAX_NAME_LEN];
>  	int cache_type = -1, cache_op = -1, cache_result = -1;
> +	char *op_result[2] = { op_result1, op_result2 };
> +	int i, n;
>  
> -	cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
>  	/*
>  	 * No fallback - if we cannot get a clear cache type
>  	 * then bail out:
>  	 */
> +	cache_type = parse_aliases(type, hw_cache,
> +				   PERF_COUNT_HW_CACHE_MAX);
>  	if (cache_type == -1)
> -		return EVT_FAILED;
> +		return -EINVAL;
>  
> -	while ((cache_op == -1 || cache_result == -1) && *s == '-') {
> -		++s;
> +	n = snprintf(name, MAX_NAME_LEN, "%s", type);
> +
> +	for (i = 0; (i < 2) && (op_result[i]); i++) {
> +		char *str = op_result[i];
> +
> +		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
>  
>  		if (cache_op == -1) {
> -			cache_op = parse_aliases(&s, hw_cache_op,
> -						PERF_COUNT_HW_CACHE_OP_MAX);
> +			cache_op = parse_aliases(str, hw_cache_op,
> +						 PERF_COUNT_HW_CACHE_OP_MAX);
>  			if (cache_op >= 0) {
>  				if (!is_cache_op_valid(cache_type, cache_op))
> -					return EVT_FAILED;
> +					return -EINVAL;
>  				continue;
>  			}
>  		}
>  
>  		if (cache_result == -1) {
> -			cache_result = parse_aliases(&s, hw_cache_result,
> +			cache_result = parse_aliases(str, hw_cache_result,
>  						PERF_COUNT_HW_CACHE_RESULT_MAX);
>  			if (cache_result >= 0)
>  				continue;
>  		}
> -
> -		/*
> -		 * Can't parse this as a cache op or result, so back up
> -		 * to the '-'.
> -		 */
> -		--s;
> -		break;
>  	}
>  
>  	/*
> @@ -426,20 +450,16 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
>  	if (cache_result == -1)
>  		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
>  
> -	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
> -	attr->type = PERF_TYPE_HW_CACHE;
> -
> -	*str = s;
> -	return EVT_HANDLED;
> +	memset(&attr, 0, sizeof(attr));
> +	attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
> +	attr.type = PERF_TYPE_HW_CACHE;
> +	return add_event(&attr, name, mod);
>  }
>  
> -static enum event_result
> -parse_single_tracepoint_event(char *sys_name,
> -			      const char *evt_name,
> -			      unsigned int evt_length,
> -			      struct perf_event_attr *attr,
> -			      const char **strp)
> +static int add_tracepoint(char *sys_name, char *evt_name, char *mod)
>  {
> +	struct perf_event_attr attr;
> +	char name[MAX_NAME_LEN];
>  	char evt_path[MAXPATHLEN];
>  	char id_buf[4];
>  	u64 id;
> @@ -450,130 +470,78 @@ parse_single_tracepoint_event(char *sys_name,
>  
>  	fd = open(evt_path, O_RDONLY);
>  	if (fd < 0)
> -		return EVT_FAILED;
> +		return -1;
>  
>  	if (read(fd, id_buf, sizeof(id_buf)) < 0) {
>  		close(fd);
> -		return EVT_FAILED;
> +		return -1;
>  	}
>  
>  	close(fd);
>  	id = atoll(id_buf);
> -	attr->config = id;
> -	attr->type = PERF_TYPE_TRACEPOINT;
> -	*strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
> -
> -	attr->sample_type |= PERF_SAMPLE_RAW;
> -	attr->sample_type |= PERF_SAMPLE_TIME;
> -	attr->sample_type |= PERF_SAMPLE_CPU;
>  
> -	attr->sample_period = 1;
> +	memset(&attr, 0, sizeof(attr));
> +	attr.config = id;
> +	attr.type = PERF_TYPE_TRACEPOINT;
> +	attr.sample_type |= PERF_SAMPLE_RAW;
> +	attr.sample_type |= PERF_SAMPLE_TIME;
> +	attr.sample_type |= PERF_SAMPLE_CPU;
> +	attr.sample_period = 1;
>  
> -
> -	return EVT_HANDLED;
> +	snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
> +	return add_event(&attr, name, mod);
>  }
>  
> -/* sys + ':' + event + ':' + flags*/
> -#define MAX_EVOPT_LEN	(MAX_EVENT_LENGTH * 2 + 2 + 128)
> -static enum event_result
> -parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
> -				const char *evt_exp, char *flags)
> +static int add_tracepoint_multi(char *sys_name, char *evt_name, char *mod)
>  {
>  	char evt_path[MAXPATHLEN];
>  	struct dirent *evt_ent;
>  	DIR *evt_dir;
> +	int ret = 0;
>  
>  	snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
>  	evt_dir = opendir(evt_path);
> -
>  	if (!evt_dir) {
>  		perror("Can't open event dir");
> -		return EVT_FAILED;
> +		return -1;
>  	}
>  
> -	while ((evt_ent = readdir(evt_dir))) {
> -		char event_opt[MAX_EVOPT_LEN + 1];
> -		int len;
> -
> +	while (!ret && (evt_ent = readdir(evt_dir))) {
>  		if (!strcmp(evt_ent->d_name, ".")
>  		    || !strcmp(evt_ent->d_name, "..")
>  		    || !strcmp(evt_ent->d_name, "enable")
>  		    || !strcmp(evt_ent->d_name, "filter"))
>  			continue;
>  
> -		if (!strglobmatch(evt_ent->d_name, evt_exp))
> +		if (!strglobmatch(evt_ent->d_name, evt_name))
>  			continue;
>  
> -		len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
> -			       evt_ent->d_name, flags ? ":" : "",
> -			       flags ?: "");
> -		if (len < 0)
> -			return EVT_FAILED;
> -
> -		if (parse_events(evlist, event_opt, 0))
> -			return EVT_FAILED;
> +		ret = add_tracepoint(sys_name, evt_ent->d_name, mod);
>  	}
>  
> -	return EVT_HANDLED_ALL;
> +	return ret;
>  }
>  
> -static enum event_result
> -parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
> -		       struct perf_event_attr *attr)
> +int parse_events_add_tracepoint(char *sys, char *event, char *mod)
>  {
> -	const char *evt_name;
> -	char *flags = NULL, *comma_loc;
> -	char sys_name[MAX_EVENT_LENGTH];
> -	unsigned int sys_length, evt_length;
> -
> -	if (debugfs_valid_mountpoint(tracing_events_path))
> -		return 0;
> +	int ret;
>  
> -	evt_name = strchr(*strp, ':');
> -	if (!evt_name)
> -		return EVT_FAILED;
> -
> -	sys_length = evt_name - *strp;
> -	if (sys_length >= MAX_EVENT_LENGTH)
> -		return 0;
> +	ret = debugfs_valid_mountpoint(tracing_events_path);
> +	if (ret)
> +		return ret;
>  
> -	strncpy(sys_name, *strp, sys_length);
> -	sys_name[sys_length] = '\0';
> -	evt_name = evt_name + 1;
> -
> -	comma_loc = strchr(evt_name, ',');
> -	if (comma_loc) {
> -		/* take the event name up to the comma */
> -		evt_name = strndup(evt_name, comma_loc - evt_name);
> -	}
> -	flags = strchr(evt_name, ':');
> -	if (flags) {
> -		/* split it out: */
> -		evt_name = strndup(evt_name, flags - evt_name);
> -		flags++;
> -	}
> -
> -	evt_length = strlen(evt_name);
> -	if (evt_length >= MAX_EVENT_LENGTH)
> -		return EVT_FAILED;
> -	if (strpbrk(evt_name, "*?")) {
> -		*strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
> -		return parse_multiple_tracepoint_event(evlist, sys_name,
> -						       evt_name, flags);
> -	} else {
> -		return parse_single_tracepoint_event(sys_name, evt_name,
> -						     evt_length, attr, strp);
> -	}
> +	return strpbrk(event, "*?") ?
> +	       add_tracepoint_multi(sys, event, mod) :
> +	       add_tracepoint(sys, event, mod);
>  }
>  
> -static enum event_result
> -parse_breakpoint_type(const char *type, const char **strp,
> -		      struct perf_event_attr *attr)
> +static int
> +parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
>  {
>  	int i;
>  
>  	for (i = 0; i < 3; i++) {
> -		if (!type[i])
> +		if (!type || !type[i])
>  			break;
>  
>  		switch (type[i]) {
> @@ -587,65 +555,40 @@ parse_breakpoint_type(const char *type, const char **strp,
>  			attr->bp_type |= HW_BREAKPOINT_X;
>  			break;
>  		default:
> -			return EVT_FAILED;
> +			return -EINVAL;
>  		}
>  	}
> +
>  	if (!attr->bp_type) /* Default */
>  		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
>  
> -	*strp = type + i;
> -
> -	return EVT_HANDLED;
> +	return 0;
>  }
>  
> -static enum event_result
> -parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
> +int parse_events_add_breakpoint(void *ptr, char *type, char *mod)
>  {
> -	const char *target;
> -	const char *type;
> -	char *endaddr;
> -	u64 addr;
> -	enum event_result err;
> -
> -	target = strchr(*strp, ':');
> -	if (!target)
> -		return EVT_FAILED;
> -
> -	if (strncmp(*strp, "mem", target - *strp) != 0)
> -		return EVT_FAILED;
> -
> -	target++;
> -
> -	addr = strtoull(target, &endaddr, 0);
> -	if (target == endaddr)
> -		return EVT_FAILED;
> -
> -	attr->bp_addr = addr;
> -	*strp = endaddr;
> +	struct perf_event_attr attr;
> +	char name[MAX_NAME_LEN];
>  
> -	type = strchr(target, ':');
> +	memset(&attr, 0, sizeof(attr));
> +	attr.bp_addr = (u64) ptr;
>  
> -	/* If no type is defined, just rw as default */
> -	if (!type) {
> -		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
> -	} else {
> -		err = parse_breakpoint_type(++type, strp, attr);
> -		if (err == EVT_FAILED)
> -			return EVT_FAILED;
> -	}
> +	if (parse_breakpoint_type(type, &attr))
> +		return -EINVAL;
>  
>  	/*
>  	 * We should find a nice way to override the access length
>  	 * Provide some defaults for now
>  	 */
> -	if (attr->bp_type == HW_BREAKPOINT_X)
> -		attr->bp_len = sizeof(long);
> +	if (attr.bp_type == HW_BREAKPOINT_X)
> +		attr.bp_len = sizeof(long);
>  	else
> -		attr->bp_len = HW_BREAKPOINT_LEN_4;
> +		attr.bp_len = HW_BREAKPOINT_LEN_4;
>  
> -	attr->type = PERF_TYPE_BREAKPOINT;
> +	attr.type = PERF_TYPE_BREAKPOINT;
>  
> -	return EVT_HANDLED;
> +	snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
> +	return add_event(&attr, name, mod);
>  }
>  
>  static int check_events(const char *str, unsigned int i)
> @@ -665,85 +608,59 @@ static int check_events(const char *str, unsigned int i)
>  	return 0;
>  }
>  
> -static enum event_result
> -parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
> +int parse_events_add_symbolic(char *symbol, char *mod)
>  {
> -	const char *str = *strp;
> +	struct perf_event_attr attr;
> +	char name[MAX_NAME_LEN];
>  	unsigned int i;
> -	int n;
>  
>  	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
> -		n = check_events(str, i);
> -		if (n > 0) {
> -			attr->type = event_symbols[i].type;
> -			attr->config = event_symbols[i].config;
> -			*strp = str + n;
> -			return EVT_HANDLED;
> -		}
> +		if (!check_events(symbol, i))
> +			continue;
> +		memset(&attr, 0, sizeof(attr));
> +		attr.type = event_symbols[i].type;
> +		attr.config = event_symbols[i].config;
> +		snprintf(name, MAX_NAME_LEN, "%s", event_symbols[i].symbol);
> +		return add_event(&attr, name, mod);
>  	}
> -	return EVT_FAILED;
> +
> +	return -EINVAL;
>  }
>  
> -static enum event_result
> -parse_raw_event(const char **strp, struct perf_event_attr *attr)
> +int parse_events_add_raw(long code, char *mod)
>  {
> -	const char *str = *strp;
> -	u64 config;
> -	int n;
> +	struct perf_event_attr attr;
> +	char name[MAX_NAME_LEN];
>  
> -	if (*str != 'r')
> -		return EVT_FAILED;
> -	n = hex2u64(str + 1, &config);
> -	if (n > 0) {
> -		const char *end = str + n + 1;
> -		if (*end != '\0' && *end != ',' && *end != ':')
> -			return EVT_FAILED;
> -
> -		*strp = end;
> -		attr->type = PERF_TYPE_RAW;
> -		attr->config = config;
> -		return EVT_HANDLED;
> -	}
> -	return EVT_FAILED;
> +	memset(&attr, 0, sizeof(attr));
> +	attr.type = PERF_TYPE_RAW;
> +	attr.config = code;
> +
> +	snprintf(name, MAX_NAME_LEN, "r%lx", code);
> +	return add_event(&attr, name, mod);
>  }
>  
> -static enum event_result
> -parse_numeric_event(const char **strp, struct perf_event_attr *attr)
> +int parse_events_add_numeric(long type, long config, char *mod)
>  {
> -	const char *str = *strp;
> -	char *endp;
> -	unsigned long type;
> -	u64 config;
> -
> -	type = strtoul(str, &endp, 0);
> -	if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
> -		str = endp + 1;
> -		config = strtoul(str, &endp, 0);
> -		if (endp > str) {
> -			attr->type = type;
> -			attr->config = config;
> -			*strp = endp;
> -			return EVT_HANDLED;
> -		}
> -	}
> -	return EVT_FAILED;
> +	struct perf_event_attr attr;
> +	char name[MAX_NAME_LEN];
> +
> +	memset(&attr, 0, sizeof(attr));
> +	attr.type = type;
> +	attr.config = config;
> +
> +	snprintf(name, MAX_NAME_LEN, "%lx:%lx", type, config);
> +	return add_event(&attr, name, mod);
>  }
>  
> -static int
> -parse_event_modifier(const char **strp, struct perf_event_attr *attr)
> +static void
> +parse_event_modifier(char *str, struct perf_event_attr *attr)
>  {
> -	const char *str = *strp;
>  	int exclude = 0;
>  	int eu = 0, ek = 0, eh = 0, precise = 0;
>  
> -	if (!*str)
> -		return 0;
> -
> -	if (*str == ',')
> -		return 0;
> -
> -	if (*str++ != ':')
> -		return -1;
> +	if (str == NULL)
> +		return;
>  
>  	while (*str) {
>  		if (*str == 'u') {
> @@ -765,108 +682,36 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
>  
>  		++str;
>  	}
> -	if (str < *strp + 2)
> -		return -1;
> -
> -	*strp = str;
>  
>  	attr->exclude_user   = eu;
>  	attr->exclude_kernel = ek;
>  	attr->exclude_hv     = eh;
>  	attr->precise_ip     = precise;
> -
> -	return 0;
> +	return;
>  }
>  
> -/*
> - * Each event can have multiple symbolic names.
> - * Symbolic names are (almost) exactly matched.
> - */
> -static enum event_result
> -parse_event_symbols(struct perf_evlist *evlist, const char **str,
> -		    struct perf_event_attr *attr)
> +int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
>  {
> -	enum event_result ret;
> -
> -	ret = parse_tracepoint_event(evlist, str, attr);
> -	if (ret != EVT_FAILED)
> -		goto modifier;
> -
> -	ret = parse_raw_event(str, attr);
> -	if (ret != EVT_FAILED)
> -		goto modifier;
> +	YY_BUFFER_STATE buffer;
> +	int ret;
>  
> -	ret = parse_numeric_event(str, attr);
> -	if (ret != EVT_FAILED)
> -		goto modifier;
> +	__evlist = evlist;
>  
> -	ret = parse_symbolic_event(str, attr);
> -	if (ret != EVT_FAILED)
> -		goto modifier;
> +	buffer = parse_events__scan_string(str);
>  
> -	ret = parse_generic_hw_event(str, attr);
> -	if (ret != EVT_FAILED)
> -		goto modifier;
> +	ret = parse_events_parse();
>  
> -	ret = parse_breakpoint_event(str, attr);
> -	if (ret != EVT_FAILED)
> -		goto modifier;
> +	parse_events__flush_buffer(buffer);
> +	parse_events__delete_buffer(buffer);
>  
> -	fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
> -	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
> -	return EVT_FAILED;
> -
> -modifier:
> -	if (parse_event_modifier(str, attr) < 0) {
> -		fprintf(stderr, "invalid event modifier: '%s'\n", *str);
> -		fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
> -
> -		return EVT_FAILED;
> +	if (ret) {
> +		fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
> +		fprintf(stderr, "Run 'perf list' for a list of valid events\n");
>  	}
>  
>  	return ret;
>  }
>  
> -int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
> -{
> -	struct perf_event_attr attr;
> -	enum event_result ret;
> -	const char *ostr;
> -
> -	for (;;) {
> -		ostr = str;
> -		memset(&attr, 0, sizeof(attr));
> -		ret = parse_event_symbols(evlist, &str, &attr);
> -		if (ret == EVT_FAILED)
> -			return -1;
> -
> -		if (!(*str == 0 || *str == ',' || isspace(*str)))
> -			return -1;
> -
> -		if (ret != EVT_HANDLED_ALL) {
> -			struct perf_evsel *evsel;
> -			evsel = perf_evsel__new(&attr, evlist->nr_entries);
> -			if (evsel == NULL)
> -				return -1;
> -			perf_evlist__add(evlist, evsel);
> -
> -			evsel->name = calloc(str - ostr + 1, 1);
> -			if (!evsel->name)
> -				return -1;
> -			strncpy(evsel->name, ostr, str - ostr);
> -		}
> -
> -		if (*str == 0)
> -			break;
> -		if (*str == ',')
> -			++str;
> -		while (isspace(*str))
> -			++str;
> -	}
> -
> -	return 0;
> -}
> -
>  int parse_events_option(const struct option *opt, const char *str,
>  			int unset __used)
>  {
> @@ -1039,8 +884,6 @@ int print_hwcache_events(const char *event_glob)
>  	return printed;
>  }
>  
> -#define MAX_NAME_LEN 100
> -
>  /*
>   * Print the help text for the event symbols:
>   */
> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> index 7e0cbe7..fa3ac7f 100644
> --- a/tools/perf/util/parse-events.h
> +++ b/tools/perf/util/parse-events.h
> @@ -33,6 +33,15 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
>  
>  #define EVENTS_HELP_MAX (128*1024)
>  
> +int parse_events_add_tracepoint(char *sys, char *event, char *mod);
> +int parse_events_add_raw(long code, char *mod);
> +int parse_events_add_numeric(long type, long config, char *mod);
> +int parse_events_add_symbolic(char *symbol, char *mod);
> +int parse_events_add_generic_hw(char *type, char *op_result1, char *op_result2,
> +				char *mod);
> +int parse_events_add_breakpoint(void *ptr, char *type, char *mod);
> +void parse_events_error(char const *msg);
> +
>  void print_events(const char *event_glob);
>  void print_events_type(u8 type);
>  void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
> -- 
> 1.7.4

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

* Re: [PATCH 3/3] perf, tool: Add more automated tests for event parsing
  2011-12-15 15:30 ` [PATCH 3/3] perf, tool: Add more automated tests for event parsing Jiri Olsa
@ 2011-12-20 17:38   ` Arnaldo Carvalho de Melo
  2011-12-21  8:47   ` [tip:perf/core] perf test: " tip-bot for Jiri Olsa
  1 sibling, 0 replies; 91+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-12-20 17:38 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, cjashfor, linux-kernel

Em Thu, Dec 15, 2011 at 04:30:39PM +0100, Jiri Olsa escreveu:
> Adding automated tests for event parsing to include testing
> for modifier, ',' operator and group_leader.

Aha! Brownie points hereby granted, good stuff,

- Arnaldo
 
> Signed-off-by: Jiri Olsa <jolsa@redhat.com>
> ---
>  tools/perf/builtin-test.c |  245 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 244 insertions(+), 1 deletions(-)
> 
> diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
> index 6173f78..0cdb4c9 100644
> --- a/tools/perf/builtin-test.c
> +++ b/tools/perf/builtin-test.c
> @@ -603,7 +603,7 @@ out_free_threads:
>  
>  #define TEST_ASSERT_VAL(text, cond) \
>  do { \
> -	if (!cond) { \
> +	if (!(cond)) { \
>  		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
>  		return -1; \
>  	} \
> @@ -759,6 +759,201 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
>  	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_list(struct perf_evlist *evlist)
> +{
> +	struct perf_evsel *evsel;
> +	struct perf_evsel *group_leader;
> +
> +	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
> +
> +	/* r1 */
> +	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
> +	group_leader = evsel;
> +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == 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);
> +	TEST_ASSERT_VAL("wrong group_leader", !evsel->group_leader);
> +
> +	/* 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);
> +	TEST_ASSERT_VAL("wrong group_leader",
> +			evsel->group_leader == group_leader);
> +
> +	/* 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);
> +	TEST_ASSERT_VAL("wrong group_leader",
> +			evsel->group_leader == group_leader);
> +
> +	return 0;
> +}
> +
>  static struct test__event_st {
>  	const char *name;
>  	__u32 type;
> @@ -808,6 +1003,54 @@ static struct test__event_st {
>  		.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  = "r1: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  = "r1,syscalls:sys_enter_open:k,1:1:hp",
> +		.check = test__checkevent_list,
> +	},
>  };
>  
>  #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
> -- 
> 1.7.4

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

* Re: [PATCH 2/3] perf, tool: Add new event group management
  2011-12-15 15:30 ` [PATCH 2/3] perf, tool: Add new event group management Jiri Olsa
@ 2011-12-20 17:47   ` Arnaldo Carvalho de Melo
  2011-12-20 21:20     ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-12-20 17:47 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, cjashfor, linux-kernel

Em Thu, Dec 15, 2011 at 04:30:38PM +0100, Jiri Olsa escreveu:
> The current event grouping is basic. If you specify the '--group'
> option for record/stat/top command, all the specified events become
> members of a single group with the first event as a group leader.
> 
> This patch adds a functionality that allows to create event groups
> based on the way they are specified on the command line. Extending
> the '--group/-g' option power while preserving the current behaviour.
> 
> It is now possible to use '--group/-g' option with 'parsed' value,
> which will create groups based on the command line events layout.
> 
> With the '--group/-g parsed' option specified, all events separated
> by ',' within a single '-e' option now become members of a group with
> the first event specified as a group leader. Another '-e' option with
> multiple events creates separate group.
> 
> All groups are created with regards to threads and cpus. Thus
> recording an event group within a 2 threads on server with
> 4 CPUs will create 8 separate groups.
> 
> Examples (first event in brackets is group leader):
> 
>   # 1 group (cpu-clock,task-clock)
>   perf record --group -e cpu-clock,task-clock ls
>   perf record --group parsed -e cpu-clock,task-clock ls
> 
>   # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
>   perf record --group parsed -e cpu-clock,task-clock \
>    -e minor-faults,major-faults ls
> 
>   # 1 group (cpu-clock,task-clock,minor-faults,major-faults)
>   perf record --group -e cpu-clock,task-clock \
>    -e minor-faults,major-faults ls
> 
>   # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
>   perf record --group parsed -e cpu-clock,task-clock \
>    -e minor-faults,major-faults -e instructions ls
> 
>   # 1 group (cpu-clock,task-clock,minor-faults,major-faults,instructions)
>   perf record --group -e cpu-clock,task-clock \
>    -e minor-faults,major-faults -e instructions ls

Looks awesome! Peter, comments? All OK with you?

Jiri, can we have some 'perf test' that tests this thoroughly? Are they
there already on that next patch and I'm being to change my glasses yet
again?

Some minor nits below:

- Arnaldo
 
> Signed-off-by: Jiri Olsa <jolsa@redhat.com>
> ---
>  tools/perf/Makefile            |    2 ++
>  tools/perf/builtin-record.c    |    8 +++++---
>  tools/perf/builtin-stat.c      |   10 ++++++----
>  tools/perf/builtin-top.c       |    8 +++++---
>  tools/perf/perf.h              |    2 +-
>  tools/perf/util/evsel.c        |   28 ++++++++++++++++++++++------
>  tools/perf/util/evsel.h        |    9 +++++----
>  tools/perf/util/group.c        |   23 +++++++++++++++++++++++
>  tools/perf/util/group.h        |   25 +++++++++++++++++++++++++
>  tools/perf/util/parse-events.c |    6 ++++++
>  tools/perf/util/python.c       |    4 ++++
>  tools/perf/util/top.h          |    2 +-
>  12 files changed, 105 insertions(+), 22 deletions(-)
>  create mode 100644 tools/perf/util/group.c
>  create mode 100644 tools/perf/util/group.h
> 
> diff --git a/tools/perf/Makefile b/tools/perf/Makefile
> index ef6b621..c54b595 100644
> --- a/tools/perf/Makefile
> +++ b/tools/perf/Makefile
> @@ -299,6 +299,7 @@ LIB_H += util/cpumap.h
>  LIB_H += util/top.h
>  LIB_H += $(ARCH_INCLUDE)
>  LIB_H += util/cgroup.h
> +LIB_H += util/group.h
>  
>  LIB_OBJS += $(OUTPUT)util/abspath.o
>  LIB_OBJS += $(OUTPUT)util/alias.o
> @@ -356,6 +357,7 @@ LIB_OBJS += $(OUTPUT)util/util.o
>  LIB_OBJS += $(OUTPUT)util/xyarray.o
>  LIB_OBJS += $(OUTPUT)util/cpumap.o
>  LIB_OBJS += $(OUTPUT)util/cgroup.o
> +LIB_OBJS += $(OUTPUT)util/group.o
>  
>  BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
>  
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 766fa0a..581c72d 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -26,6 +26,7 @@
>  #include "util/symbol.h"
>  #include "util/cpumap.h"
>  #include "util/thread_map.h"
> +#include "util/group.h"
>  
>  #include <unistd.h>
>  #include <sched.h>
> @@ -202,7 +203,7 @@ static void perf_record__open(struct perf_record *rec)
>  		 */
>  		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
>  
> -		if (opts->group && pos != first)
> +		if (group_is_single(opts->group) && pos != first)
>  			group_fd = first->fd;
>  retry_sample_id:
>  		attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
> @@ -688,8 +689,9 @@ const struct option record_options[] = {
>  	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
>  	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
>  		     "number of mmap data pages"),
> -	OPT_BOOLEAN(0, "group", &record.opts.group,
> -		    "put the counters into a counter group"),
> +	OPT_CALLBACK_DEFAULT(0, "group", &record.opts.group, "[parsed]",
> +		     "put the counters into a counter group",
> +		     parse_group, PERF_GROUP_NONE),
>  	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
>  		    "do call-graph (stack chain/backtrace) recording"),
>  	OPT_INCR('v', "verbose", &verbose,
> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> index cc53de3..c28c852 100644
> --- a/tools/perf/builtin-stat.c
> +++ b/tools/perf/builtin-stat.c
> @@ -55,6 +55,7 @@
>  #include "util/cpumap.h"
>  #include "util/thread.h"
>  #include "util/thread_map.h"
> +#include "util/group.h"
>  
>  #include <sys/prctl.h>
>  #include <math.h>
> @@ -193,7 +194,7 @@ static int			big_num_opt			=  -1;
>  static const char		*cpu_list;
>  static const char		*csv_sep			= NULL;
>  static bool			csv_output			= false;
> -static bool			group				= false;
> +static int			group;
>  static const char		*output_name			= NULL;
>  static FILE			*output				= NULL;
>  static int			output_fd;
> @@ -284,7 +285,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
>  	struct perf_event_attr *attr = &evsel->attr;
>  	struct xyarray *group_fd = NULL;
>  
> -	if (group && evsel != first)
> +	if (group_is_single(group) && evsel != first)
>  		group_fd = first->fd;
>  
>  	if (scale)
> @@ -1068,8 +1069,9 @@ static const struct option options[] = {
>  		    "stat events on existing thread id"),
>  	OPT_BOOLEAN('a', "all-cpus", &system_wide,
>  		    "system-wide collection from all CPUs"),
> -	OPT_BOOLEAN('g', "group", &group,
> -		    "put the counters into a counter group"),
> +	OPT_CALLBACK_DEFAULT('g', "group", &group, "[parsed]",
> +		    "put the counters into a counter group",
> +		    parse_group, PERF_GROUP_NONE),
>  	OPT_BOOLEAN('c', "scale", &scale,
>  		    "scale/normalize counters"),
>  	OPT_INCR('v', "verbose", &verbose,
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index c3836b9..c1f205c 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -38,6 +38,7 @@
>  #include "util/cpumap.h"
>  #include "util/xyarray.h"
>  #include "util/sort.h"
> +#include "util/group.h"
>  
>  #include "util/debug.h"
>  
> @@ -830,7 +831,7 @@ static void perf_top__start_counters(struct perf_top *top)
>  		struct perf_event_attr *attr = &counter->attr;
>  		struct xyarray *group_fd = NULL;
>  
> -		if (top->group && counter != first)
> +		if (group_is_single(top->group) && counter != first)
>  			group_fd = first->fd;
>  
>  		attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
> @@ -1120,8 +1121,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
>  			    "dump the symbol table used for profiling"),
>  	OPT_INTEGER('f', "count-filter", &top.count_filter,
>  		    "only display functions with more events than this"),
> -	OPT_BOOLEAN('g', "group", &top.group,
> -			    "put the counters into a counter group"),
> +	OPT_CALLBACK_DEFAULT('g', "group", &top.group, "[parsed]",
> +		    "put the counters into a counter group",
> +		    parse_group, PERF_GROUP_NONE),
>  	OPT_BOOLEAN('i', "inherit", &top.inherit,
>  		    "child tasks inherit counters"),
>  	OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
> diff --git a/tools/perf/perf.h b/tools/perf/perf.h
> index ea804f5..b2aa37a 100644
> --- a/tools/perf/perf.h
> +++ b/tools/perf/perf.h
> @@ -189,7 +189,7 @@ struct perf_record_opts {
>  	pid_t	     target_pid;
>  	pid_t	     target_tid;
>  	bool	     call_graph;
> -	bool	     group;
> +	int	     group;

When doing that move it consider alignment, you've just added a 2 bytes
hole here :-) Not critical path, but never the less good to have things
properly aligned.

Shameless plug: pahole would help here, I think I should even add a
pahole check to checkpatch.pl to warn the user if he/she is adding
holes...

>  	bool	     inherit_stat;
>  	bool	     no_delay;
>  	bool	     no_inherit;
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 4a8c8b0..280286a 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -14,6 +14,7 @@
>  #include "util.h"
>  #include "cpumap.h"
>  #include "thread_map.h"
> +#include "group.h"
>  
>  #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
>  #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
> @@ -284,8 +285,17 @@ int __perf_evsel__read(struct perf_evsel *evsel,
>  	return 0;
>  }
>  
> +static int perf_evsel_group(struct perf_evsel *evsel,
> +			    int cpu, int thread)

Please use "perf_evsel__group(...)

The double __ is to ease grepping/ctag'in and to separate class name
(perf_evsel) from method name (group), a convention I used in other
projects and have been trying to keep consistent in tools/perf/ even not
being completely crazy about it to refuse patches based only on that
aspect.

> +{
> +	if (evsel->group_leader)
> +		return FD(evsel->group_leader, cpu, thread);
> +
> +	return -1;
> +}
> +
>  static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> -			      struct thread_map *threads, bool group,
> +			      struct thread_map *threads, int group,
>  			      struct xyarray *group_fds)
>  {
>  	int cpu, thread;
> @@ -302,13 +312,19 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
>  	}
>  
>  	for (cpu = 0; cpu < cpus->nr; cpu++) {
> -		int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
> +		int group_fd = -1;
> +
> +		if (group_is_single(group))
> +			group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
>  
>  		for (thread = 0; thread < threads->nr; thread++) {
>  
>  			if (!evsel->cgrp)
>  				pid = threads->map[thread];
>  
> +			if (group_is_parsed(group))
> +				group_fd = perf_evsel_group(evsel, cpu, thread);
> +
>  			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
>  								     pid,
>  								     cpus->map[cpu],
> @@ -318,7 +334,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
>  				goto out_close;
>  			}
>  
> -			if (group && group_fd == -1)
> +			if (group_is_single(group) && group_fd == -1)
>  				group_fd = FD(evsel, cpu, thread);
>  		}
>  	}
> @@ -363,7 +379,7 @@ static struct {
>  };
>  
>  int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> -		     struct thread_map *threads, bool group,
> +		     struct thread_map *threads, int group,
>  		     struct xyarray *group_fd)
>  {
>  	if (cpus == NULL) {
> @@ -378,7 +394,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
>  }
>  
>  int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
> -			     struct cpu_map *cpus, bool group,
> +			     struct cpu_map *cpus, int group,
>  			     struct xyarray *group_fd)
>  {
>  	return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
> @@ -386,7 +402,7 @@ int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
>  }
>  
>  int perf_evsel__open_per_thread(struct perf_evsel *evsel,
> -				struct thread_map *threads, bool group,
> +				struct thread_map *threads, int group,
>  				struct xyarray *group_fd)
>  {
>  	return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
> diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
> index 326b8e4..db9ee0b 100644
> --- a/tools/perf/util/evsel.h
> +++ b/tools/perf/util/evsel.h
> @@ -66,6 +66,7 @@ struct perf_evsel {
>  		void		*data;
>  	} handler;
>  	bool 			supported;
> +	struct perf_evsel	*group_leader;
>  };
>  
>  struct cpu_map;
> @@ -90,14 +91,14 @@ void perf_evsel__free_id(struct perf_evsel *evsel);
>  void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
>  
>  int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
> -			     struct cpu_map *cpus, bool group,
> +			     struct cpu_map *cpus, int group,
>  			     struct xyarray *group_fds);
>  int perf_evsel__open_per_thread(struct perf_evsel *evsel,
> -				struct thread_map *threads, bool group,
> +				struct thread_map *threads, int group,
>  				struct xyarray *group_fds);
>  int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> -		     struct thread_map *threads, bool group,
> -		     struct xyarray *group_fds);
> +		     struct thread_map *threads, int group,
> +		     struct xyarray *group_fd);
>  void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
>  
>  #define perf_evsel__match(evsel, t, c)		\
> diff --git a/tools/perf/util/group.c b/tools/perf/util/group.c
> new file mode 100644
> index 0000000..89468a9
> --- /dev/null
> +++ b/tools/perf/util/group.c
> @@ -0,0 +1,23 @@
> +
> +#include <linux/compiler.h>
> +#include "types.h"
> +#include "util.h"
> +#include "parse-options.h"
> +#include "group.h"
> +
> +int parse_group(const struct option *opt, const char *str,
> +		int unset __used)
> +{
> +	int *group_opt = (int *) opt->value;
> +
> +	if (!str)
> +		*group_opt = PERF_GROUP_SINGLE;
> +	else if (!strcmp(str, "parsed"))
> +		*group_opt = PERF_GROUP_PARSED;
> +	else {
> +		fprintf(stderr, "unknown group option value\n");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> diff --git a/tools/perf/util/group.h b/tools/perf/util/group.h
> new file mode 100644
> index 0000000..ad80015
> --- /dev/null
> +++ b/tools/perf/util/group.h
> @@ -0,0 +1,25 @@
> +#ifndef __GROUP_H__
> +#define __GROUP_H__
> +
> +struct option;
> +
> +enum perf_group_opt {
> +	PERF_GROUP_NONE,
> +	PERF_GROUP_SINGLE,
> +	PERF_GROUP_PARSED
> +};
> +
> +int parse_group(const struct option *opt, const char *str,
> +		int unset);
> +
> +static inline bool group_is_single(int group)
> +{
> +	return group == PERF_GROUP_SINGLE;
> +}
> +
> +static inline bool group_is_parsed(int group)
> +{
> +	return group == PERF_GROUP_PARSED;
> +}
> +
> +#endif /* __GROUP_H__ */
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index b9c4189..b7913c3 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -25,6 +25,7 @@ struct event_symbol {
>  int parse_events_parse(void);
>  
>  static struct perf_evlist *__evlist;
> +static struct perf_evsel *group_leader;
>  
>  #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
>  #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
> @@ -373,6 +374,10 @@ static int add_event(struct perf_event_attr *attr, char *name, char *mod)
>  	if (!evsel->name)
>  		return -ENOMEM;
>  
> +	evsel->group_leader = group_leader;
> +	if (!group_leader)
> +		group_leader = evsel;
> +
>  	strncpy(evsel->name, name, len);
>  	return 0;
>  }
> @@ -696,6 +701,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
>  	int ret;
>  
>  	__evlist = evlist;
> +	group_leader = NULL;
>  
>  	buffer = parse_events__scan_string(str);
>  
> diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> index 9dd47a4..b91a43b 100644
> --- a/tools/perf/util/python.c
> +++ b/tools/perf/util/python.c
> @@ -7,6 +7,7 @@
>  #include "event.h"
>  #include "cpumap.h"
>  #include "thread_map.h"
> +#include "group.h"
>  
>  /* Define PyVarObject_HEAD_INIT for python 2.5 */
>  #ifndef PyVarObject_HEAD_INIT
> @@ -828,6 +829,9 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
>  	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
>  		return NULL;
>  
> +	if (group)
> +		group = PERF_GROUP_SINGLE;
> +
>  	if (perf_evlist__open(evlist, group) < 0) {
>  		PyErr_SetFromErrno(PyExc_OSError);
>  		return NULL;
> diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
> index a248f3c..f545bc6 100644
> --- a/tools/perf/util/top.h
> +++ b/tools/perf/util/top.h
> @@ -32,7 +32,7 @@ struct perf_top {
>  	bool		   kptr_restrict_warned;
>  	bool		   vmlinux_warned;
>  	bool		   inherit;
> -	bool		   group;
> +	int		   group;
>  	bool		   sample_id_all_avail;
>  	bool		   dump_symtab;
>  	const char	   *cpu_list;
> -- 
> 1.7.4

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

* Re: [PATCH 2/3] perf, tool: Add new event group management
  2011-12-20 17:47   ` Arnaldo Carvalho de Melo
@ 2011-12-20 21:20     ` Peter Zijlstra
  2011-12-21 11:54       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2011-12-20 21:20 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, mingo, paulus, cjashfor, linux-kernel

On Tue, 2011-12-20 at 15:47 -0200, Arnaldo Carvalho de Melo wrote:
> Looks awesome! Peter, comments? All OK with you?

Read my replies, not really. I'm ok with the idea, but I think we should
take this possibility to clean up the syntax, sod backward compat.

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

* [tip:perf/core] perf test: Add more automated tests for event parsing
  2011-12-15 15:30 ` [PATCH 3/3] perf, tool: Add more automated tests for event parsing Jiri Olsa
  2011-12-20 17:38   ` Arnaldo Carvalho de Melo
@ 2011-12-21  8:47   ` tip-bot for Jiri Olsa
  1 sibling, 0 replies; 91+ messages in thread
From: tip-bot for Jiri Olsa @ 2011-12-21  8:47 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa, tglx, mingo

Commit-ID:  65c1e0452a3389f9b7b8c1b23305ed2922fafb2d
Gitweb:     http://git.kernel.org/tip/65c1e0452a3389f9b7b8c1b23305ed2922fafb2d
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Thu, 15 Dec 2011 16:30:39 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 20 Dec 2011 14:46:14 -0200

perf test: Add more automated tests for event parsing

Adding automated tests for event parsing to include testing for modifier
and ',' operator.

Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: cjashfor@linux.vnet.ibm.com
Link: http://lkml.kernel.org/r/1323963039-7602-4-git-send-email-jolsa@redhat.com
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
[ committer note: Remove some tests that need group_leader & bison patchkits ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-test.c |  127 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 126 insertions(+), 1 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 6173f78..2b9a7f4 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -603,7 +603,7 @@ out_free_threads:
 
 #define TEST_ASSERT_VAL(text, cond) \
 do { \
-	if (!cond) { \
+	if (!(cond)) { \
 		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
 		return -1; \
 	} \
@@ -759,6 +759,103 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
 	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 struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -808,6 +905,34 @@ static struct test__event_st {
 		.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  = "r1: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,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))

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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-20 17:37   ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Arnaldo Carvalho de Melo
@ 2011-12-21  9:55     ` Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-21  9:55 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: a.p.zijlstra, mingo, paulus, cjashfor, linux-kernel

On Tue, Dec 20, 2011 at 03:37:22PM -0200, Arnaldo Carvalho de Melo wrote:
> Em Thu, Dec 15, 2011 at 04:30:37PM +0100, Jiri Olsa escreveu:
> > Changing event parsing to use flex/bison parse generator.
> > The event syntax stays as it is.
> 
> Seems really cool, using the right tool for the task, comments:
> 
> . Can we avoid more globals? Like that __event_list one.
ok, looks like there's a way to pass an parameter to the parse function,
I'll chec and make the change if possible


> . All those ABORT_ON do what? die() like stuff? /me googles YYABORT...
> 
> ----
> YYABORT
> Return immediately with value 1 (to report failure).
> ----
> 
> 	Ok, so it gets propagated back and hopefully the we die() just
> back at main() in tools/perf/perf.c, right?
right, it'll make parse_events_parse return error

> 
> . make help | perf
> 
> 	Then running one of those targets and trying to build perf still
> works? I guess so, but better check that.
> 
> 	Having it added to some new "make perf-test" that does that +
> 'perf test' too would get you brownie points. Leave it for later/someone
> else if you're busy/not looking for more work, of course 8-)
> 
> . We have some tests to parse events in 'perf test', right? From the top
> of my head it was even ya that did that, guess those are ok/improved
> (still need to look at the other patches in the backlog).
right ;)

thanks,
jirka

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

* Re: [PATCH 2/3] perf, tool: Add new event group management
  2011-12-20 21:20     ` Peter Zijlstra
@ 2011-12-21 11:54       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 91+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-12-21 11:54 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, mingo, paulus, cjashfor, linux-kernel

Em Tue, Dec 20, 2011 at 10:20:51PM +0100, Peter Zijlstra escreveu:
> On Tue, 2011-12-20 at 15:47 -0200, Arnaldo Carvalho de Melo wrote:
> > Looks awesome! Peter, comments? All OK with you?
> 
> Read my replies, not really. I'm ok with the idea, but I think we should
> take this possibility to clean up the syntax, sod backward compat.

Ok, I meant the idea mostly, didn't looked that much at the syntax and
haven't taken any of those patches :)

- Arnaldo

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

* new syntax for perf event
  2011-12-20 11:39             ` Peter Zijlstra
@ 2011-12-21 16:16               ` Jiri Olsa
  2012-01-05  9:17                 ` Jiri Olsa
  2012-01-05 14:10                 ` Peter Zijlstra
  0 siblings, 2 replies; 91+ messages in thread
From: Jiri Olsa @ 2011-12-21 16:16 UTC (permalink / raw)
  To: Peter Zijlstra, acme; +Cc: mingo, paulus, cjashfor, linux-kernel

On Tue, Dec 20, 2011 at 12:39:21PM +0100, Peter Zijlstra wrote:
> On Tue, 2011-12-20 at 12:30 +0100, Peter Zijlstra wrote:
> > event   config-0:7
> > umask   config-8:15
> > usr     config-16
> > os      config-17
> > edge    config-18
> > any     config-21
> > inv     config-23
> > cmask   config-24:31
> > 
> > nhm-dmnd_data_rd        config1-0
> > nhm-dmnd_rfo            config1-1
> > nhm-dmnd_ifetch         config1-2
> > ...
> > 
> > (the real syntax will likely be a little more complex in order to be
> > able to express the various other architectures their raw input format). 
> 
> for instance AMD would need:
> 
> event	config-0:7,32-35
> guest	config-40
> host	config-41
> 
> (assuming you read that as a mask from LSB to MSB)
> 
> And I still haven't actually read how the P4 works so I can't help out
> there.


ok first try ;) description + grammar attached

- event has a general format:
        pmu/event_def[:modifier] [ ',' pmu/event_def[:modifier] ] ...

  where event_def depends on the chosen pmu:
        'cpu' 'tracepoint' 'breakpoint'


- to keep some of the old interface, symbolic and cache events stays,
  since they are recognizable by keywords (event_symbol, event_cache)


- raw events are defined with the help of event keywords like:
        cpu/raw,config=1,config1=0,config2=0
        cpu/hw,config=1,config1=0

  * first symbol after '/' defines the type: raw/hw/cache
    which match PERF_TYPE_RAW/PERF_TYPE_HARDWARE/PERF_TYPE_HW_CACHE

  * the rest consists assignments for 'config/config1/config1' keywords
    that match with the perf_event_attr:config/config1/config values
    (possibly extended once we have sysfs events representation)


- tracepoint events are defined like:
        tracepoint/system:tracepoint

  where tracepoint could contain '*?'


- breakpoint events are defined like:
        breakpoint/addr:type


- each event could be followed by modifier definition


- I think pmu names should match registered pmu names,
  but we could make some shortcuts so we dont need to type 'tracepoint/',
  but just 'tp/' or smth..


- as for tracepoints it looks like the old format does not clash with the new one
  and we could add shortcut (omit the 'tracepoint/') like:
      event: event_tracepoint


- not sure I should include 'software' pmu, as it seems to covered by
  event_symbol events


thanks for comments,
jirka



grammar
-------
events:
                event_mod ',' event_mod | event_mod

event_mod:
                event | event ':' modifier

event:
                event_symbol |
                event_cache |
                'cpu' '/' event_cpu |
                'tracepoint' '/' event_tracepoint
                'breakpoint' '/' event_breakpoint

event_symbol:
                cpu-cycles|cycles
                stalled-cycles-frontend|idle-cycles-frontend
                stalled-cycles-backend|idle-cycles-backend
                instructions
                cache-references
                cache-misses
                branch-instructions|branches
                branch-misses
                bus-cycles
                cpu-clock
                task-clock
                page-faults|faults
                minor-faults
                major-faults
                context-switches|cs
                cpu-migrations|migrations
                alignment-faults
                emulation-faults

event_cache:
                cache_type
                cache_type '-' cache_result_op
                cache_type '-' cache_result_op '-' cache_result_op

cache_type:
                L1-dcache|l1-d|l1d|L1-data
                L1-icache|l1-i|l1i|L1-instruction
                LLC|L2
                dTLB|d-tlb|Data-TLB
                iTLB|i-tlb|Instruction-TLB
                branch|branches|bpu|btb|bpc
                node

cache_result_op:
                load|loads|read
                store|stores|write
                prefetch|prefetches
                speculative-read|speculative-load
                refs|Reference|ops|access
                misses|miss

event_cpu:
                'raw'    ',' event_cpu_def
                'hw'     ',' event_cpu_def
                'cache'  ',' event_cpu_def

event_cpu_def:
                event_cpu_ass ',' event_cpu_ass |
                event_cpu_ass

event_cpu_ass:
                event_cpu_elem '=' value

event_cpu_elem:
                'config' | 'config1' | 'config2'

event_tracepoint:
                system ':' tracepoint

event_breakpoint:
                addr ':' type

modifier:
                [ukhp]{1,4}

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

* Re: [PATCH 1/3] perf, tool: Add parser generator for events parsing
  2011-12-20 11:30           ` Peter Zijlstra
  2011-12-20 11:39             ` Peter Zijlstra
@ 2011-12-22 19:32             ` Vince Weaver
  1 sibling, 0 replies; 91+ messages in thread
From: Vince Weaver @ 2011-12-22 19:32 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, linux-kernel

On Tue, 20 Dec 2011, Peter Zijlstra wrote:

> 
> This would allow us to write things like:
> 
>  perf record -e cpu/event=0x34,umask=0x01,inv,cmask=2

I know this is beating a dead horse, but are you guys *really* that 
against just linking against libpfm4?

Instead of (to use your example):
    perf record -e cpu/event=0x34,umask=0x01,inv,cmask=2
Insn't
    perf record -e nhm::UNC_CBO_CACHE_LOOKUP:M:i=1:cmask=2
much nicer? 

And the code that translates that to bits for you already exists in a nice 
library form.  And it supports Pentium 4 already.

In PAPI we're finally moving to all string-based event names simply 
because trying to create cross-platform ways of specifying bits like you 
are just didn't work very well.

Vince


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

* Re: new syntax for perf event
  2011-12-21 16:16               ` new syntax for perf event Jiri Olsa
@ 2012-01-05  9:17                 ` Jiri Olsa
  2012-01-05 14:10                 ` Peter Zijlstra
  1 sibling, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-05  9:17 UTC (permalink / raw)
  To: Peter Zijlstra, acme; +Cc: mingo, paulus, cjashfor, linux-kernel

hi, any feedback?

thanks,
jirka

On Wed, Dec 21, 2011 at 05:16:13PM +0100, Jiri Olsa wrote:
> On Tue, Dec 20, 2011 at 12:39:21PM +0100, Peter Zijlstra wrote:
> > On Tue, 2011-12-20 at 12:30 +0100, Peter Zijlstra wrote:
> > > event   config-0:7
> > > umask   config-8:15
> > > usr     config-16
> > > os      config-17
> > > edge    config-18
> > > any     config-21
> > > inv     config-23
> > > cmask   config-24:31
> > > 
> > > nhm-dmnd_data_rd        config1-0
> > > nhm-dmnd_rfo            config1-1
> > > nhm-dmnd_ifetch         config1-2
> > > ...
> > > 
> > > (the real syntax will likely be a little more complex in order to be
> > > able to express the various other architectures their raw input format). 
> > 
> > for instance AMD would need:
> > 
> > event	config-0:7,32-35
> > guest	config-40
> > host	config-41
> > 
> > (assuming you read that as a mask from LSB to MSB)
> > 
> > And I still haven't actually read how the P4 works so I can't help out
> > there.
> 
> 
> ok first try ;) description + grammar attached
> 
> - event has a general format:
>         pmu/event_def[:modifier] [ ',' pmu/event_def[:modifier] ] ...
> 
>   where event_def depends on the chosen pmu:
>         'cpu' 'tracepoint' 'breakpoint'
> 
> 
> - to keep some of the old interface, symbolic and cache events stays,
>   since they are recognizable by keywords (event_symbol, event_cache)
> 
> 
> - raw events are defined with the help of event keywords like:
>         cpu/raw,config=1,config1=0,config2=0
>         cpu/hw,config=1,config1=0
> 
>   * first symbol after '/' defines the type: raw/hw/cache
>     which match PERF_TYPE_RAW/PERF_TYPE_HARDWARE/PERF_TYPE_HW_CACHE
> 
>   * the rest consists assignments for 'config/config1/config1' keywords
>     that match with the perf_event_attr:config/config1/config values
>     (possibly extended once we have sysfs events representation)
> 
> 
> - tracepoint events are defined like:
>         tracepoint/system:tracepoint
> 
>   where tracepoint could contain '*?'
> 
> 
> - breakpoint events are defined like:
>         breakpoint/addr:type
> 
> 
> - each event could be followed by modifier definition
> 
> 
> - I think pmu names should match registered pmu names,
>   but we could make some shortcuts so we dont need to type 'tracepoint/',
>   but just 'tp/' or smth..
> 
> 
> - as for tracepoints it looks like the old format does not clash with the new one
>   and we could add shortcut (omit the 'tracepoint/') like:
>       event: event_tracepoint
> 
> 
> - not sure I should include 'software' pmu, as it seems to covered by
>   event_symbol events
> 
> 
> thanks for comments,
> jirka
> 
> 
> 
> grammar
> -------
> events:
>                 event_mod ',' event_mod | event_mod
> 
> event_mod:
>                 event | event ':' modifier
> 
> event:
>                 event_symbol |
>                 event_cache |
>                 'cpu' '/' event_cpu |
>                 'tracepoint' '/' event_tracepoint
>                 'breakpoint' '/' event_breakpoint
> 
> event_symbol:
>                 cpu-cycles|cycles
>                 stalled-cycles-frontend|idle-cycles-frontend
>                 stalled-cycles-backend|idle-cycles-backend
>                 instructions
>                 cache-references
>                 cache-misses
>                 branch-instructions|branches
>                 branch-misses
>                 bus-cycles
>                 cpu-clock
>                 task-clock
>                 page-faults|faults
>                 minor-faults
>                 major-faults
>                 context-switches|cs
>                 cpu-migrations|migrations
>                 alignment-faults
>                 emulation-faults
> 
> event_cache:
>                 cache_type
>                 cache_type '-' cache_result_op
>                 cache_type '-' cache_result_op '-' cache_result_op
> 
> cache_type:
>                 L1-dcache|l1-d|l1d|L1-data
>                 L1-icache|l1-i|l1i|L1-instruction
>                 LLC|L2
>                 dTLB|d-tlb|Data-TLB
>                 iTLB|i-tlb|Instruction-TLB
>                 branch|branches|bpu|btb|bpc
>                 node
> 
> cache_result_op:
>                 load|loads|read
>                 store|stores|write
>                 prefetch|prefetches
>                 speculative-read|speculative-load
>                 refs|Reference|ops|access
>                 misses|miss
> 
> event_cpu:
>                 'raw'    ',' event_cpu_def
>                 'hw'     ',' event_cpu_def
>                 'cache'  ',' event_cpu_def
> 
> event_cpu_def:
>                 event_cpu_ass ',' event_cpu_ass |
>                 event_cpu_ass
> 
> event_cpu_ass:
>                 event_cpu_elem '=' value
> 
> event_cpu_elem:
>                 'config' | 'config1' | 'config2'
> 
> event_tracepoint:
>                 system ':' tracepoint
> 
> event_breakpoint:
>                 addr ':' type
> 
> modifier:
>                 [ukhp]{1,4}

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

* Re: new syntax for perf event
  2011-12-21 16:16               ` new syntax for perf event Jiri Olsa
  2012-01-05  9:17                 ` Jiri Olsa
@ 2012-01-05 14:10                 ` Peter Zijlstra
  2012-01-09 15:28                   ` Jiri Olsa
  1 sibling, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-05 14:10 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Wed, 2011-12-21 at 17:16 +0100, Jiri Olsa wrote:
> grammar

yacc/bison notation it seems.. lemme get the rules for that.

> -------
> events:
>                 event_mod ',' event_mod | event_mod

events = event_mod, {',' , event_mod};

would be the EBNF variant for allowing inf repetition, not sure how to
express that, it seems to want a recursive rule which I'm not sure I
see. The way I read your thing it only allows 1 or 2 events.

> 
> event_mod:
>                 event | event ':' modifier


event_mod = event, [':' , modifier];

Would be the EBNF thing, and I think your rule does indeed match that.

> event:
>                 event_symbol |
>                 event_cache |
>                 'cpu' '/' event_cpu |
>                 'tracepoint' '/' event_tracepoint
>                 'breakpoint' '/' event_breakpoint

I think I'd like to see something like:

event   = pmu, '/', event_config 
	| event_symbol | event_cache;

pmu = ? ls /sys/bus/event_source/devices ?;
(* maybe add some aliasses like you suggest *)

event_config = (event_predef | event_term), {',', event_term};

event_predef = ? special name -> raw mapping read from somewhere ?;

event_term = event_sym, '=', value;

event_sym = "config" | "config1" | "config2"
	  | ? contents of /sys/bus/event_source/devices/$pmu/format ?;

value = integer | hexint;


> event_symbol:
>                 cpu-cycles|cycles
>                 stalled-cycles-frontend|idle-cycles-frontend
>                 stalled-cycles-backend|idle-cycles-backend
>                 instructions
>                 cache-references
>                 cache-misses
>                 branch-instructions|branches
>                 branch-misses
>                 bus-cycles
>                 cpu-clock
>                 task-clock
>                 page-faults|faults
>                 minor-faults
>                 major-faults
>                 context-switches|cs
>                 cpu-migrations|migrations
>                 alignment-faults
>                 emulation-faults
> 
> event_cache:
>                 cache_type
>                 cache_type '-' cache_result_op
>                 cache_type '-' cache_result_op '-' cache_result_op

I'd write that as:

event_cache = cache_type, '-', cache_mod, ['-', cache_xs];

cache_type = cache_l1d | cache_l1i | cache_llc 
	   | cache_dtlb | cache_itlb
	   | cache_branch | cache_node;

cache_mod = cache_load | cache_store | cache_prefetch;

cache_xs = cache_accesses | cache_misses;

cache_l1d = "L1-dcache" | ... ;

etc..


> event_cpu:
>                 'raw'    ',' event_cpu_def
>                 'hw'     ',' event_cpu_def
>                 'cache'  ',' event_cpu_def

I think these are superfluous and we could deduce them from the actual
event_term's used. Something using "config" will be a raw event etc..

> 
> event_cpu_def:
>                 event_cpu_ass ',' event_cpu_ass |
>                 event_cpu_ass
> 
> event_cpu_ass:
>                 event_cpu_elem '=' value

Hehehe, you said 'ass', hehe.


> event_tracepoint:
>                 system ':' tracepoint
> 
> event_breakpoint:
>                 addr ':' type

Right, something like that.

> 
> modifier:
>                 [ukhp]{1,4} 

I think you need at least 5, or you can write it like:

modifier = ['u'], ['k'], ['h'], [3*'p'];

Also, I think we grew a few more modifiers with some of the perf kvm
guest muck.

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

* Re: new syntax for perf event
  2012-01-05 14:10                 ` Peter Zijlstra
@ 2012-01-09 15:28                   ` Jiri Olsa
  2012-01-09 15:43                     ` Peter Zijlstra
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
  0 siblings, 2 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-09 15:28 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Thu, Jan 05, 2012 at 03:10:56PM +0100, Peter Zijlstra wrote:
> On Wed, 2011-12-21 at 17:16 +0100, Jiri Olsa wrote:
> > grammar
> 
> yacc/bison notation it seems.. lemme get the rules for that.
> 
> > -------
> > events:
> >                 event_mod ',' event_mod | event_mod
> 
> events = event_mod, {',' , event_mod};
> 
> would be the EBNF variant for allowing inf repetition, not sure how to
> express that, it seems to want a recursive rule which I'm not sure I
> see. The way I read your thing it only allows 1 or 2 events.

aargh, sure we want more than 2 events ;)
should have been something like:

events: events ',' event_mod | event_mod


> 
> > 
> > event_mod:
> >                 event | event ':' modifier
> 
> 
> event_mod = event, [':' , modifier];
> 
> Would be the EBNF thing, and I think your rule does indeed match that.
> 
> > event:
> >                 event_symbol |
> >                 event_cache |
> >                 'cpu' '/' event_cpu |
> >                 'tracepoint' '/' event_tracepoint
> >                 'breakpoint' '/' event_breakpoint
> 
> I think I'd like to see something like:
> 
> event   = pmu, '/', event_config 
> 	| event_symbol | event_cache;
> 
> pmu = ? ls /sys/bus/event_source/devices ?;

ok


> (* maybe add some aliasses like you suggest *)
> 
> event_config = (event_predef | event_term), {',', event_term};
> 
> event_predef = ? special name -> raw mapping read from somewhere ?;
> 
> event_term = event_sym, '=', value;
> 
> event_sym = "config" | "config1" | "config2"
> 	  | ? contents of /sys/bus/event_source/devices/$pmu/format ?;

anyone working on the 'format' stuff? ;) I guess thats the place,
where we can stay with hardcoded config[12] so far.. right?


> 
> value = integer | hexint;
> 
> 
> > event_symbol:
> >                 cpu-cycles|cycles
> >                 stalled-cycles-frontend|idle-cycles-frontend
> >                 stalled-cycles-backend|idle-cycles-backend
> >                 instructions
> >                 cache-references
> >                 cache-misses
> >                 branch-instructions|branches
> >                 branch-misses
> >                 bus-cycles
> >                 cpu-clock
> >                 task-clock
> >                 page-faults|faults
> >                 minor-faults
> >                 major-faults
> >                 context-switches|cs
> >                 cpu-migrations|migrations
> >                 alignment-faults
> >                 emulation-faults
> > 
> > event_cache:
> >                 cache_type
> >                 cache_type '-' cache_result_op
> >                 cache_type '-' cache_result_op '-' cache_result_op
> 
> I'd write that as:
> 
> event_cache = cache_type, '-', cache_mod, ['-', cache_xs];
> 
> cache_type = cache_l1d | cache_l1i | cache_llc 
> 	   | cache_dtlb | cache_itlb
> 	   | cache_branch | cache_node;
> 
> cache_mod = cache_load | cache_store | cache_prefetch;
> 
> cache_xs = cache_accesses | cache_misses;
> 
> cache_l1d = "L1-dcache" | ... ;

ok


> 
> etc..
> 
> 
> > event_cpu:
> >                 'raw'    ',' event_cpu_def
> >                 'hw'     ',' event_cpu_def
> >                 'cache'  ',' event_cpu_def
> 
> I think these are superfluous and we could deduce them from the actual
> event_term's used. Something using "config" will be a raw event etc..

ok


> 
> > 
> > event_cpu_def:
> >                 event_cpu_ass ',' event_cpu_ass |
> >                 event_cpu_ass
> > 
> > event_cpu_ass:
> >                 event_cpu_elem '=' value
> 
> Hehehe, you said 'ass', hehe.
eh.. you're seeing things ;) just best fitting abbrev..


> 
> 
> > event_tracepoint:
> >                 system ':' tracepoint
> > 
> > event_breakpoint:
> >                 addr ':' type
> 
> Right, something like that.
> 
> > 
> > modifier:
> >                 [ukhp]{1,4} 
> 
> I think you need at least 5, or you can write it like:
> 
> modifier = ['u'], ['k'], ['h'], [3*'p'];
> 
> Also, I think we grew a few more modifiers with some of the perf kvm
> guest muck.

yep, I'll update it..
I'll prepare another patch version including above changes

thanks,
jirka

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

* Re: new syntax for perf event
  2012-01-09 15:28                   ` Jiri Olsa
@ 2012-01-09 15:43                     ` Peter Zijlstra
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
  1 sibling, 0 replies; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-09 15:43 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Mon, 2012-01-09 at 16:28 +0100, Jiri Olsa wrote:
> anyone working on the 'format' stuff? ;) I guess thats the place,
> where we can stay with hardcoded config[12] so far.. right?

Nobody afaik. Its just one of those things that would be nice to have
and are on the todo list someplace. So yeah, you can keep the hardcoded
config things for now.

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

* [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-09 15:28                   ` Jiri Olsa
  2012-01-09 15:43                     ` Peter Zijlstra
@ 2012-01-16 12:31                     ` Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
                                         ` (11 more replies)
  1 sibling, 12 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel

hi,
I'd never imagine how much code I need to introduce before
I could push through the event grouping patch.. ;)

Here's new version of event parsing patchset. To summarize:
 - adding event parser bison/flex generator
 - the event syntax stays as it was
 - adding event format file sysfs attribute
   for pmu device
 - adding new syntax to specify raw events based
   on the sysfs pmu's format attribute
   eg. "cpu/config=1,config1=2,config2=3/u"

There are helping patches 1-4, which I did not want to
mangle with the actual change. Patches 5-9 implement
the feature itself.

I consider this patchset as RFC. Everything seems to work,
but I did not want to spend much time over it before any
fundamental design comments.. ;)

Attached patches:
 1/9 perf, tool: Make perf_evlist__splice_list_tail global
 2/9 perf, tool: Remove unused functions from debugfs object
 3/9 perf, tool: Add sysfs mountpoint interface
 4/9 perf, tool: Add bitmap_or function into bitmap object
 5/9 perf: Add sysfs format attribute for pmu device
 6/9 perf, tool: Add parser generator for events parsing
 7/9 perf, tool: Add config options support for event parsing
 8/9 perf, tool: Add perf pmu object to access pmu format
 9/9 perf, tool: Add support to specify pmu style event

thanks for comments,
jirka
---
 include/linux/perf_event.h             |    6 +
 kernel/events/core.c                   |   23 +
 tools/perf/Makefile                    |   32 +
 tools/perf/builtin-test.c              |   46 +
 tools/perf/util/bitmap.c               |   10 +
 tools/perf/util/debugfs.c              |  141 --
 tools/perf/util/debugfs.h              |    6 -
 tools/perf/util/evlist.c               |    6 +-
 tools/perf/util/evlist.h               |    5 +
 tools/perf/util/include/linux/bitmap.h |   11 +
 tools/perf/util/parse-events-bison.c   | 1813 ++++++++++++++++++++++++++
 tools/perf/util/parse-events-bison.h   |   81 ++
 tools/perf/util/parse-events-flex.c    | 2232 ++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events-flex.h    |  316 +++++
 tools/perf/util/parse-events.c         |  552 ++++-----
 tools/perf/util/parse-events.h         |   37 +
 tools/perf/util/parse-events.l         |  107 ++
 tools/perf/util/parse-events.y         |  191 +++
 tools/perf/util/pmu-bison.c            | 1623 +++++++++++++++++++++++
 tools/perf/util/pmu-bison.h            |   72 +
 tools/perf/util/pmu-flex.c             | 1821 ++++++++++++++++++++++++++
 tools/perf/util/pmu-flex.h             |  316 +++++
 tools/perf/util/pmu.c                  |  409 ++++++
 tools/perf/util/pmu.h                  |   42 +
 tools/perf/util/pmu.l                  |   50 +
 tools/perf/util/pmu.y                  |   76 ++
 tools/perf/util/sysfs.c                |   60 +
 tools/perf/util/sysfs.h                |    6 +
 28 files changed, 9613 insertions(+), 477 deletions(-)

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

* [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 2/9] perf, tool: Remove unused functions from debugfs object Jiri Olsa
                                         ` (10 subsequent siblings)
  11 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Making perf_evlist__splice_list_tail globaly accessible.
It is used in the upcomming paches.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/evlist.c |    6 +++---
 tools/perf/util/evlist.h |    5 +++++
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3f16e08..b918e30 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -97,9 +97,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 	++evlist->nr_entries;
 }
 
-static void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
-					  struct list_head *list,
-					  int nr_entries)
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries)
 {
 	list_splice_tail(list, &evlist->entries);
 	evlist->nr_entries += nr_entries;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 8922aee..6ec2f6e 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -117,4 +117,9 @@ u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
 
 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
+
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries);
+
 #endif /* __PERF_EVLIST_H */
-- 
1.7.6.5


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

* [PATCH 2/9] perf, tool: Remove unused functions from debugfs object
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 3/9] perf, tool: Add sysfs mountpoint interface Jiri Olsa
                                         ` (9 subsequent siblings)
  11 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Following debugfs object functions are not referenced
within the code:

  int debugfs_valid_entry(const char *path);
  int debugfs_umount(void);
  int debugfs_write(const char *entry, const char *value);
  int debugfs_read(const char *entry, char *buffer, size_t size);
  void debugfs_force_cleanup(void);
  int debugfs_make_path(const char *element, char *buffer, int size);

Removing them.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/debugfs.c |  141 ---------------------------------------------
 tools/perf/util/debugfs.h |    6 --
 2 files changed, 0 insertions(+), 147 deletions(-)

diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index ffc35e7..dd8b193 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -15,32 +15,6 @@ static const char *debugfs_known_mountpoints[] = {
 	0,
 };
 
-/* use this to force a umount */
-void debugfs_force_cleanup(void)
-{
-	debugfs_find_mountpoint();
-	debugfs_premounted = 0;
-	debugfs_umount();
-}
-
-/* construct a full path to a debugfs element */
-int debugfs_make_path(const char *element, char *buffer, int size)
-{
-	int len;
-
-	if (strlen(debugfs_mountpoint) == 0) {
-		buffer[0] = '\0';
-		return -1;
-	}
-
-	len = strlen(debugfs_mountpoint) + strlen(element) + 1;
-	if (len >= size)
-		return len+1;
-
-	snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
-	return 0;
-}
-
 static int debugfs_found;
 
 /* find the path to the mounted debugfs */
@@ -97,17 +71,6 @@ int debugfs_valid_mountpoint(const char *debugfs)
 	return 0;
 }
 
-
-int debugfs_valid_entry(const char *path)
-{
-	struct stat st;
-
-	if (stat(path, &st))
-		return -errno;
-
-	return 0;
-}
-
 static void debugfs_set_tracing_events_path(const char *mountpoint)
 {
 	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -149,107 +112,3 @@ void debugfs_set_path(const char *mountpoint)
 	snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
 	debugfs_set_tracing_events_path(mountpoint);
 }
-
-/* umount the debugfs */
-
-int debugfs_umount(void)
-{
-	char umountcmd[128];
-	int ret;
-
-	/* if it was already mounted, leave it */
-	if (debugfs_premounted)
-		return 0;
-
-	/* make sure it's a valid mount point */
-	ret = debugfs_valid_mountpoint(debugfs_mountpoint);
-	if (ret)
-		return ret;
-
-	snprintf(umountcmd, sizeof(umountcmd),
-		 "/bin/umount %s", debugfs_mountpoint);
-	return system(umountcmd);
-}
-
-int debugfs_write(const char *entry, const char *value)
-{
-	char path[PATH_MAX + 1];
-	int ret, count;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* get how many chars we're going to write */
-	count = strlen(value);
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDWR);
-	if (fd < 0)
-		return -errno;
-
-	while (count > 0) {
-		/* write it */
-		ret = write(fd, value, count);
-		if (ret <= 0) {
-			if (ret == EAGAIN)
-				continue;
-			close(fd);
-			return -errno;
-		}
-		count -= ret;
-	}
-
-	/* close it */
-	close(fd);
-
-	/* return success */
-	return 0;
-}
-
-/*
- * read a debugfs entry
- * returns the number of chars read or a negative errno
- */
-int debugfs_read(const char *entry, char *buffer, size_t size)
-{
-	char path[PATH_MAX + 1];
-	int ret;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDONLY);
-	if (fd < 0)
-		return -errno;
-
-	do {
-		/* read it */
-		ret = read(fd, buffer, size);
-		if (ret == 0) {
-			close(fd);
-			return EOF;
-		}
-	} while (ret < 0 && errno == EAGAIN);
-
-	/* close it */
-	close(fd);
-
-	/* make *sure* there's a null character at the end */
-	buffer[ret] = '\0';
-
-	/* return the number of chars read */
-	return ret;
-}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 4a878f7..68f3e87 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -3,14 +3,8 @@
 
 const char *debugfs_find_mountpoint(void);
 int debugfs_valid_mountpoint(const char *debugfs);
-int debugfs_valid_entry(const char *path);
 char *debugfs_mount(const char *mountpoint);
-int debugfs_umount(void);
 void debugfs_set_path(const char *mountpoint);
-int debugfs_write(const char *entry, const char *value);
-int debugfs_read(const char *entry, char *buffer, size_t size);
-void debugfs_force_cleanup(void);
-int debugfs_make_path(const char *element, char *buffer, int size);
 
 extern char debugfs_mountpoint[];
 extern char tracing_events_path[];
-- 
1.7.6.5


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

* [PATCH 3/9] perf, tool: Add sysfs mountpoint interface
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 2/9] perf, tool: Remove unused functions from debugfs object Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object Jiri Olsa
                                         ` (8 subsequent siblings)
  11 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding sysfs object to provide sysfs mount information
in the same way as debugfs object does.

The object provides following function:
  sysfs_find_mountpoint

which returns the sysfs mount point.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile     |    2 +
 tools/perf/util/sysfs.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/sysfs.h |    6 ++++
 3 files changed, 68 insertions(+), 0 deletions(-)
 create mode 100644 tools/perf/util/sysfs.c
 create mode 100644 tools/perf/util/sysfs.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index ac86d67..41daa92 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -259,6 +259,7 @@ LIB_H += util/callchain.h
 LIB_H += util/build-id.h
 LIB_H += util/debug.h
 LIB_H += util/debugfs.h
+LIB_H += util/sysfs.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
 LIB_H += util/evlist.h
@@ -305,6 +306,7 @@ LIB_OBJS += $(OUTPUT)util/build-id.o
 LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
+LIB_OBJS += $(OUTPUT)util/sysfs.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
 LIB_OBJS += $(OUTPUT)util/evlist.o
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
new file mode 100644
index 0000000..0368bba
--- /dev/null
+++ b/tools/perf/util/sysfs.c
@@ -0,0 +1,60 @@
+
+#include "util.h"
+#include "sysfs.h"
+
+static const char *sysfs_known_mountpoints[] = {
+	"/sys",
+	0,
+};
+
+static int sysfs_found;
+char sysfs_mountpoint[PATH_MAX];
+
+static int sysfs_valid_mountpoint(const char *sysfs)
+{
+	struct statfs st_fs;
+
+	if (statfs(sysfs, &st_fs) < 0)
+		return -ENOENT;
+	else if (st_fs.f_type != (long) SYSFS_MAGIC)
+		return -ENOENT;
+
+	return 0;
+}
+
+const char *sysfs_find_mountpoint(void)
+{
+	const char **ptr;
+	char type[100];
+	FILE *fp;
+
+	if (sysfs_found)
+		return (const char *) sysfs_mountpoint;
+
+	ptr = sysfs_known_mountpoints;
+	while (*ptr) {
+		if (sysfs_valid_mountpoint(*ptr) == 0) {
+			sysfs_found = 1;
+			strcpy(sysfs_mountpoint, *ptr);
+			return sysfs_mountpoint;
+		}
+		ptr++;
+	}
+
+	/* give up and parse /proc/mounts */
+	fp = fopen("/proc/mounts", "r");
+	if (fp == NULL)
+		return NULL;
+
+	while (!sysfs_found &&
+	       fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
+		      sysfs_mountpoint, type) == 2) {
+
+		if (strcmp(type, "sysfs") == 0)
+			sysfs_found = 1;
+	}
+
+	fclose(fp);
+
+	return sysfs_found ? sysfs_mountpoint : NULL;
+}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
new file mode 100644
index 0000000..a813b72
--- /dev/null
+++ b/tools/perf/util/sysfs.h
@@ -0,0 +1,6 @@
+#ifndef __SYSFS_H__
+#define __SYSFS_H__
+
+const char *sysfs_find_mountpoint(void);
+
+#endif /* __DEBUGFS_H__ */
-- 
1.7.6.5


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

* [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (2 preceding siblings ...)
  2012-01-16 12:31                       ` [PATCH 3/9] perf, tool: Add sysfs mountpoint interface Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 5/9] perf: Add sysfs format attribute for pmu device Jiri Olsa
                                         ` (7 subsequent siblings)
  11 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding implementation os bitmap_or function to the bitmap
object. It is stolen from the kernel lib/bitmap.o object.

It is used in upcomming patches.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/bitmap.c               |   10 ++++++++++
 tools/perf/util/include/linux/bitmap.h |   11 +++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
index 5e230ac..0a1adc1 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/perf/util/bitmap.c
@@ -19,3 +19,13 @@ int __bitmap_weight(const unsigned long *bitmap, int bits)
 
 	return w;
 }
+
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits)
+{
+	int k;
+	int nr = BITS_TO_LONGS(bits);
+
+	for (k = 0; k < nr; k++)
+		dst[k] = bitmap1[k] | bitmap2[k];
+}
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index eda4416..bb162e4 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -5,6 +5,8 @@
 #include <linux/bitops.h>
 
 int __bitmap_weight(const unsigned long *bitmap, int bits);
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits);
 
 #define BITMAP_LAST_WORD_MASK(nbits)					\
 (									\
@@ -32,4 +34,13 @@ static inline int bitmap_weight(const unsigned long *src, int nbits)
 	return __bitmap_weight(src, nbits);
 }
 
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+			     const unsigned long *src2, int nbits)
+{
+	if (small_const_nbits(nbits))
+		*dst = *src1 | *src2;
+	else
+		__bitmap_or(dst, src1, src2, nbits);
+}
+
 #endif /* _PERF_BITOPS_H */
-- 
1.7.6.5


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

* [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (3 preceding siblings ...)
  2012-01-16 12:31                       ` [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-23 15:13                         ` Eric W. Biederman
  2012-01-26 16:26                         ` Peter Zijlstra
  2012-01-16 12:31                       ` [PATCH 6/9] perf, tool: Add parser generator for events parsing Jiri Olsa
                                         ` (6 subsequent siblings)
  11 siblings, 2 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding 'format' attribute for pmu device that contains
a syntax description on how to construct raw events.

The event configuration is described in following
struct pefr_event_attr attributes:

  config
  config1
  config2

Each line of the format file describes mapping of name
and bitfield definition within one of abve attributes.

eg:
  event   config:0-7
  umask   config:8-15
  usr     config:16
  os      config:17
  edge    config:18
  any     config:21
  inv     config:23
  cmask   config:24-31

Line syntax:
  line:      NAME config ':' bits
  config:    'config' | 'config1' | 'config2"
  bits:      bits ',' bit_term | bit_term
  bit_term:  VALUE '-' VALUE | VALUE

Adding event_format callback to the struct pmu, which provides
the format information. The pmu shall override this function
and provide its own specific format information.

If not overloaded the default format information is used:

  config  config:0-63
  config1 config1:0-63
  config2 config2:0-63

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 include/linux/perf_event.h |    6 ++++++
 kernel/events/core.c       |   23 +++++++++++++++++++++++
 2 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0b91db2..bf17d15 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -638,6 +638,12 @@ struct pmu {
 	 */
 	int (*event_init)		(struct perf_event *event);
 
+	/*
+	 * Provide event raw format information for sysfs
+	 * 'format' attribute.
+	 */
+	ssize_t (*event_format)		(struct pmu *pmu, char *page);
+
 #define PERF_EF_START	0x01		/* start the counter when adding    */
 #define PERF_EF_RELOAD	0x02		/* reload the counter when starting */
 #define PERF_EF_UPDATE	0x04		/* update the counter when stopping */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 91fb68a..3bec8ca 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5492,8 +5492,31 @@ type_show(struct device *dev, struct device_attribute *attr, char *page)
 	return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type);
 }
 
+static ssize_t perf_default_event_format(struct pmu *pmu, char *page)
+{
+	ssize_t ret;
+
+	ret  = sprintf(page,       "config  config:0-63\n");
+	ret += sprintf(page + ret, "config1 config1:0-63\n");
+	ret += sprintf(page + ret, "config2 config2:0-63\n");
+
+	return ret;
+}
+
+static ssize_t
+format_show(struct device *dev, struct device_attribute *attr, char *page)
+{
+	struct pmu *pmu = dev_get_drvdata(dev);
+
+	if (pmu->event_format)
+		pmu->event_format(pmu, page);
+
+	return perf_default_event_format(pmu, page);
+}
+
 static struct device_attribute pmu_dev_attrs[] = {
        __ATTR_RO(type),
+       __ATTR_RO(format),
        __ATTR_NULL,
 };
 
-- 
1.7.6.5


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

* [PATCH 6/9] perf, tool: Add parser generator for events parsing
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (4 preceding siblings ...)
  2012-01-16 12:31                       ` [PATCH 5/9] perf: Add sysfs format attribute for pmu device Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-24 16:02                         ` Peter Zijlstra
  2012-01-16 12:31                       ` [PATCH 7/9] perf, tool: Add config options support for event parsing Jiri Olsa
                                         ` (5 subsequent siblings)
  11 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Changing event parsing to use flex/bison parse generator.
The event syntax stays as it was.

grammar description:

events: events ',' event | event

event:  event_def PE_MODIFIER_EVENT | event_def

event_def: event_legacy_symbol sep_dc     |
           event_legacy_cache sep_dc      |
           event_legacy_breakpoint sep_dc |
           event_legacy_tracepoint sep_dc |
           event_legacy_numeric sep_dc    |
           event_legacy_raw sep_dc

event_legacy_symbol:      PE_NAME_SYM

event_legacy_cache:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
                          PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT  |
                          PE_NAME_CACHE_TYPE

event_legacy_raw:         PE_SEP_RAW PE_VALUE

event_legacy_numeric:     PE_VALUE ':' PE_VALUE

event_legacy_breakpoint:  PE_SEP_BP ':' PE_VALUE ':' PE_MODIFIER_BP

event_breakpoint_type:    PE_MODIFIER_BPTYPE | empty

PE_NAME_SYM:              cpu-cycles|cycles                              |
                          stalled-cycles-frontend|idle-cycles-frontend   |
                          stalled-cycles-backend|idle-cycles-backend     |
                          instructions                                   |
                          cache-references                               |
                          cache-misses                                   |
                          branch-instructions|branches                   |
                          branch-misses                                  |
                          bus-cycles                                     |
                          cpu-clock                                      |
                          task-clock                                     |
                          page-faults|faults                             |
                          minor-faults                                   |
                          major-faults                                   |
                          context-switches|cs                            |
                          cpu-migrations|migrations                      |
                          alignment-faults                               |
                          emulation-faults

PE_NAME_CACHE_TYPE:       L1-dcache|l1-d|l1d|L1-data             |
                          L1-icache|l1-i|l1i|L1-instruction      |
                          LLC|L2                                 |
                          dTLB|d-tlb|Data-TLB                    |
                          iTLB|i-tlb|Instruction-TLB             |
                          branch|branches|bpu|btb|bpc            |
                          node

PE_NAME_CACHE_OP_RESULT:  load|loads|read                        |
                          store|stores|write                     |
                          prefetch|prefetches                    |
                          speculative-read|speculative-load      |
                          refs|Reference|ops|access              |
                          misses|miss

PE_MODIFIER_EVENT:        [ukhp]{0,5}

PE_MODIFIER_BP:           [rwx]

PE_SEP_BP:                'mem'

PE_SEP_RAW:               'r'

sep_dc:                   ':' |

Added flex/bison files for event grammar parsing. The generated
parser is part of the patch. Added makefile rule 'event-parser'
to generate the parser code out of the bison/flex sources.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile                  |   18 +
 tools/perf/util/parse-events-bison.c | 1715 ++++++++++++++++++++++++++
 tools/perf/util/parse-events-bison.h |   79 ++
 tools/perf/util/parse-events-flex.c  | 2232 ++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events-flex.h  |  316 +++++
 tools/perf/util/parse-events.c       |  486 +++-----
 tools/perf/util/parse-events.h       |   15 +
 tools/perf/util/parse-events.l       |  107 ++
 tools/perf/util/parse-events.y       |  127 ++
 9 files changed, 4757 insertions(+), 338 deletions(-)
 create mode 100644 tools/perf/util/parse-events-bison.c
 create mode 100644 tools/perf/util/parse-events-bison.h
 create mode 100644 tools/perf/util/parse-events-flex.c
 create mode 100644 tools/perf/util/parse-events-flex.h
 create mode 100644 tools/perf/util/parse-events.l
 create mode 100644 tools/perf/util/parse-events.y

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 41daa92..7143dc3 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -47,6 +47,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
+FLEX = $(CROSS_COMPILE)flex
+BISON= $(CROSS_COMPILE)bison
 
 # Additional ARCH settings for x86
 ifeq ($(ARCH),i386)
@@ -343,6 +345,8 @@ LIB_OBJS += $(OUTPUT)util/session.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
+LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
+LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -629,6 +633,8 @@ ifndef V
 	QUIET_LINK     = @echo '   ' LINK $@;
 	QUIET_MKDIR    = @echo '   ' MKDIR $@;
 	QUIET_GEN      = @echo '   ' GEN $@;
+	QUIET_FLEX     = @echo '   ' FLEX $@;
+	QUIET_BISON    = @echo '   ' BISON $@;
 endif
 endif
 
@@ -709,6 +715,9 @@ $(OUTPUT)perf.o perf.spec \
 	$(SCRIPTS) \
 	: $(OUTPUT)PERF-VERSION-FILE
 
+.SUFFIXES:
+.SUFFIXES: .o .c .S .s
+
 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
 $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
@@ -741,6 +750,10 @@ $(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+
+$(OUTPUT)util/parse-events-flex.o: util/parse-events-flex.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
@@ -777,6 +790,7 @@ help:
 	@echo '  html		- make html documentation'
 	@echo '  info		- make GNU info documentation (access with info <foo>)'
 	@echo '  pdf		- make pdf documentation'
+	@echo '  event-parser	- make event parser code'
 	@echo '  TAGS		- use etags to make tag information for source browsing'
 	@echo '  tags		- use ctags to make tag information for source browsing'
 	@echo '  cscope	- use cscope to make interactive browsing database'
@@ -827,6 +841,10 @@ cscope:
 	$(RM) cscope*
 	$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
 
+event-parser:
+	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o util/parse-events-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=util/parse-events-flex.h -t util/parse-events.l > util/parse-events-flex.c
+
 ### Detect prefix changes
 TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
              $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
new file mode 100644
index 0000000..20fca26
--- /dev/null
+++ b/tools/perf/util/parse-events-bison.c
@@ -0,0 +1,1715 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.4.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse         parse_events_parse
+#define yylex           parse_events_lex
+#define yyerror         parse_events_error
+#define yylval          parse_events_lval
+#define yychar          parse_events_char
+#define yydebug         parse_events_debug
+#define yynerrs         parse_events_nerrs
+
+
+/* Copy the first part of user declarations.  */
+
+/* Line 189 of yacc.c  */
+#line 6 "util/parse-events.y"
+
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+
+
+/* Line 189 of yacc.c  */
+#line 101 "util/parse-events-bison.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PE_VALUE = 258,
+     PE_VALUE_SYM = 259,
+     PE_RAW = 260,
+     PE_NAME = 261,
+     PE_MODIFIER_EVENT = 262,
+     PE_MODIFIER_BP = 263,
+     PE_NAME_CACHE_TYPE = 264,
+     PE_NAME_CACHE_OP_RESULT = 265,
+     PE_PREFIX_MEM = 266,
+     PE_PREFIX_RAW = 267,
+     PE_ERROR = 268
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c  */
+#line 42 "util/parse-events.y"
+
+	char *str;
+	unsigned long num;
+
+
+
+/* Line 214 of yacc.c  */
+#line 157 "util/parse-events-bison.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 264 of yacc.c  */
+#line 169 "util/parse-events-bison.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  20
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   27
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  17
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  11
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  22
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  39
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   268
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    14,    15,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    16,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     7,     9,    12,    14,    17,    20,    22,
+      25,    28,    31,    33,    39,    43,    45,    51,    55,    59,
+      63,    65,    67
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      18,     0,    -1,    18,    14,    19,    -1,    19,    -1,    20,
+       7,    -1,    20,    -1,    21,    27,    -1,    22,    27,    -1,
+      23,    -1,    24,    27,    -1,    25,    27,    -1,    26,    27,
+      -1,     4,    -1,     9,    15,    10,    15,    10,    -1,     9,
+      15,    10,    -1,     9,    -1,    11,     3,    16,     8,    27,
+      -1,    11,     3,    27,    -1,     6,    16,     6,    -1,     3,
+      16,     3,    -1,     5,    -1,    16,    -1,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,    49,    49,    49,    52,    57,    59,    60,    61,    62,
+      63,    64,    67,    76,    81,    86,    92,    97,   103,   109,
+     115,   120,   120
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "PE_VALUE", "PE_VALUE_SYM", "PE_RAW",
+  "PE_NAME", "PE_MODIFIER_EVENT", "PE_MODIFIER_BP", "PE_NAME_CACHE_TYPE",
+  "PE_NAME_CACHE_OP_RESULT", "PE_PREFIX_MEM", "PE_PREFIX_RAW", "PE_ERROR",
+  "','", "'-'", "':'", "$accept", "events", "event", "event_def",
+  "event_legacy_symbol", "event_legacy_cache", "event_legacy_mem",
+  "event_legacy_tracepoint", "event_legacy_numeric", "event_legacy_raw",
+  "sep_dc", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,    44,    45,    58
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    17,    18,    18,    19,    19,    20,    20,    20,    20,
+      20,    20,    21,    22,    22,    22,    23,    23,    24,    25,
+      26,    27,    27
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     3,     1,     2,     1,     2,     2,     1,     2,
+       2,     2,     1,     5,     3,     1,     5,     3,     3,     3,
+       1,     1,     0
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,     0,    12,    20,     0,    15,     0,     0,     3,     5,
+      22,    22,     8,    22,    22,    22,     0,     0,     0,    22,
+       1,     0,     4,    21,     6,     7,     9,    10,    11,    19,
+      18,    14,    21,    17,     2,     0,    22,    13,    16
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      24
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -12
+static const yytype_int8 yypact[] =
+{
+       7,   -10,   -12,   -12,    -9,    -6,     2,     1,   -12,    10,
+      -2,    -2,   -12,    -2,    -2,    -2,    16,    14,    11,     6,
+     -12,     7,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
+     -12,     8,    18,   -12,   -12,    17,    -2,   -12,   -12
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -12,   -12,     3,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
+     -11
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+      25,    20,    26,    27,    28,    19,    16,    17,    33,    18,
+       1,     2,     3,     4,    23,    21,     5,    22,     6,    29,
+      30,    31,    32,    35,    34,    38,    36,    37
+};
+
+static const yytype_uint8 yycheck[] =
+{
+      11,     0,    13,    14,    15,     3,    16,    16,    19,    15,
+       3,     4,     5,     6,    16,    14,     9,     7,    11,     3,
+       6,    10,    16,    15,    21,    36,     8,    10
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,     4,     5,     6,     9,    11,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    16,    16,    15,     3,
+       0,    14,     7,    16,    27,    27,    27,    27,    27,     3,
+       6,    10,    16,    27,    19,    15,     8,    10,    27
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  However,
+   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
+   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+   discussed.  */
+
+#define YYFAIL		goto yyerrlab
+#if defined YYFAIL
+  /* This is here to suppress warnings from the GCC cpp's
+     -Wunused-macros.  Normally we don't worry about that warning, but
+     some users do, and we want to make it easy for users to remove
+     YYFAIL uses, which will produce warnings from Bison 2.5.  */
+#endif
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (list, idx, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, list, idx); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list, int *idx)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (list);
+  YYUSE (idx);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list, int *idx)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, list, idx)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, struct list_head *list, int *idx)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, list, idx)
+    YYSTYPE *yyvsp;
+    int yyrule;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       , list, idx);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule, list, idx); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct list_head *list, int *idx)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, list, idx)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (list);
+  YYUSE (idx);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (struct list_head *list, int *idx);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (struct list_head *list, int *idx)
+#else
+int
+yyparse (list, idx)
+    struct list_head *list;
+    int *idx;
+#endif
+#endif
+{
+
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+
+/* Line 1464 of yacc.c  */
+#line 53 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_modifier(list, (yyvsp[(2) - (2)].str)));
+;}
+    break;
+
+  case 12:
+
+/* Line 1464 of yacc.c  */
+#line 68 "util/parse-events.y"
+    {
+	int type = (yyvsp[(1) - (1)].num) >> 16;
+	int config = (yyvsp[(1) - (1)].num) & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+;}
+    break;
+
+  case 13:
+
+/* Line 1464 of yacc.c  */
+#line 77 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
+;}
+    break;
+
+  case 14:
+
+/* Line 1464 of yacc.c  */
+#line 82 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
+;}
+    break;
+
+  case 15:
+
+/* Line 1464 of yacc.c  */
+#line 87 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
+;}
+    break;
+
+  case 16:
+
+/* Line 1464 of yacc.c  */
+#line 93 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
+;}
+    break;
+
+  case 17:
+
+/* Line 1464 of yacc.c  */
+#line 98 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
+;}
+    break;
+
+  case 18:
+
+/* Line 1464 of yacc.c  */
+#line 104 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
+;}
+    break;
+
+  case 19:
+
+/* Line 1464 of yacc.c  */
+#line 110 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num)));
+;}
+    break;
+
+  case 20:
+
+/* Line 1464 of yacc.c  */
+#line 116 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num)));
+;}
+    break;
+
+
+
+/* Line 1464 of yacc.c  */
+#line 1497 "util/parse-events-bison.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (list, idx, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (list, idx, yymsg);
+	  }
+	else
+	  {
+	    yyerror (list, idx, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, list, idx);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, list, idx);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (list, idx, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, list, idx);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, list, idx);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+/* Line 1684 of yacc.c  */
+#line 122 "util/parse-events.y"
+
+
+void parse_events_error(struct list_head *list __used, int *idx __used,
+			char const *msg __used)
+{
+}
+
diff --git a/tools/perf/util/parse-events-bison.h b/tools/perf/util/parse-events-bison.h
new file mode 100644
index 0000000..097a632
--- /dev/null
+++ b/tools/perf/util/parse-events-bison.h
@@ -0,0 +1,79 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PE_VALUE = 258,
+     PE_VALUE_SYM = 259,
+     PE_RAW = 260,
+     PE_NAME = 261,
+     PE_MODIFIER_EVENT = 262,
+     PE_MODIFIER_BP = 263,
+     PE_NAME_CACHE_TYPE = 264,
+     PE_NAME_CACHE_OP_RESULT = 265,
+     PE_PREFIX_MEM = 266,
+     PE_PREFIX_RAW = 267,
+     PE_ERROR = 268
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1685 of yacc.c  */
+#line 42 "util/parse-events.y"
+
+	char *str;
+	unsigned long num;
+
+
+
+/* Line 1685 of yacc.c  */
+#line 71 "util/parse-events-bison.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE parse_events_lval;
+
+
diff --git a/tools/perf/util/parse-events-flex.c b/tools/perf/util/parse-events-flex.c
new file mode 100644
index 0000000..c74f6f6
--- /dev/null
+++ b/tools/perf/util/parse-events-flex.c
@@ -0,0 +1,2232 @@
+
+#line 3 "<stdout>"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer parse_events__create_buffer
+#define yy_delete_buffer parse_events__delete_buffer
+#define yy_flex_debug parse_events__flex_debug
+#define yy_init_buffer parse_events__init_buffer
+#define yy_flush_buffer parse_events__flush_buffer
+#define yy_load_buffer_state parse_events__load_buffer_state
+#define yy_switch_to_buffer parse_events__switch_to_buffer
+#define yyin parse_events_in
+#define yyleng parse_events_leng
+#define yylex parse_events_lex
+#define yylineno parse_events_lineno
+#define yyout parse_events_out
+#define yyrestart parse_events_restart
+#define yytext parse_events_text
+#define yywrap parse_events_wrap
+#define yyalloc parse_events_alloc
+#define yyrealloc parse_events_realloc
+#define yyfree parse_events_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE parse_events_restart(parse_events_in  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int parse_events_leng;
+
+extern FILE *parse_events_in, *parse_events_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up parse_events_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up parse_events_text again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via parse_events_restart()), so that the user can continue scanning by
+	 * just pointing parse_events_in at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when parse_events_text is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int parse_events_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow parse_events_wrap()'s to do buffer switches
+ * instead of setting up a fresh parse_events_in.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void parse_events_restart (FILE *input_file  );
+void parse_events__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE parse_events__create_buffer (FILE *file,int size  );
+void parse_events__delete_buffer (YY_BUFFER_STATE b  );
+void parse_events__flush_buffer (YY_BUFFER_STATE b  );
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void parse_events_pop_buffer_state (void );
+
+static void parse_events_ensure_buffer_stack (void );
+static void parse_events__load_buffer_state (void );
+static void parse_events__init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER parse_events__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE parse_events__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE parse_events__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE parse_events__scan_bytes (yyconst char *bytes,int len  );
+
+void *parse_events_alloc (yy_size_t  );
+void *parse_events_realloc (void *,yy_size_t  );
+void parse_events_free (void *  );
+
+#define yy_new_buffer parse_events__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        parse_events_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        parse_events_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *parse_events_in = (FILE *) 0, *parse_events_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int parse_events_lineno;
+
+int parse_events_lineno = 1;
+
+extern char *parse_events_text;
+#define yytext_ptr parse_events_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up parse_events_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	parse_events_leng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 45
+#define YY_END_OF_BUFFER 46
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[427] =
+    {   0,
+        0,    0,   46,   45,   39,   42,   41,   40,   35,   35,
+       43,   44,   39,   39,   39,   39,   39,   39,   39,   39,
+       39,   39,   37,   39,   39,   39,   39,   39,   37,   38,
+       39,   39,   38,   38,   39,   35,    0,   39,   39,   39,
+       21,   39,   39,   39,   39,   39,   39,   39,   39,   39,
+       39,   39,   15,   39,    0,   39,   39,   39,   37,    0,
+       39,   39,   39,   39,   39,   39,   39,   39,   39,   39,
+       39,   39,   33,   33,   39,   39,   39,   39,   39,   36,
+       39,   39,    0,   39,   39,   39,   24,   39,   39,   39,
+       39,   39,   39,    0,   39,   39,   39,   37,    0,   39,
+
+       39,   39,    0,   19,   20,   39,   39,   39,   39,   39,
+       39,   39,   30,   39,   39,   39,   39,   39,   39,   39,
+       39,   39,   39,   39,   39,    0,    0,   39,   39,   39,
+       39,    0,   39,   39,    0,   39,    0,   22,   39,   39,
+       37,    0,   23,   39,   39,   19,   20,   26,   39,   32,
+       39,   39,   31,   25,   39,   39,   34,   26,   39,   39,
+       39,   39,   39,    0,   39,    0,    0,    0,    0,   39,
+       39,   39,   39,    0,   39,   39,    0,    0,   39,   22,
+       39,   39,   37,   23,    0,   39,   39,   39,   39,   39,
+        0,   39,   39,   39,   27,    0,   27,    0,   39,    0,
+
+        0,    0,    0,   39,   39,   24,    0,    0,   39,    0,
+        0,    0,    1,   39,   12,    0,   39,    0,   39,    0,
+       31,    0,   39,   39,   39,    0,    0,   39,    0,    0,
+        0,   39,   39,    0,   39,    0,    0,    0,   39,    0,
+        0,    0,   39,    0,   39,    0,   39,    0,    0,   39,
+       39,   39,    0,   39,    0,    0,    0,   39,   39,    0,
+        0,    7,    0,    0,    0,    0,    0,    0,    0,   39,
+        0,   39,    0,   39,    0,    0,   28,   39,    0,    0,
+       39,    0,   39,    0,    0,    0,    0,    0,    0,   10,
+        0,    0,   39,    0,   39,    0,   39,    0,    0,   39,
+
+       39,    0,    0,   39,    0,    0,    0,    0,    9,    0,
+        0,    0,    1,    0,    0,    0,   39,    0,   16,    0,
+        0,   28,   39,    0,   11,   39,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,   39,    0,    0,   12,
+       39,    0,    0,    0,    0,    0,    0,    6,    0,    0,
+        0,    0,    0,    4,   14,   13,    0,    0,    0,    0,
+        0,    0,    8,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,   16,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,   17,    0,    5,   15,   18,    0,
+
+        0,   29,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    7,    3,    0,    0,    0,    2,
+        0,    0,    0,    0,    0,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    3,    4,    1,    5,    6,    7,    8,
+        9,    9,    9,    9,    9,    9,    9,   10,    1,    1,
+       11,    1,    2,    1,   12,   13,   14,   15,   12,   12,
+        2,    2,   16,    2,    2,   17,    2,    2,    2,    2,
+        2,   18,    2,   19,    2,    2,    2,    2,    2,    2,
+        1,    1,    1,    1,    2,    1,   20,   21,   22,   23,
+
+       24,   25,   26,   27,   28,   29,   30,   31,   32,   33,
+       34,   35,    2,   36,   37,   38,   39,   40,   41,   42,
+       43,    2,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[44] =
+    {   0,
+        1,    2,    1,    1,    1,    3,    3,    3,    3,    1,
+        1,    3,    3,    3,    3,    2,    2,    2,    2,    3,
+        3,    3,    3,    3,    3,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2
+    } ;
+
+static yyconst flex_int16_t yy_base[429] =
+    {   0,
+        0,    0,  503,  504,    0,  504,  504,  504,   38,   42,
+      504,  504,  482,  468,   45,  476,   32,   20,   40,   53,
+      467,  478,   34,   62,   58,   58,  463,  461,   64,   81,
+       32,  475,  458,    0,    0,  100,    0,  455,  455,  487,
+        0,  476,  464,  466,  459,   54,  466,  464,  447,  461,
+      449,  442,    0,  458,  441,  461,  438,  437,   83,  437,
+      457,  442,  435,   92,  451,  441,  437,   86,  445,  430,
+      440,  441,  118,  122,   77,  440,  101,  426,  434,    0,
+      441,  422,   88,  435,  434,  431,    0,  423,  451,  427,
+      415,  448,  420,  419,  436,  417,  416,  106,  415,  432,
+
+      420,  405,  109,    0,    0,  419,  407,  430,  403,  404,
+      400,  412,    0,  411,  409,  155,  410,  395,  409,  399,
+      393,  398,  389,  422,  389,  118,   46,  388,  386,  389,
+      399,  398,  395,  394,   82,  393,  395,    0,  395,  376,
+      112,  392,    0,  408,  375,  504,  504,  373,  373,  504,
+      388,  371,  382,    0,  401,  380,    0,    0,  364,  371,
+      377,  396,  375,  379,  358,  358,  375,  374,  356,  368,
+      354,  358,  362,  345,  383,  344,  103,  357,  347,  504,
+      345,  345,    0,  504,  359,  341,  375,  340,  373,  339,
+      350,  336,  342,  348,  334,  348,    0,  352,  346,  347,
+
+      344,  343,  326,  330,  338,  148,  339,  112,  322,  325,
+      336,  331,    0,  328,    0,  312,  332,  328,  324,  326,
+        0,  330,  327,  328,  324,  315,  332,  306,  316,  315,
+      305,  318,  306,  121,  301,  306,  308,  311,  330,  311,
+      301,  295,  296,  307,  290,  307,  292,  305,  285,  296,
+      284,  317,  286,  291,  294,  293,  277,  291,  276,  280,
+      284,    0,  287,  273,  284,  271,  277,  282,  285,  271,
+      272,  274,  262,  267,  260,  267,  273,  268,  273,  272,
+      259,  270,  287,  253,  252,  251,  250,  262,  244,  504,
+      247,  245,  278,  257,  246,  248,  241,  246,  238,  238,
+
+      234,  230,  242,  238,  232,  244,  230,  230,  504,  242,
+      229,  236,  504,  235,  237,  224,  227,  221,    0,  220,
+      220,    0,  232,  233,  504,  250,  225,  232,  215,  226,
+      212,  224,  209,  212,  225,  240,  206,  205,  204,  504,
+      236,  208,  219,  203,  197,  196,  197,  504,  200,  210,
+      198,  191,  129,    0,  504,  504,  135,  205,  211,  194,
+      195,  203,  504,  202,  196,  185,  190,  200,  183,  184,
+      193,  179,  202,  176,  175,  188,  187,  504,  172,  187,
+      174,  187,  186,  201,  167,  175,  165,  164,  163,  169,
+      165,  174,  173,  134,  504,  161,  504,  504,  504,  170,
+
+      155,  504,  172,  155,  157,  156,  164,  165,  152,  148,
+      161,  150,  144,  140,  504,  504,  142,  134,  119,  504,
+      123,  119,   94,   68,   75,  504,  179,   68
+    } ;
+
+static yyconst flex_int16_t yy_def[429] =
+    {   0,
+      426,    1,  426,  426,  427,  426,  426,  426,  426,  426,
+      426,  426,  427,  427,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  427,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  427,  427,  426,  428,  427,  427,  427,
+      427,  427,  427,  427,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  427,  426,  427,  427,  427,  427,  426,
+      427,  427,  427,  427,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  427,  427,  427,  427,  427,  427,  428,
+      427,  427,  426,  427,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  426,  427,  427,  427,  427,  426,  427,
+
+      427,  427,  426,  427,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  427,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  427,  427,  426,  426,  427,  427,  427,
+      427,  426,  427,  427,  426,  427,  426,  427,  427,  427,
+      427,  426,  427,  427,  427,  426,  426,  427,  427,  426,
+      427,  427,  427,  427,  427,  427,  116,  427,  427,  427,
+      427,  427,  427,  426,  427,  426,  426,  426,  426,  427,
+      427,  427,  427,  426,  427,  427,  426,  426,  427,  426,
+      427,  427,  427,  426,  426,  427,  427,  427,  427,  427,
+      426,  427,  427,  427,  427,  426,  427,  426,  427,  426,
+
+      426,  426,  426,  427,  427,  427,  426,  426,  427,  426,
+      426,  426,  427,  427,  427,  426,  427,  426,  427,  426,
+      427,  426,  427,  427,  427,  426,  426,  427,  426,  426,
+      426,  427,  427,  426,  427,  426,  426,  426,  427,  426,
+      426,  426,  427,  426,  427,  426,  427,  426,  426,  427,
+      427,  427,  426,  427,  426,  426,  426,  427,  427,  426,
+      426,  427,  426,  426,  426,  426,  426,  426,  426,  427,
+      426,  427,  426,  427,  426,  426,  427,  427,  426,  426,
+      427,  426,  427,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  427,  426,  427,  426,  427,  426,  426,  427,
+
+      427,  426,  426,  427,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  427,  426,  427,  426,
+      426,  427,  427,  426,  426,  427,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  427,  426,  426,  426,
+      427,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  427,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,    0,  426,  426
+    } ;
+
+static yyconst flex_int16_t yy_nxt[548] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   10,   10,   11,
+       12,    5,    5,    5,   13,   14,   15,   16,    5,   17,
+       18,   19,   20,   21,   22,    5,   23,   24,    5,   23,
+       25,   26,   27,   28,   29,   30,   31,   32,   23,    5,
+       33,   34,    5,   36,   36,   36,   36,   36,   36,   36,
+       36,   40,   41,   44,   46,   47,   55,   48,   49,   50,
+       59,   42,   45,   59,   64,   60,   76,  168,   59,   77,
+       80,   56,   59,   51,   52,   87,   53,   66,  169,   37,
+       61,   67,   54,   71,   62,   68,   73,   74,   74,   74,
+       59,   65,   87,   59,   63,  103,  117,  420,   59,   72,
+
+      425,  118,   59,  177,   75,   36,   36,   36,   36,   98,
+      126,  109,   98,  178,  104,  127,  416,   98,  110,  105,
+      120,   98,  111,   74,   74,   74,   74,   74,   74,   74,
+       74,  146,  141,  210,  121,  141,  147,  166,  183,  167,
+      141,  183,  424,  237,  141,  211,  183,  238,  260,  368,
+      183,  234,  261,  369,  403,  423,  422,  421,  404,  116,
+      157,  157,  157,  157,  420,  370,  157,  157,  157,  157,
+      371,  235,  419,  418,  157,  157,  157,  157,  157,  157,
+       35,   35,  417,  416,  415,  414,  413,  412,  411,  410,
+      409,  408,  407,  406,  405,  402,  402,  401,  400,  399,
+
+      398,  397,  396,  395,  394,  393,  392,  391,  390,  389,
+      388,  387,  386,  385,  184,  384,  383,  382,  381,  380,
+      379,  378,  377,  376,  375,  374,  147,  373,  372,  367,
+      366,  365,  364,  363,  362,  361,  360,  359,  358,  357,
+      356,  355,  354,  353,  352,  351,  350,  349,  348,  347,
+      346,  345,  344,  343,  342,  341,  340,  339,  338,  337,
+      336,  335,  334,  333,  332,  331,  330,  329,  328,  327,
+      326,  325,  324,  323,  322,  321,  320,  319,  318,  317,
+      316,  315,  314,  313,  312,  311,  310,  309,  308,  307,
+      306,  305,  304,  303,  302,  301,  300,  299,  298,  297,
+
+      296,  295,  294,  293,  292,  291,  290,  289,  288,  287,
+      286,  285,  284,  283,  113,  282,  147,  146,  281,  280,
+      279,  278,  277,  276,  275,  274,  273,  272,  271,  270,
+      269,  268,  267,  266,  265,  264,  263,  262,  259,  258,
+      257,  256,  255,  254,  180,  253,  252,  251,  250,  249,
+      248,  247,  246,  245,  244,  243,  242,  241,  240,  239,
+      236,  233,  232,  231,  230,  229,  146,  228,  227,  226,
+      197,  225,  224,  223,  222,  221,  220,  219,  218,  217,
+      216,  215,  214,  213,  212,  209,  208,  207,  206,  205,
+      113,  204,  203,  202,  201,  200,  199,  198,  197,  196,
+
+      195,  194,  193,  192,  191,  190,  189,  188,  187,  158,
+      186,  185,  184,  182,  181,  180,  179,  176,  175,  174,
+      173,  172,  171,  170,  165,  164,  163,  162,  161,  160,
+      159,  113,  158,  156,  155,  154,  153,  152,  151,  150,
+      149,  148,  145,  144,  143,  142,  140,  139,  138,  137,
+      136,  135,  134,  133,  132,  131,  130,  129,  128,  125,
+      124,  123,  122,  119,  115,  114,  113,  112,  108,  107,
+      106,  102,  101,  100,   99,   97,   96,   95,   94,   93,
+       92,   91,   90,   89,   87,   88,   86,   85,   84,   41,
+       83,   82,   81,   79,   78,   70,   69,   58,   57,   43,
+
+       39,   38,  426,    3,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426
+    } ;
+
+static yyconst flex_int16_t yy_chk[548] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    9,    9,    9,    9,   10,   10,   10,
+       10,   15,   15,   17,   18,   18,   20,   18,   18,   19,
+       23,   15,   17,   23,   25,   24,   31,  127,   23,   31,
+      428,   20,   23,   19,   19,   46,   19,   26,  127,    9,
+       24,   26,   19,   29,   24,   26,   30,   30,   30,   30,
+       29,   25,   46,   29,   24,   64,   75,  425,   29,   29,
+
+      424,   75,   29,  135,   30,   36,   36,   36,   36,   59,
+       83,   68,   59,  135,   64,   83,  423,   59,   68,   64,
+       77,   59,   68,   73,   73,   73,   73,   74,   74,   74,
+       74,  103,   98,  177,   77,   98,  103,  126,  141,  126,
+       98,  141,  422,  208,   98,  177,  141,  208,  234,  353,
+      141,  206,  234,  353,  394,  421,  419,  418,  394,   73,
+      116,  116,  116,  116,  417,  357,  116,  116,  116,  116,
+      357,  206,  414,  413,  116,  116,  116,  116,  116,  116,
+      427,  427,  412,  411,  410,  409,  408,  407,  406,  405,
+      404,  403,  401,  400,  396,  393,  392,  391,  390,  389,
+
+      388,  387,  386,  385,  384,  383,  382,  381,  380,  379,
+      377,  376,  375,  374,  373,  372,  371,  370,  369,  368,
+      367,  366,  365,  364,  362,  361,  360,  359,  358,  352,
+      351,  350,  349,  347,  346,  345,  344,  343,  342,  341,
+      339,  338,  337,  336,  335,  334,  333,  332,  331,  330,
+      329,  328,  327,  326,  324,  323,  321,  320,  318,  317,
+      316,  315,  314,  312,  311,  310,  308,  307,  306,  305,
+      304,  303,  302,  301,  300,  299,  298,  297,  296,  295,
+      294,  293,  292,  291,  289,  288,  287,  286,  285,  284,
+      283,  282,  281,  280,  279,  278,  277,  276,  275,  274,
+
+      273,  272,  271,  270,  269,  268,  267,  266,  265,  264,
+      263,  261,  260,  259,  258,  257,  256,  255,  254,  253,
+      252,  251,  250,  249,  248,  247,  246,  245,  244,  243,
+      242,  241,  240,  239,  238,  237,  236,  235,  233,  232,
+      231,  230,  229,  228,  227,  226,  225,  224,  223,  222,
+      220,  219,  218,  217,  216,  214,  212,  211,  210,  209,
+      207,  205,  204,  203,  202,  201,  200,  199,  198,  196,
+      195,  194,  193,  192,  191,  190,  189,  188,  187,  186,
+      185,  182,  181,  179,  178,  176,  175,  174,  173,  172,
+      171,  170,  169,  168,  167,  166,  165,  164,  163,  162,
+
+      161,  160,  159,  156,  155,  153,  152,  151,  149,  148,
+      145,  144,  142,  140,  139,  137,  136,  134,  133,  132,
+      131,  130,  129,  128,  125,  124,  123,  122,  121,  120,
+      119,  118,  117,  115,  114,  112,  111,  110,  109,  108,
+      107,  106,  102,  101,  100,   99,   97,   96,   95,   94,
+       93,   92,   91,   90,   89,   88,   86,   85,   84,   82,
+       81,   79,   78,   76,   72,   71,   70,   69,   67,   66,
+       65,   63,   62,   61,   60,   58,   57,   56,   55,   54,
+       52,   51,   50,   49,   48,   47,   45,   44,   43,   42,
+       40,   39,   38,   33,   32,   28,   27,   22,   21,   16,
+
+       14,   13,    3,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  426,  426,  426
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int parse_events__flex_debug;
+int parse_events__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *parse_events_text;
+#line 1 "util/parse-events.l"
+#line 5 "util/parse-events.l"
+#include <errno.h>
+#include "../perf.h"
+#include "parse-events-bison.h"
+
+static int __value(char *str, int base, int token)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(str, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.num = num;
+	return token;
+}
+
+static int value(int base)
+{
+	return __value(parse_events_text, base, PE_VALUE);
+}
+
+static int raw(int base)
+{
+	return __value(parse_events_text + 1, base, PE_RAW);
+}
+
+static int str(int token)
+{
+	parse_events_lval.str = strdup(parse_events_text);
+	return token;
+}
+
+static int sym(int type, int config)
+{
+	parse_events_lval.num = (type << 16) + config;
+	return PE_VALUE_SYM;
+}
+
+#line 768 "<stdout>"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int parse_events_lex_destroy (void );
+
+int parse_events_get_debug (void );
+
+void parse_events_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE parse_events_get_extra (void );
+
+void parse_events_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *parse_events_get_in (void );
+
+void parse_events_set_in  (FILE * in_str  );
+
+FILE *parse_events_get_out (void );
+
+void parse_events_set_out  (FILE * out_str  );
+
+int parse_events_get_leng (void );
+
+char *parse_events_get_text (void );
+
+int parse_events_get_lineno (void );
+
+void parse_events_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int parse_events_wrap (void );
+#else
+extern int parse_events_wrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( parse_events_text, parse_events_leng, 1, parse_events_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		unsigned n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( parse_events_in )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( parse_events_in ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, parse_events_in))==0 && ferror(parse_events_in)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(parse_events_in); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int parse_events_lex (void);
+
+#define YY_DECL int parse_events_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after parse_events_text and parse_events_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 52 "util/parse-events.l"
+
+#line 952 "<stdout>"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! parse_events_in )
+			parse_events_in = stdin;
+
+		if ( ! parse_events_out )
+			parse_events_out = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			parse_events_ensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				parse_events__create_buffer(parse_events_in,YY_BUF_SIZE );
+		}
+
+		parse_events__load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of parse_events_text. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 427 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 504 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 53 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 54 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 55 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 56 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 57 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 58 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 59 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 60 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 61 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 62 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 63 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 64 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 65 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 66 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 67 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 68 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 69 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 70 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+	YY_BREAK
+case 19:
+#line 73 "util/parse-events.l"
+case 20:
+#line 74 "util/parse-events.l"
+case 21:
+#line 75 "util/parse-events.l"
+case 22:
+#line 76 "util/parse-events.l"
+case 23:
+#line 77 "util/parse-events.l"
+case 24:
+#line 78 "util/parse-events.l"
+case 25:
+YY_RULE_SETUP
+#line 78 "util/parse-events.l"
+{ return str(PE_NAME_CACHE_TYPE); }
+	YY_BREAK
+case 26:
+#line 81 "util/parse-events.l"
+case 27:
+#line 82 "util/parse-events.l"
+case 28:
+#line 83 "util/parse-events.l"
+case 29:
+#line 84 "util/parse-events.l"
+case 30:
+#line 85 "util/parse-events.l"
+case 31:
+YY_RULE_SETUP
+#line 85 "util/parse-events.l"
+{ return str(PE_NAME_CACHE_OP_RESULT); }
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 87 "util/parse-events.l"
+{ return PE_PREFIX_MEM; }
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 88 "util/parse-events.l"
+{ return raw(10); }
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 89 "util/parse-events.l"
+{ return raw(16); }
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 90 "util/parse-events.l"
+{ return value(10); }
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 91 "util/parse-events.l"
+{ return value(16); }
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 93 "util/parse-events.l"
+{ return str(PE_MODIFIER_EVENT); }
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 94 "util/parse-events.l"
+{ return str(PE_MODIFIER_BP); }
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 95 "util/parse-events.l"
+{ return str(PE_NAME); }
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 96 "util/parse-events.l"
+{ return '/'; }
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 97 "util/parse-events.l"
+{ return '-'; }
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 98 "util/parse-events.l"
+{ return ','; }
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 99 "util/parse-events.l"
+{ return ':'; }
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 100 "util/parse-events.l"
+{ return '='; }
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 102 "util/parse-events.l"
+ECHO;
+	YY_BREAK
+#line 1227 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed parse_events_in at a new source and called
+			 * parse_events_lex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = parse_events_in;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( parse_events_wrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * parse_events_text, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of parse_events_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					parse_events_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			parse_events_restart(parse_events_in  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) parse_events_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 427 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    	register char *yy_cp = (yy_c_buf_p);
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 427 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 426);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up parse_events_text */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					parse_events_restart(parse_events_in );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( parse_events_wrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve parse_events_text */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void parse_events_restart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        parse_events_ensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE );
+	}
+
+	parse_events__init_buffer(YY_CURRENT_BUFFER,input_file );
+	parse_events__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void parse_events__switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		parse_events_pop_buffer_state();
+	 *		parse_events_push_buffer_state(new_buffer);
+     */
+	parse_events_ensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	parse_events__load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (parse_events_wrap()) processing, but the only time this flag
+	 * is looked at is after parse_events_wrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void parse_events__load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	parse_events_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE parse_events__create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) parse_events_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) parse_events_alloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	parse_events__init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with parse_events__create_buffer()
+ * 
+ */
+    void parse_events__delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		parse_events_free((void *) b->yy_ch_buf  );
+
+	parse_events_free((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a parse_events_restart() or at EOF.
+ */
+    static void parse_events__init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	parse_events__flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then parse_events__init_buffer was _probably_
+     * called from parse_events_restart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void parse_events__flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		parse_events__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	parse_events_ensure_buffer_stack();
+
+	/* This block is copied from parse_events__switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from parse_events__switch_to_buffer. */
+	parse_events__load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void parse_events_pop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	parse_events__delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		parse_events__load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void parse_events_ensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)parse_events_alloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in parse_events_ensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)parse_events_realloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in parse_events_ensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE parse_events__scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) parse_events_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	parse_events__switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to parse_events_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       parse_events__scan_bytes() instead.
+ */
+YY_BUFFER_STATE parse_events__scan_string (yyconst char * yystr )
+{
+    
+	return parse_events__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to parse_events_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE parse_events__scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) parse_events_alloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = parse_events__scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in parse_events__scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up parse_events_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		parse_events_text[parse_events_leng] = (yy_hold_char); \
+		(yy_c_buf_p) = parse_events_text + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		parse_events_leng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int parse_events_get_lineno  (void)
+{
+        
+    return parse_events_lineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *parse_events_get_in  (void)
+{
+        return parse_events_in;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *parse_events_get_out  (void)
+{
+        return parse_events_out;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int parse_events_get_leng  (void)
+{
+        return parse_events_leng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *parse_events_get_text  (void)
+{
+        return parse_events_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void parse_events_set_lineno (int  line_number )
+{
+    
+    parse_events_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see parse_events__switch_to_buffer
+ */
+void parse_events_set_in (FILE *  in_str )
+{
+        parse_events_in = in_str ;
+}
+
+void parse_events_set_out (FILE *  out_str )
+{
+        parse_events_out = out_str ;
+}
+
+int parse_events_get_debug  (void)
+{
+        return parse_events__flex_debug;
+}
+
+void parse_events_set_debug (int  bdebug )
+{
+        parse_events__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from parse_events_lex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    parse_events_in = stdin;
+    parse_events_out = stdout;
+#else
+    parse_events_in = (FILE *) 0;
+    parse_events_out = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * parse_events_lex_init()
+     */
+    return 0;
+}
+
+/* parse_events_lex_destroy is for both reentrant and non-reentrant scanners. */
+int parse_events_lex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		parse_events__delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		parse_events_pop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	parse_events_free((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * parse_events_lex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *parse_events_alloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *parse_events_realloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void parse_events_free (void * ptr )
+{
+	free( (char *) ptr );	/* see parse_events_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 102 "util/parse-events.l"
+
+
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
+
diff --git a/tools/perf/util/parse-events-flex.h b/tools/perf/util/parse-events-flex.h
new file mode 100644
index 0000000..b927f9a
--- /dev/null
+++ b/tools/perf/util/parse-events-flex.h
@@ -0,0 +1,316 @@
+#ifndef parse_events_HEADER_H
+#define parse_events_HEADER_H 1
+#define parse_events_IN_HEADER 1
+
+#line 6 "util/parse-events-flex.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int parse_events_leng;
+
+extern FILE *parse_events_in, *parse_events_out;
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void parse_events_restart (FILE *input_file  );
+void parse_events__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE parse_events__create_buffer (FILE *file,int size  );
+void parse_events__delete_buffer (YY_BUFFER_STATE b  );
+void parse_events__flush_buffer (YY_BUFFER_STATE b  );
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void parse_events_pop_buffer_state (void );
+
+YY_BUFFER_STATE parse_events__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE parse_events__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE parse_events__scan_bytes (yyconst char *bytes,int len  );
+
+void *parse_events_alloc (yy_size_t  );
+void *parse_events_realloc (void *,yy_size_t  );
+void parse_events_free (void *  );
+
+/* Begin user sect3 */
+
+extern int parse_events_lineno;
+
+extern char *parse_events_text;
+#define yytext_ptr parse_events_text
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int parse_events_lex_destroy (void );
+
+int parse_events_get_debug (void );
+
+void parse_events_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE parse_events_get_extra (void );
+
+void parse_events_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *parse_events_get_in (void );
+
+void parse_events_set_in  (FILE * in_str  );
+
+FILE *parse_events_get_out (void );
+
+void parse_events_set_out  (FILE * out_str  );
+
+int parse_events_get_leng (void );
+
+char *parse_events_get_text (void );
+
+int parse_events_get_lineno (void );
+
+void parse_events_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int parse_events_wrap (void );
+#else
+extern int parse_events_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int parse_events_lex (void);
+
+#define YY_DECL int parse_events_lex (void)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 102 "util/parse-events.l"
+
+
+#line 315 "util/parse-events-flex.h"
+#undef parse_events_IN_HEADER
+#endif /* parse_events_HEADER_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b029296..6e50b91 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,9 @@
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
+#include "parse-events-flex.h"
+
+#define MAX_NAME_LEN 100
 
 struct event_symbol {
 	u8		type;
@@ -19,11 +22,7 @@ struct event_symbol {
 	const char	*alias;
 };
 
-enum event_result {
-	EVT_FAILED,
-	EVT_HANDLED,
-	EVT_HANDLED_ALL
-};
+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
@@ -354,7 +353,24 @@ const char *__event_name(int type, u64 config)
 	return "unknown";
 }
 
-static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
+static int add_event(struct list_head *list, int *idx,
+		     struct perf_event_attr *attr, char *name)
+{
+	struct perf_evsel *evsel;
+
+	event_attr_init(attr);
+
+	evsel = perf_evsel__new(attr, (*idx)++);
+	if (!evsel)
+		return -ENOMEM;
+
+	list_add_tail(&evsel->node, list);
+
+	evsel->name = strdup(name);
+	return 0;
+}
+
+static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
 {
 	int i, j;
 	int n, longest = -1;
@@ -362,58 +378,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
 	for (i = 0; i < size; i++) {
 		for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
 			n = strlen(names[i][j]);
-			if (n > longest && !strncasecmp(*str, names[i][j], n))
+			if (n > longest && !strncasecmp(str, names[i][j], n))
 				longest = n;
 		}
-		if (longest > 0) {
-			*str += longest;
+		if (longest > 0)
 			return i;
-		}
 	}
 
 	return -1;
 }
 
-static enum event_result
-parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
+int parse_events_add_cache(struct list_head *list, int *idx,
+			   char *type, char *op_result1, char *op_result2)
 {
-	const char *s = *str;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	int cache_type = -1, cache_op = -1, cache_result = -1;
+	char *op_result[2] = { op_result1, op_result2 };
+	int i, n;
 
-	cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
 	/*
 	 * No fallback - if we cannot get a clear cache type
 	 * then bail out:
 	 */
+	cache_type = parse_aliases(type, hw_cache,
+				   PERF_COUNT_HW_CACHE_MAX);
 	if (cache_type == -1)
-		return EVT_FAILED;
+		return -EINVAL;
+
+	n = snprintf(name, MAX_NAME_LEN, "%s", type);
 
-	while ((cache_op == -1 || cache_result == -1) && *s == '-') {
-		++s;
+	for (i = 0; (i < 2) && (op_result[i]); i++) {
+		char *str = op_result[i];
+
+		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
 		if (cache_op == -1) {
-			cache_op = parse_aliases(&s, hw_cache_op,
-						PERF_COUNT_HW_CACHE_OP_MAX);
+			cache_op = parse_aliases(str, hw_cache_op,
+						 PERF_COUNT_HW_CACHE_OP_MAX);
 			if (cache_op >= 0) {
 				if (!is_cache_op_valid(cache_type, cache_op))
-					return EVT_FAILED;
+					return -EINVAL;
 				continue;
 			}
 		}
 
 		if (cache_result == -1) {
-			cache_result = parse_aliases(&s, hw_cache_result,
+			cache_result = parse_aliases(str, hw_cache_result,
 						PERF_COUNT_HW_CACHE_RESULT_MAX);
 			if (cache_result >= 0)
 				continue;
 		}
-
-		/*
-		 * Can't parse this as a cache op or result, so back up
-		 * to the '-'.
-		 */
-		--s;
-		break;
 	}
 
 	/*
@@ -428,20 +443,17 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
 	if (cache_result == -1)
 		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
 
-	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
-	attr->type = PERF_TYPE_HW_CACHE;
-
-	*str = s;
-	return EVT_HANDLED;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
+	attr.type = PERF_TYPE_HW_CACHE;
+	return add_event(list, idx, &attr, name);
 }
 
-static enum event_result
-parse_single_tracepoint_event(char *sys_name,
-			      const char *evt_name,
-			      unsigned int evt_length,
-			      struct perf_event_attr *attr,
-			      const char **strp)
+static int add_tracepoint(struct list_head *list, int *idx,
+			  char *sys_name, char *evt_name)
 {
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	char evt_path[MAXPATHLEN];
 	char id_buf[4];
 	u64 id;
@@ -452,130 +464,80 @@ parse_single_tracepoint_event(char *sys_name,
 
 	fd = open(evt_path, O_RDONLY);
 	if (fd < 0)
-		return EVT_FAILED;
+		return -1;
 
 	if (read(fd, id_buf, sizeof(id_buf)) < 0) {
 		close(fd);
-		return EVT_FAILED;
+		return -1;
 	}
 
 	close(fd);
 	id = atoll(id_buf);
-	attr->config = id;
-	attr->type = PERF_TYPE_TRACEPOINT;
-	*strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
 
-	attr->sample_type |= PERF_SAMPLE_RAW;
-	attr->sample_type |= PERF_SAMPLE_TIME;
-	attr->sample_type |= PERF_SAMPLE_CPU;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = id;
+	attr.type = PERF_TYPE_TRACEPOINT;
+	attr.sample_type |= PERF_SAMPLE_RAW;
+	attr.sample_type |= PERF_SAMPLE_TIME;
+	attr.sample_type |= PERF_SAMPLE_CPU;
+	attr.sample_period = 1;
 
-	attr->sample_period = 1;
-
-
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
+	return add_event(list, idx, &attr, name);
 }
 
-/* sys + ':' + event + ':' + flags*/
-#define MAX_EVOPT_LEN	(MAX_EVENT_LENGTH * 2 + 2 + 128)
-static enum event_result
-parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
-				const char *evt_exp, char *flags)
+static int add_tracepoint_multi(struct list_head *list, int *idx,
+				char *sys_name, char *evt_name)
 {
 	char evt_path[MAXPATHLEN];
 	struct dirent *evt_ent;
 	DIR *evt_dir;
+	int ret = 0;
 
 	snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
 	evt_dir = opendir(evt_path);
-
 	if (!evt_dir) {
 		perror("Can't open event dir");
-		return EVT_FAILED;
+		return -1;
 	}
 
-	while ((evt_ent = readdir(evt_dir))) {
-		char event_opt[MAX_EVOPT_LEN + 1];
-		int len;
-
+	while (!ret && (evt_ent = readdir(evt_dir))) {
 		if (!strcmp(evt_ent->d_name, ".")
 		    || !strcmp(evt_ent->d_name, "..")
 		    || !strcmp(evt_ent->d_name, "enable")
 		    || !strcmp(evt_ent->d_name, "filter"))
 			continue;
 
-		if (!strglobmatch(evt_ent->d_name, evt_exp))
+		if (!strglobmatch(evt_ent->d_name, evt_name))
 			continue;
 
-		len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
-			       evt_ent->d_name, flags ? ":" : "",
-			       flags ?: "");
-		if (len < 0)
-			return EVT_FAILED;
-
-		if (parse_events(evlist, event_opt, 0))
-			return EVT_FAILED;
+		ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
 	}
 
-	return EVT_HANDLED_ALL;
+	return ret;
 }
 
-static enum event_result
-parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
-		       struct perf_event_attr *attr)
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
+				char *sys, char *event)
 {
-	const char *evt_name;
-	char *flags = NULL, *comma_loc;
-	char sys_name[MAX_EVENT_LENGTH];
-	unsigned int sys_length, evt_length;
-
-	if (debugfs_valid_mountpoint(tracing_events_path))
-		return 0;
+	int ret;
 
-	evt_name = strchr(*strp, ':');
-	if (!evt_name)
-		return EVT_FAILED;
+	ret = debugfs_valid_mountpoint(tracing_events_path);
+	if (ret)
+		return ret;
 
-	sys_length = evt_name - *strp;
-	if (sys_length >= MAX_EVENT_LENGTH)
-		return 0;
-
-	strncpy(sys_name, *strp, sys_length);
-	sys_name[sys_length] = '\0';
-	evt_name = evt_name + 1;
-
-	comma_loc = strchr(evt_name, ',');
-	if (comma_loc) {
-		/* take the event name up to the comma */
-		evt_name = strndup(evt_name, comma_loc - evt_name);
-	}
-	flags = strchr(evt_name, ':');
-	if (flags) {
-		/* split it out: */
-		evt_name = strndup(evt_name, flags - evt_name);
-		flags++;
-	}
-
-	evt_length = strlen(evt_name);
-	if (evt_length >= MAX_EVENT_LENGTH)
-		return EVT_FAILED;
-	if (strpbrk(evt_name, "*?")) {
-		*strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
-		return parse_multiple_tracepoint_event(evlist, sys_name,
-						       evt_name, flags);
-	} else {
-		return parse_single_tracepoint_event(sys_name, evt_name,
-						     evt_length, attr, strp);
-	}
+	return strpbrk(event, "*?") ?
+	       add_tracepoint_multi(list, idx, sys, event) :
+	       add_tracepoint(list, idx, sys, event);
 }
 
-static enum event_result
-parse_breakpoint_type(const char *type, const char **strp,
-		      struct perf_event_attr *attr)
+static int
+parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
 	int i;
 
 	for (i = 0; i < 3; i++) {
-		if (!type[i])
+		if (!type || !type[i])
 			break;
 
 		switch (type[i]) {
@@ -589,164 +551,65 @@ parse_breakpoint_type(const char *type, const char **strp,
 			attr->bp_type |= HW_BREAKPOINT_X;
 			break;
 		default:
-			return EVT_FAILED;
+			return -EINVAL;
 		}
 	}
+
 	if (!attr->bp_type) /* Default */
 		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
 
-	*strp = type + i;
-
-	return EVT_HANDLED;
+	return 0;
 }
 
-static enum event_result
-parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
+				void *ptr, char *type)
 {
-	const char *target;
-	const char *type;
-	char *endaddr;
-	u64 addr;
-	enum event_result err;
-
-	target = strchr(*strp, ':');
-	if (!target)
-		return EVT_FAILED;
-
-	if (strncmp(*strp, "mem", target - *strp) != 0)
-		return EVT_FAILED;
-
-	target++;
-
-	addr = strtoull(target, &endaddr, 0);
-	if (target == endaddr)
-		return EVT_FAILED;
-
-	attr->bp_addr = addr;
-	*strp = endaddr;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 
-	type = strchr(target, ':');
+	memset(&attr, 0, sizeof(attr));
+	attr.bp_addr = (u64) ptr;
 
-	/* If no type is defined, just rw as default */
-	if (!type) {
-		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
-	} else {
-		err = parse_breakpoint_type(++type, strp, attr);
-		if (err == EVT_FAILED)
-			return EVT_FAILED;
-	}
+	if (parse_breakpoint_type(type, &attr))
+		return -EINVAL;
 
 	/*
 	 * We should find a nice way to override the access length
 	 * Provide some defaults for now
 	 */
-	if (attr->bp_type == HW_BREAKPOINT_X)
-		attr->bp_len = sizeof(long);
+	if (attr.bp_type == HW_BREAKPOINT_X)
+		attr.bp_len = sizeof(long);
 	else
-		attr->bp_len = HW_BREAKPOINT_LEN_4;
-
-	attr->type = PERF_TYPE_BREAKPOINT;
-
-	return EVT_HANDLED;
-}
-
-static int check_events(const char *str, unsigned int i)
-{
-	int n;
-
-	n = strlen(event_symbols[i].symbol);
-	if (!strncasecmp(str, event_symbols[i].symbol, n))
-		return n;
+		attr.bp_len = HW_BREAKPOINT_LEN_4;
 
-	n = strlen(event_symbols[i].alias);
-	if (n) {
-		if (!strncasecmp(str, event_symbols[i].alias, n))
-			return n;
-	}
+	attr.type = PERF_TYPE_BREAKPOINT;
 
-	return 0;
+	snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
+	return add_event(list, idx, &attr, name);
 }
 
-static enum event_result
-parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
+int
+parse_events_add_numeric(struct list_head *list, int *idx,
+			 unsigned long type, unsigned long config)
 {
-	const char *str = *strp;
-	unsigned int i;
-	int n;
-
-	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-		n = check_events(str, i);
-		if (n > 0) {
-			attr->type = event_symbols[i].type;
-			attr->config = event_symbols[i].config;
-			*strp = str + n;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
-}
+	struct perf_event_attr attr;
 
-static enum event_result
-parse_raw_event(const char **strp, struct perf_event_attr *attr)
-{
-	const char *str = *strp;
-	u64 config;
-	int n;
-
-	if (*str != 'r')
-		return EVT_FAILED;
-	n = hex2u64(str + 1, &config);
-	if (n > 0) {
-		const char *end = str + n + 1;
-		if (*end != '\0' && *end != ',' && *end != ':')
-			return EVT_FAILED;
-
-		*strp = end;
-		attr->type = PERF_TYPE_RAW;
-		attr->config = config;
-		return EVT_HANDLED;
-	}
-	return EVT_FAILED;
+	memset(&attr, 0, sizeof(attr));
+	attr.type = type;
+	attr.config = config;
+	return add_event(list, idx, &attr,
+			 (char *) __event_name(type, config));
 }
 
-static enum event_result
-parse_numeric_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_modifier(struct list_head *list, char *str)
 {
-	const char *str = *strp;
-	char *endp;
-	unsigned long type;
-	u64 config;
-
-	type = strtoul(str, &endp, 0);
-	if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
-		str = endp + 1;
-		config = strtoul(str, &endp, 0);
-		if (endp > str) {
-			attr->type = type;
-			attr->config = config;
-			*strp = endp;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
-}
-
-static int
-parse_event_modifier(const char **strp, struct perf_event_attr *attr)
-{
-	const char *str = *strp;
+	struct perf_evsel *evsel;
 	int exclude = 0, exclude_GH = 0;
 	int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
 
-	if (!*str)
+	if (str == NULL)
 		return 0;
 
-	if (*str == ',')
-		return 0;
-
-	if (*str++ != ':')
-		return -1;
-
 	while (*str) {
 		if (*str == 'u') {
 			if (!exclude)
@@ -775,111 +638,60 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
 
 		++str;
 	}
-	if (str < *strp + 2)
-		return -1;
 
-	*strp = str;
+	/*
+	 * precise ip:
+	 *
+	 *  0 - SAMPLE_IP can have arbitrary skid
+	 *  1 - SAMPLE_IP must have constant skid
+	 *  2 - SAMPLE_IP requested to have 0 skid
+	 *  3 - SAMPLE_IP must have 0 skid
+	 *
+	 *  See also PERF_RECORD_MISC_EXACT_IP
+	 */
+	if (precise > 3)
+		return -EINVAL;
 
-	attr->exclude_user   = eu;
-	attr->exclude_kernel = ek;
-	attr->exclude_hv     = eh;
-	attr->precise_ip     = precise;
-	attr->exclude_host   = eH;
-	attr->exclude_guest  = eG;
+	list_for_each_entry(evsel, list, node) {
+		evsel->attr.exclude_user   = eu;
+		evsel->attr.exclude_kernel = ek;
+		evsel->attr.exclude_hv     = eh;
+		evsel->attr.precise_ip     = precise;
+		evsel->attr.exclude_host   = eH;
+		evsel->attr.exclude_guest  = eG;
+	}
 
 	return 0;
 }
 
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static enum event_result
-parse_event_symbols(struct perf_evlist *evlist, const char **str,
-		    struct perf_event_attr *attr)
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
-	enum event_result ret;
-
-	ret = parse_tracepoint_event(evlist, str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	struct perf_evsel *evsel, *h;
+	LIST_HEAD(list);
+	YY_BUFFER_STATE buffer;
+	int ret, idx = evlist->nr_entries;
 
-	ret = parse_raw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	buffer = parse_events__scan_string(str);
 
-	ret = parse_numeric_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	ret = parse_events_parse(&list, &idx);
 
-	ret = parse_symbolic_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	parse_events__flush_buffer(buffer);
+	parse_events__delete_buffer(buffer);
 
-	ret = parse_generic_hw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	if (!ret) {
+		int entries = idx - evlist->nr_entries;
+		perf_evlist__splice_list_tail(evlist, &list, entries);
+		return 0;
+	}
 
-	ret = parse_breakpoint_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	list_for_each_entry_safe(evsel, h, &list, node)
+		perf_evsel__delete(evsel);
 
-	fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
+	fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
 	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
-	return EVT_FAILED;
-
-modifier:
-	if (parse_event_modifier(str, attr) < 0) {
-		fprintf(stderr, "invalid event modifier: '%s'\n", *str);
-		fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
-
-		return EVT_FAILED;
-	}
-
 	return ret;
 }
 
-int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
-{
-	struct perf_event_attr attr;
-	enum event_result ret;
-	const char *ostr;
-
-	for (;;) {
-		ostr = str;
-		memset(&attr, 0, sizeof(attr));
-		event_attr_init(&attr);
-		ret = parse_event_symbols(evlist, &str, &attr);
-		if (ret == EVT_FAILED)
-			return -1;
-
-		if (!(*str == 0 || *str == ',' || isspace(*str)))
-			return -1;
-
-		if (ret != EVT_HANDLED_ALL) {
-			struct perf_evsel *evsel;
-			evsel = perf_evsel__new(&attr, evlist->nr_entries);
-			if (evsel == NULL)
-				return -1;
-			perf_evlist__add(evlist, evsel);
-
-			evsel->name = calloc(str - ostr + 1, 1);
-			if (!evsel->name)
-				return -1;
-			strncpy(evsel->name, ostr, str - ostr);
-		}
-
-		if (*str == 0)
-			break;
-		if (*str == ',')
-			++str;
-		while (isspace(*str))
-			++str;
-	}
-
-	return 0;
-}
-
 int parse_events_option(const struct option *opt, const char *str,
 			int unset __used)
 {
@@ -1052,8 +864,6 @@ int print_hwcache_events(const char *event_glob)
 	return printed;
 }
 
-#define MAX_NAME_LEN 100
-
 /*
  * Print the help text for the event symbols:
  */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7e0cbe7..84d3771 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,21 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
 
+int parse_events_modifier(struct list_head *list __used, char *str __used);
+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,
+			     unsigned long type, unsigned long config);
+int parse_events_add_cache(struct list_head *list, int *idx,
+			   char *type, char *op_result1, char *op_result2);
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
+				void *ptr, char *type);
+void parse_events_error(struct list_head *list, int *idx,
+			char const *msg);
+
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
 void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
new file mode 100644
index 0000000..aeedebb
--- /dev/null
+++ b/tools/perf/util/parse-events.l
@@ -0,0 +1,107 @@
+
+%option prefix="parse_events_"
+
+%{
+#include <errno.h>
+#include "../perf.h"
+#include "parse-events-bison.h"
+
+static int __value(char *str, int base, int token)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(str, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.num = num;
+	return token;
+}
+
+static int value(int base)
+{
+	return __value(parse_events_text, base, PE_VALUE);
+}
+
+static int raw(int base)
+{
+	return __value(parse_events_text + 1, base, PE_RAW);
+}
+
+static int str(int token)
+{
+	parse_events_lval.str = strdup(parse_events_text);
+	return token;
+}
+
+static int sym(int type, int config)
+{
+	parse_events_lval.num = (type << 16) + config;
+	return PE_VALUE_SYM;
+}
+
+%}
+
+num_dec		[0-9]+
+num_hex		0x[a-fA-F0-9]+
+name		[a-zA-Z_*?][a-zA-Z0-9_*?]*
+modifier_event	[ukhp]{1,5}
+modifier_bp	[rwx]
+
+%%
+cpu-cycles|cycles				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches			{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+cpu-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations			{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+
+L1-dcache|l1-d|l1d|L1-data		|
+L1-icache|l1-i|l1i|L1-instruction	|
+LLC|L2					|
+dTLB|d-tlb|Data-TLB			|
+iTLB|i-tlb|Instruction-TLB		|
+branch|branches|bpu|btb|bpc		|
+node					{ return str(PE_NAME_CACHE_TYPE); }
+
+load|loads|read				|
+store|stores|write			|
+prefetch|prefetches			|
+speculative-read|speculative-load	|
+refs|Reference|ops|access		|
+misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
+
+mem:			{ return PE_PREFIX_MEM; }
+r{num_dec}		{ return raw(10); }
+r{num_hex}		{ return raw(16); }
+{num_dec}		{ return value(10); }
+{num_hex}		{ return value(16); }
+
+{modifier_event}	{ return str(PE_MODIFIER_EVENT); }
+{modifier_bp}		{ return str(PE_MODIFIER_BP); }
+{name}			{ return str(PE_NAME); }
+"/"			{ return '/'; }
+-			{ return '-'; }
+,			{ return ','; }
+:			{ return ':'; }
+=			{ return '='; }
+
+%%
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
new file mode 100644
index 0000000..4b4459e
--- /dev/null
+++ b/tools/perf/util/parse-events.y
@@ -0,0 +1,127 @@
+
+%name-prefix "parse_events_"
+%parse-param {struct list_head *list}
+%parse-param {int *idx}
+
+%{
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+%}
+
+%token PE_VALUE PE_VALUE_SYM PE_RAW
+%token PE_NAME
+%token PE_MODIFIER_EVENT PE_MODIFIER_BP
+%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
+%token PE_PREFIX_MEM PE_PREFIX_RAW
+%token PE_ERROR
+%type <num> PE_VALUE
+%type <num> PE_VALUE_SYM
+%type <num> PE_RAW
+%type <str> PE_NAME
+%type <str> PE_NAME_CACHE_TYPE
+%type <str> PE_NAME_CACHE_OP_RESULT
+%type <str> PE_MODIFIER_EVENT
+%type <str> PE_MODIFIER_BP
+
+%union
+{
+	char *str;
+	unsigned long num;
+}
+%%
+
+events:
+events ',' event | event
+
+event:
+event_def PE_MODIFIER_EVENT
+{
+	ABORT_ON(parse_events_modifier(list, $2));
+}
+|
+event_def
+
+event_def: event_legacy_symbol sep_dc |
+	   event_legacy_cache sep_dc |
+	   event_legacy_mem |
+	   event_legacy_tracepoint sep_dc |
+	   event_legacy_numeric sep_dc |
+	   event_legacy_raw sep_dc
+
+event_legacy_symbol:
+PE_VALUE_SYM
+{
+	int type = $1 >> 16;
+	int config = $1 & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+}
+
+event_legacy_cache:
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
+{
+	ABORT_ON(parse_events_add_cache(list, idx, $1, $3, $5));
+}
+|
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
+{
+	ABORT_ON(parse_events_add_cache(list, idx, $1, $3, NULL));
+}
+|
+PE_NAME_CACHE_TYPE
+{
+	ABORT_ON(parse_events_add_cache(list, idx, $1, NULL, NULL));
+}
+
+event_legacy_mem:
+PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
+{
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) $2, $4));
+}
+|
+PE_PREFIX_MEM PE_VALUE sep_dc
+{
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) $2, NULL));
+}
+
+event_legacy_tracepoint:
+PE_NAME ':' PE_NAME
+{
+	ABORT_ON(parse_events_add_tracepoint(list, idx, $1, $3));
+}
+
+event_legacy_numeric:
+PE_VALUE ':' PE_VALUE
+{
+	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3));
+}
+
+event_legacy_raw:
+PE_RAW
+{
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1));
+}
+
+sep_dc: ':' |
+
+%%
+
+void parse_events_error(struct list_head *list __used, int *idx __used,
+			char const *msg __used)
+{
+}
-- 
1.7.6.5


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

* [PATCH 7/9] perf, tool: Add config options support for event parsing
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (5 preceding siblings ...)
  2012-01-16 12:31                       ` [PATCH 6/9] perf, tool: Add parser generator for events parsing Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition Jiri Olsa
                                         ` (4 subsequent siblings)
  11 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding a new rule to the event grammar to be able to specify
values of additional attributes of symbolic event.

The new syntax for event symbolic definition is:

event_legacy_symbol:  PE_NAME_SYM '/' event_config '/' |
                      PE_NAME_SYM sep_slash_dc

event_config:         event_config ',' event_term | event_term

event_term:           PE_NAME '=' PE_NAME |
                      PE_NAME '=' PE_VALUE

sep_slash_dc:         '/' | ':' |

At the moment the code is recognizing only 'period' config
option, which modifies value sample_period event attribute.

Use is now allowed to specify events like:
  cycles/period=100000/

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c            |   18 +++
 tools/perf/util/parse-events-bison.c |  245 +++++++++++++++++++++++-----------
 tools/perf/util/parse-events-bison.h |    6 +-
 tools/perf/util/parse-events.c       |   75 ++++++++++-
 tools/perf/util/parse-events.h       |   22 +++-
 tools/perf/util/parse-events.y       |   66 +++++++++-
 6 files changed, 340 insertions(+), 92 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 1fbba0a..081cad7 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -677,6 +677,20 @@ static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
 	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);
+	return 0;
+}
+
 static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -884,6 +898,10 @@ static struct test__event_st {
 		.check = test__checkevent_symbolic_name,
 	},
 	{
+		.name  = "cycles/period=100000/",
+		.check = test__checkevent_symbolic_name_config,
+	},
+	{
 		.name  = "faults",
 		.check = test__checkevent_symbolic_alias,
 	},
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
index 20fca26..32adc40 100644
--- a/tools/perf/util/parse-events-bison.c
+++ b/tools/perf/util/parse-events-bison.c
@@ -145,15 +145,17 @@ typedef union YYSTYPE
 {
 
 /* Line 214 of yacc.c  */
-#line 42 "util/parse-events.y"
+#line 44 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
+	struct list_head *head;
+	struct parse_events__term *term;
 
 
 
 /* Line 214 of yacc.c  */
-#line 157 "util/parse-events-bison.c"
+#line 159 "util/parse-events-bison.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -165,7 +167,7 @@ typedef union YYSTYPE
 
 
 /* Line 264 of yacc.c  */
-#line 169 "util/parse-events-bison.c"
+#line 171 "util/parse-events-bison.c"
 
 #ifdef short
 # undef short
@@ -378,18 +380,18 @@ union yyalloc
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  20
+#define YYFINAL  23
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   27
+#define YYLAST   35
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  17
+#define YYNTOKENS  19
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  11
+#define YYNNTS  14
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  22
+#define YYNRULES  30
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  39
+#define YYNSTATES  50
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -405,9 +407,9 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    14,    15,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    16,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    14,    16,     2,    15,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    17,     2,
+       2,    18,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -435,29 +437,34 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint8 yyprhs[] =
 {
-       0,     0,     3,     7,     9,    12,    14,    17,    20,    22,
-      25,    28,    31,    33,    39,    43,    45,    51,    55,    59,
-      63,    65,    67
+       0,     0,     3,     7,     9,    12,    14,    16,    19,    21,
+      24,    27,    30,    35,    38,    44,    48,    50,    56,    60,
+      64,    68,    70,    74,    76,    80,    84,    86,    87,    89,
+      91
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      18,     0,    -1,    18,    14,    19,    -1,    19,    -1,    20,
-       7,    -1,    20,    -1,    21,    27,    -1,    22,    27,    -1,
-      23,    -1,    24,    27,    -1,    25,    27,    -1,    26,    27,
-      -1,     4,    -1,     9,    15,    10,    15,    10,    -1,     9,
-      15,    10,    -1,     9,    -1,    11,     3,    16,     8,    27,
-      -1,    11,     3,    27,    -1,     6,    16,     6,    -1,     3,
-      16,     3,    -1,     5,    -1,    16,    -1,    -1
+      20,     0,    -1,    20,    14,    21,    -1,    21,    -1,    22,
+       7,    -1,    22,    -1,    23,    -1,    24,    31,    -1,    25,
+      -1,    26,    31,    -1,    27,    31,    -1,    28,    31,    -1,
+       4,    15,    29,    15,    -1,     4,    32,    -1,     9,    16,
+      10,    16,    10,    -1,     9,    16,    10,    -1,     9,    -1,
+      11,     3,    17,     8,    31,    -1,    11,     3,    31,    -1,
+       6,    17,     6,    -1,     3,    17,     3,    -1,     5,    -1,
+      29,    14,    30,    -1,    30,    -1,     6,    18,     6,    -1,
+       6,    18,     3,    -1,    17,    -1,    -1,    15,    -1,    17,
+      -1,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    49,    49,    49,    52,    57,    59,    60,    61,    62,
-      63,    64,    67,    76,    81,    86,    92,    97,   103,   109,
-     115,   120,   120
+       0,    53,    53,    53,    56,    61,    63,    64,    65,    66,
+      67,    68,    71,    80,    89,    94,    99,   105,   110,   116,
+     122,   128,   134,   144,   156,   165,   174,   174,   176,   176,
+     176
 };
 #endif
 
@@ -469,10 +476,11 @@ static const char *const yytname[] =
   "$end", "error", "$undefined", "PE_VALUE", "PE_VALUE_SYM", "PE_RAW",
   "PE_NAME", "PE_MODIFIER_EVENT", "PE_MODIFIER_BP", "PE_NAME_CACHE_TYPE",
   "PE_NAME_CACHE_OP_RESULT", "PE_PREFIX_MEM", "PE_PREFIX_RAW", "PE_ERROR",
-  "','", "'-'", "':'", "$accept", "events", "event", "event_def",
-  "event_legacy_symbol", "event_legacy_cache", "event_legacy_mem",
-  "event_legacy_tracepoint", "event_legacy_numeric", "event_legacy_raw",
-  "sep_dc", 0
+  "','", "'/'", "'-'", "':'", "'='", "$accept", "events", "event",
+  "event_def", "event_legacy_symbol", "event_legacy_cache",
+  "event_legacy_mem", "event_legacy_tracepoint", "event_legacy_numeric",
+  "event_legacy_raw", "event_config", "event_term", "sep_dc",
+  "sep_slash_dc", 0
 };
 #endif
 
@@ -482,24 +490,26 @@ static const char *const yytname[] =
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,    44,    45,    58
+     265,   266,   267,   268,    44,    47,    45,    58,    61
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    17,    18,    18,    19,    19,    20,    20,    20,    20,
-      20,    20,    21,    22,    22,    22,    23,    23,    24,    25,
-      26,    27,    27
+       0,    19,    20,    20,    21,    21,    22,    22,    22,    22,
+      22,    22,    23,    23,    24,    24,    24,    25,    25,    26,
+      27,    28,    29,    29,    30,    30,    31,    31,    32,    32,
+      32
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     3,     1,     2,     1,     2,     2,     1,     2,
-       2,     2,     1,     5,     3,     1,     5,     3,     3,     3,
-       1,     1,     0
+       0,     2,     3,     1,     2,     1,     1,     2,     1,     2,
+       2,     2,     4,     2,     5,     3,     1,     5,     3,     3,
+       3,     1,     3,     1,     3,     3,     1,     0,     1,     1,
+       0
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -507,35 +517,37 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,    12,    20,     0,    15,     0,     0,     3,     5,
-      22,    22,     8,    22,    22,    22,     0,     0,     0,    22,
-       1,     0,     4,    21,     6,     7,     9,    10,    11,    19,
-      18,    14,    21,    17,     2,     0,    22,    13,    16
+       0,     0,    30,    21,     0,    16,     0,     0,     3,     5,
+       6,    27,     8,    27,    27,    27,     0,    28,    29,    13,
+       0,     0,    27,     1,     0,     4,    26,     7,     9,    10,
+      11,    20,     0,     0,    23,    19,    15,    26,    18,     2,
+       0,     0,    12,     0,    27,    25,    24,    22,    14,    17
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
       -1,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      24
+      33,    34,    27,    19
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -12
+#define YYPACT_NINF -14
 static const yytype_int8 yypact[] =
 {
-       7,   -10,   -12,   -12,    -9,    -6,     2,     1,   -12,    10,
-      -2,    -2,   -12,    -2,    -2,    -2,    16,    14,    11,     6,
-     -12,     7,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
-     -12,     8,    18,   -12,   -12,    17,    -2,   -12,   -12
+       1,    -3,    -2,   -14,    -1,     6,    17,     3,   -14,    14,
+     -14,     7,   -14,     7,     7,     7,    20,    19,   -14,   -14,
+      21,    16,    11,   -14,     1,   -14,   -14,   -14,   -14,   -14,
+     -14,   -14,    12,     4,   -14,   -14,    13,    24,   -14,   -14,
+       5,    19,   -14,    23,     7,   -14,   -14,   -14,   -14,   -14
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -12,   -12,     3,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
-     -11
+     -14,   -14,    10,   -14,   -14,   -14,   -14,   -14,   -14,   -14,
+     -14,    -6,   -13,   -14
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -545,26 +557,29 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      25,    20,    26,    27,    28,    19,    16,    17,    33,    18,
-       1,     2,     3,     4,    23,    21,     5,    22,     6,    29,
-      30,    31,    32,    35,    34,    38,    36,    37
+      28,    29,    30,    23,     1,     2,     3,     4,    45,    38,
+       5,    46,     6,    17,    16,    18,    20,    24,    41,    42,
+      22,    25,    21,    31,    26,    32,    36,    35,    37,    43,
+      40,    49,    44,    48,    39,    47
 };
 
 static const yytype_uint8 yycheck[] =
 {
-      11,     0,    13,    14,    15,     3,    16,    16,    19,    15,
-       3,     4,     5,     6,    16,    14,     9,     7,    11,     3,
-       6,    10,    16,    15,    21,    36,     8,    10
+      13,    14,    15,     0,     3,     4,     5,     6,     3,    22,
+       9,     6,    11,    15,    17,    17,    17,    14,    14,    15,
+       3,     7,    16,     3,    17,     6,    10,     6,    17,    16,
+      18,    44,     8,    10,    24,    41
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,     4,     5,     6,     9,    11,    18,    19,    20,
-      21,    22,    23,    24,    25,    26,    16,    16,    15,     3,
-       0,    14,     7,    16,    27,    27,    27,    27,    27,     3,
-       6,    10,    16,    27,    19,    15,     8,    10,    27
+       0,     3,     4,     5,     6,     9,    11,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    17,    15,    17,    32,
+      17,    16,     3,     0,    14,     7,    17,    31,    31,    31,
+      31,     3,     6,    29,    30,     6,    10,    17,    31,    21,
+      18,    14,    15,    16,     8,     3,     6,    30,    10,    31
 };
 
 #define yyerrok		(yyerrstatus = 0)
@@ -1400,7 +1415,7 @@ yyreduce:
         case 4:
 
 /* Line 1464 of yacc.c  */
-#line 53 "util/parse-events.y"
+#line 57 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_modifier(list, (yyvsp[(2) - (2)].str)));
 ;}
@@ -1409,91 +1424,159 @@ yyreduce:
   case 12:
 
 /* Line 1464 of yacc.c  */
-#line 68 "util/parse-events.y"
+#line 72 "util/parse-events.y"
     {
-	int type = (yyvsp[(1) - (1)].num) >> 16;
-	int config = (yyvsp[(1) - (1)].num) & 255;
+	int type = (yyvsp[(1) - (4)].num) >> 16;
+	int config = (yyvsp[(1) - (4)].num) & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, (yyvsp[(3) - (4)].head)));
+	parse_events__free_terms((yyvsp[(3) - (4)].head));
 ;}
     break;
 
   case 13:
 
 /* Line 1464 of yacc.c  */
-#line 77 "util/parse-events.y"
+#line 81 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
+	int type = (yyvsp[(1) - (2)].num) >> 16;
+	int config = (yyvsp[(1) - (2)].num) & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, NULL));
 ;}
     break;
 
   case 14:
 
 /* Line 1464 of yacc.c  */
-#line 82 "util/parse-events.y"
+#line 90 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
 ;}
     break;
 
   case 15:
 
 /* Line 1464 of yacc.c  */
-#line 87 "util/parse-events.y"
+#line 95 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
 ;}
     break;
 
   case 16:
 
 /* Line 1464 of yacc.c  */
-#line 93 "util/parse-events.y"
+#line 100 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
 ;}
     break;
 
   case 17:
 
 /* Line 1464 of yacc.c  */
-#line 98 "util/parse-events.y"
+#line 106 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
 ;}
     break;
 
   case 18:
 
 /* Line 1464 of yacc.c  */
-#line 104 "util/parse-events.y"
+#line 111 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
 ;}
     break;
 
   case 19:
 
 /* Line 1464 of yacc.c  */
-#line 110 "util/parse-events.y"
+#line 117 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num)));
+	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
 ;}
     break;
 
   case 20:
 
 /* Line 1464 of yacc.c  */
-#line 116 "util/parse-events.y"
+#line 123 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
+;}
+    break;
+
+  case 21:
+
+/* Line 1464 of yacc.c  */
+#line 129 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
+;}
+    break;
+
+  case 22:
+
+/* Line 1464 of yacc.c  */
+#line 135 "util/parse-events.y"
+    {
+	struct list_head *head = (yyvsp[(1) - (3)].head);
+	struct parse_events__term *term = (yyvsp[(3) - (3)].term);
+
+	ABORT_ON(!head);
+	list_add_tail(&term->list, head);
+	(yyval.head) = (yyvsp[(1) - (3)].head);
+;}
+    break;
+
+  case 23:
+
+/* Line 1464 of yacc.c  */
+#line 145 "util/parse-events.y"
+    {
+	struct list_head *head = malloc(sizeof(*head));
+	struct parse_events__term *term = (yyvsp[(1) - (1)].term);
+
+	ABORT_ON(!head);
+	INIT_LIST_HEAD(head);
+	list_add_tail(&term->list, head);
+	(yyval.head) = head;
+;}
+    break;
+
+  case 24:
+
+/* Line 1464 of yacc.c  */
+#line 157 "util/parse-events.y"
+    {
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
+		 (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), 0));
+	(yyval.term) = term;
+;}
+    break;
+
+  case 25:
+
+/* Line 1464 of yacc.c  */
+#line 166 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num)));
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
+		 (yyvsp[(1) - (3)].str), NULL, (yyvsp[(3) - (3)].num)));
+	(yyval.term) = term;
 ;}
     break;
 
 
 
 /* Line 1464 of yacc.c  */
-#line 1497 "util/parse-events-bison.c"
+#line 1580 "util/parse-events-bison.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1705,7 +1788,7 @@ yyreturn:
 
 
 /* Line 1684 of yacc.c  */
-#line 122 "util/parse-events.y"
+#line 178 "util/parse-events.y"
 
 
 void parse_events_error(struct list_head *list __used, int *idx __used,
diff --git a/tools/perf/util/parse-events-bison.h b/tools/perf/util/parse-events-bison.h
index 097a632..b73c4bd 100644
--- a/tools/perf/util/parse-events-bison.h
+++ b/tools/perf/util/parse-events-bison.h
@@ -59,15 +59,17 @@ typedef union YYSTYPE
 {
 
 /* Line 1685 of yacc.c  */
-#line 42 "util/parse-events.y"
+#line 44 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
+	struct list_head *head;
+	struct parse_events__term *term;
 
 
 
 /* Line 1685 of yacc.c  */
-#line 71 "util/parse-events-bison.h"
+#line 73 "util/parse-events-bison.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6e50b91..7423049 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -588,15 +588,46 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
 	return add_event(list, idx, &attr, name);
 }
 
-int
-parse_events_add_numeric(struct list_head *list, int *idx,
-			 unsigned long type, unsigned long config)
+static int config_term(struct perf_event_attr *attr,
+		       struct parse_events__term *term)
+{
+	/* Only period supported so far. */
+	if (strcmp(term->config, "period"))
+		return -EINVAL;
+
+	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+		return -EINVAL;
+
+	attr->sample_period = term->val.num;
+	return 0;
+}
+
+static int config_attr(struct perf_event_attr *attr,
+		       struct list_head *head)
+{
+	struct parse_events__term *term;
+
+	list_for_each_entry(term, head, list)
+		if (config_term(attr, term))
+			return -EINVAL;
+
+	return 0;
+}
+
+int parse_events_add_numeric(struct list_head *list, int *idx,
+			     unsigned long type, unsigned long config,
+			     struct list_head *head_config)
 {
 	struct perf_event_attr attr;
 
 	memset(&attr, 0, sizeof(attr));
 	attr.type = type;
 	attr.config = config;
+
+	if (head_config &&
+	    config_attr(&attr, head_config))
+		return -EINVAL;
+
 	return add_event(list, idx, &attr,
 			 (char *) __event_name(type, config));
 }
@@ -923,3 +954,41 @@ void print_events(const char *event_glob)
 
 	print_tracepoint_events(NULL, NULL);
 }
+
+int parse_events__new_term(struct parse_events__term **_term, int type,
+			   char *config, char *str, long num)
+{
+	struct parse_events__term *term;
+
+	term = zalloc(sizeof(*term));
+	if (!term)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&term->list);
+	term->type = type;
+	term->config = config;
+
+	switch (type) {
+	case PARSE_EVENTS__TERM_TYPE_NUM:
+		term->val.num = num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_STR:
+		term->val.str = str;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_term = term;
+	return 0;
+}
+
+void parse_events__free_terms(struct list_head *terms)
+{
+	struct parse_events__term *term, *h;
+
+	list_for_each_entry_safe(term, h, terms, list)
+		free(term);
+
+	free(terms);
+}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 84d3771..2737f1e 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,25 @@ 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,
+};
+
+struct parse_events__term {
+	char *config;
+	union {
+		char *str;
+		long  num;
+	} val;
+	int type;
+
+	struct list_head list;
+};
+
+int parse_events__new_term(struct parse_events__term **term, int type,
+			   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,
 				char *sys, char *event);
@@ -40,7 +59,8 @@ 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,
-			     unsigned long type, unsigned long config);
+			     unsigned long type, unsigned long config,
+			     struct list_head *head_config);
 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,
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 4b4459e..0be12dc 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -37,11 +37,15 @@ do { \
 %type <str> PE_NAME_CACHE_OP_RESULT
 %type <str> PE_MODIFIER_EVENT
 %type <str> PE_MODIFIER_BP
+%type <head> event_config
+%type <term> event_term
 
 %union
 {
 	char *str;
 	unsigned long num;
+	struct list_head *head;
+	struct parse_events__term *term;
 }
 %%
 
@@ -56,7 +60,7 @@ event_def PE_MODIFIER_EVENT
 |
 event_def
 
-event_def: event_legacy_symbol sep_dc |
+event_def: event_legacy_symbol |
 	   event_legacy_cache sep_dc |
 	   event_legacy_mem |
 	   event_legacy_tracepoint sep_dc |
@@ -64,12 +68,21 @@ event_def: event_legacy_symbol sep_dc |
 	   event_legacy_raw sep_dc
 
 event_legacy_symbol:
-PE_VALUE_SYM
+PE_VALUE_SYM '/' event_config '/'
 {
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, $3));
+	parse_events__free_terms($3);
+}
+|
+PE_VALUE_SYM sep_slash_dc
+{
+	int type = $1 >> 16;
+	int config = $1 & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, NULL));
 }
 
 event_legacy_cache:
@@ -108,17 +121,60 @@ PE_NAME ':' PE_NAME
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3));
+	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3, NULL));
 }
 
 event_legacy_raw:
 PE_RAW
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1));
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1, NULL));
+}
+
+event_config:
+event_config ',' event_term
+{
+	struct list_head *head = $1;
+	struct parse_events__term *term = $3;
+
+	ABORT_ON(!head);
+	list_add_tail(&term->list, head);
+	$$ = $1;
+}
+|
+event_term
+{
+	struct list_head *head = malloc(sizeof(*head));
+	struct parse_events__term *term = $1;
+
+	ABORT_ON(!head);
+	INIT_LIST_HEAD(head);
+	list_add_tail(&term->list, head);
+	$$ = head;
+}
+
+event_term:
+PE_NAME '=' PE_NAME
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
+		 $1, $3, 0));
+	$$ = term;
+}
+|
+PE_NAME '=' PE_VALUE
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
+		 $1, NULL, $3));
+	$$ = term;
 }
 
 sep_dc: ':' |
 
+sep_slash_dc: '/' | ':' |
+
 %%
 
 void parse_events_error(struct list_head *list __used, int *idx __used,
-- 
1.7.6.5


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

* [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (6 preceding siblings ...)
  2012-01-16 12:31                       ` [PATCH 7/9] perf, tool: Add config options support for event parsing Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-16 12:31                       ` [PATCH 9/9] perf, tool: Add support to specify pmu style event Jiri Olsa
                                         ` (3 subsequent siblings)
  11 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding pmu object which provides interface to pmu's sysfs
event format definition located at:
  ${sysfs_mount}/bus/event_source/devices/${pmu}/format

Following interface is exported:
  struct perf_pmu* perf_pmu__find(char *name);
  - this function returns pmu object, which is then
    passed as a handle to other interface functions

  int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                       struct list_head *head_terms);
  - this function configures perf_event_attr struct based
    on pmu's format definitions and config terms data,
    containined in head_terms list.

Parser generator is used to retrive the pmu's format definition.
The generated parser is part of the patch. Added makefile rule
'pmu-parser' to generate the parser code out of the bison/flex
sources.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile         |   12 +
 tools/perf/builtin-test.c   |   10 +
 tools/perf/util/pmu-bison.c | 1623 ++++++++++++++++++++++++++++++++++++++
 tools/perf/util/pmu-bison.h |   72 ++
 tools/perf/util/pmu-flex.c  | 1821 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/pmu-flex.h  |  316 ++++++++
 tools/perf/util/pmu.c       |  409 ++++++++++
 tools/perf/util/pmu.h       |   42 +
 tools/perf/util/pmu.l       |   50 ++
 tools/perf/util/pmu.y       |   76 ++
 10 files changed, 4431 insertions(+), 0 deletions(-)
 create mode 100644 tools/perf/util/pmu-bison.c
 create mode 100644 tools/perf/util/pmu-bison.h
 create mode 100644 tools/perf/util/pmu-flex.c
 create mode 100644 tools/perf/util/pmu-flex.h
 create mode 100644 tools/perf/util/pmu.c
 create mode 100644 tools/perf/util/pmu.h
 create mode 100644 tools/perf/util/pmu.l
 create mode 100644 tools/perf/util/pmu.y

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7143dc3..27b836b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -262,6 +262,7 @@ LIB_H += util/build-id.h
 LIB_H += util/debug.h
 LIB_H += util/debugfs.h
 LIB_H += util/sysfs.h
+LIB_H += util/pmu.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
 LIB_H += util/evlist.h
@@ -309,6 +310,7 @@ LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
 LIB_OBJS += $(OUTPUT)util/sysfs.o
+LIB_OBJS += $(OUTPUT)util/pmu.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
 LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -347,6 +349,8 @@ LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
 LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
 LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
+LIB_OBJS += $(OUTPUT)util/pmu-flex.o
+LIB_OBJS += $(OUTPUT)util/pmu-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -754,6 +758,9 @@ $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/parse-events-flex.o: util/parse-events-flex.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
 
+$(OUTPUT)util/pmu-flex.o: util/pmu-flex.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
@@ -791,6 +798,7 @@ help:
 	@echo '  info		- make GNU info documentation (access with info <foo>)'
 	@echo '  pdf		- make pdf documentation'
 	@echo '  event-parser	- make event parser code'
+	@echo '  pmu-parser	- make pmu format parser code'
 	@echo '  TAGS		- use etags to make tag information for source browsing'
 	@echo '  tags		- use ctags to make tag information for source browsing'
 	@echo '  cscope	- use cscope to make interactive browsing database'
@@ -845,6 +853,10 @@ event-parser:
 	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o util/parse-events-bison.c
 	$(QUIET_FLEX)$(FLEX) --header-file=util/parse-events-flex.h -t util/parse-events.l > util/parse-events-flex.c
 
+pmu-parser:
+	$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o util/pmu-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=util/pmu-flex.h -t util/pmu.l > util/pmu-flex.c
+
 ### Detect prefix changes
 TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
              $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 081cad7..c5d7494 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -13,6 +13,7 @@
 #include "util/parse-events.h"
 #include "util/symbol.h"
 #include "util/thread_map.h"
+#include "util/pmu.h"
 #include "../../include/linux/hw_breakpoint.h"
 
 #include <sys/mman.h>
@@ -1483,6 +1484,11 @@ static int test__rdpmc(void)
 
 #endif
 
+static int test__perf_pmu(void)
+{
+	return perf_pmu__test();
+}
+
 static struct test {
 	const char *desc;
 	int (*func)(void);
@@ -1518,6 +1524,10 @@ static struct test {
 		.func = test__PERF_RECORD,
 	},
 	{
+		.desc = "Test perf pmu format parsing",
+		.func = test__perf_pmu,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/util/pmu-bison.c b/tools/perf/util/pmu-bison.c
new file mode 100644
index 0000000..e212adb
--- /dev/null
+++ b/tools/perf/util/pmu-bison.c
@@ -0,0 +1,1623 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.4.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse         perf_pmu_parse
+#define yylex           perf_pmu_lex
+#define yyerror         perf_pmu_error
+#define yylval          perf_pmu_lval
+#define yychar          perf_pmu_char
+#define yydebug         perf_pmu_debug
+#define yynerrs         perf_pmu_nerrs
+
+
+/* Copy the first part of user declarations.  */
+
+/* Line 189 of yacc.c  */
+#line 5 "util/pmu.y"
+
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/bitmap.h>
+#include <string.h>
+#include "pmu.h"
+
+extern int perf_pmu_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+        if (val) \
+                YYABORT; \
+} while (0)
+
+
+
+/* Line 189 of yacc.c  */
+#line 99 "util/pmu-bison.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PP_NAME = 258,
+     PP_VALUE = 259,
+     PP_ERROR = 260
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c  */
+#line 30 "util/pmu.y"
+
+	char *str;
+	unsigned long num;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+
+
+
+/* Line 214 of yacc.c  */
+#line 148 "util/pmu-bison.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 264 of yacc.c  */
+#line 160 "util/pmu-bison.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  5
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   10
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  9
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  5
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  8
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  15
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   260
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     7,     8,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     6,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     6,     8,    13,    17,    19,    23
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      10,     0,    -1,    10,    11,    -1,    11,    -1,     3,     3,
+       6,    12,    -1,    12,     7,    13,    -1,    13,    -1,     4,
+       8,     4,    -1,     4,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,    39,    39,    41,    44,    50,    55,    61,    66
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "PP_NAME", "PP_VALUE", "PP_ERROR", "':'",
+  "','", "'-'", "$accept", "format", "format_term", "bits", "bit_term", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,    58,    44,    45
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,     9,    10,    10,    11,    12,    12,    13,    13
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     2,     1,     4,     3,     1,     3,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,     0,     0,     3,     0,     1,     2,     0,     8,     4,
+       6,     0,     0,     7,     5
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     2,     3,     9,    10
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -8
+static const yytype_int8 yypact[] =
+{
+      -2,    -1,     0,    -8,     1,    -8,    -8,     2,    -4,     3,
+      -8,     4,     2,    -8,    -8
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+      -8,    -8,     7,    -8,    -7
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+       5,     1,     4,     1,    11,    14,     8,     7,    13,     6,
+      12
+};
+
+static const yytype_uint8 yycheck[] =
+{
+       0,     3,     3,     3,     8,    12,     4,     6,     4,     2,
+       7
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,    10,    11,     3,     0,    11,     6,     4,    12,
+      13,     8,     7,     4,    13
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  However,
+   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
+   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+   discussed.  */
+
+#define YYFAIL		goto yyerrlab
+#if defined YYFAIL
+  /* This is here to suppress warnings from the GCC cpp's
+     -Wunused-macros.  Normally we don't worry about that warning, but
+     some users do, and we want to make it easy for users to remove
+     YYFAIL uses, which will produce warnings from Bison 2.5.  */
+#endif
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (format, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, format); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *format)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, format)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *format;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (format);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *format)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, format)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *format;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, format);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, struct list_head *format)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, format)
+    YYSTYPE *yyvsp;
+    int yyrule;
+    struct list_head *format;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       , format);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule, format); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct list_head *format)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, format)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    struct list_head *format;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (format);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (struct list_head *format);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (struct list_head *format)
+#else
+int
+yyparse (format)
+    struct list_head *format;
+#endif
+#endif
+{
+
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+
+/* Line 1464 of yacc.c  */
+#line 45 "util/pmu.y"
+    {
+	ABORT_ON(perf_pmu__new_format(format, (yyvsp[(1) - (4)].str), (yyvsp[(2) - (4)].str), (yyvsp[(4) - (4)].bits)));
+;}
+    break;
+
+  case 5:
+
+/* Line 1464 of yacc.c  */
+#line 51 "util/pmu.y"
+    {
+	bitmap_or((yyval.bits), (yyvsp[(1) - (3)].bits), (yyvsp[(3) - (3)].bits), 64);
+;}
+    break;
+
+  case 6:
+
+/* Line 1464 of yacc.c  */
+#line 56 "util/pmu.y"
+    {
+	memcpy((yyval.bits), (yyvsp[(1) - (1)].bits), sizeof((yyvsp[(1) - (1)].bits)));
+;}
+    break;
+
+  case 7:
+
+/* Line 1464 of yacc.c  */
+#line 62 "util/pmu.y"
+    {
+	perf_pmut_set_format((yyval.bits), (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num));
+;}
+    break;
+
+  case 8:
+
+/* Line 1464 of yacc.c  */
+#line 67 "util/pmu.y"
+    {
+	perf_pmut_set_format((yyval.bits), (yyvsp[(1) - (1)].num), 0);
+;}
+    break;
+
+
+
+/* Line 1464 of yacc.c  */
+#line 1405 "util/pmu-bison.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (format, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (format, yymsg);
+	  }
+	else
+	  {
+	    yyerror (format, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, format);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, format);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (format, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, format);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, format);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+/* Line 1684 of yacc.c  */
+#line 71 "util/pmu.y"
+
+
+void perf_pmu_error(struct list_head *list __used,
+		    char const *msg __used)
+{
+}
+
diff --git a/tools/perf/util/pmu-bison.h b/tools/perf/util/pmu-bison.h
new file mode 100644
index 0000000..24c8404
--- /dev/null
+++ b/tools/perf/util/pmu-bison.h
@@ -0,0 +1,72 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PP_NAME = 258,
+     PP_VALUE = 259,
+     PP_ERROR = 260
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1685 of yacc.c  */
+#line 30 "util/pmu.y"
+
+	char *str;
+	unsigned long num;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+
+
+
+/* Line 1685 of yacc.c  */
+#line 64 "util/pmu-bison.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE perf_pmu_lval;
+
+
diff --git a/tools/perf/util/pmu-flex.c b/tools/perf/util/pmu-flex.c
new file mode 100644
index 0000000..8512660
--- /dev/null
+++ b/tools/perf/util/pmu-flex.c
@@ -0,0 +1,1821 @@
+
+#line 3 "<stdout>"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer perf_pmu__create_buffer
+#define yy_delete_buffer perf_pmu__delete_buffer
+#define yy_flex_debug perf_pmu__flex_debug
+#define yy_init_buffer perf_pmu__init_buffer
+#define yy_flush_buffer perf_pmu__flush_buffer
+#define yy_load_buffer_state perf_pmu__load_buffer_state
+#define yy_switch_to_buffer perf_pmu__switch_to_buffer
+#define yyin perf_pmu_in
+#define yyleng perf_pmu_leng
+#define yylex perf_pmu_lex
+#define yylineno perf_pmu_lineno
+#define yyout perf_pmu_out
+#define yyrestart perf_pmu_restart
+#define yytext perf_pmu_text
+#define yywrap perf_pmu_wrap
+#define yyalloc perf_pmu_alloc
+#define yyrealloc perf_pmu_realloc
+#define yyfree perf_pmu_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE perf_pmu_restart(perf_pmu_in  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int perf_pmu_leng;
+
+extern FILE *perf_pmu_in, *perf_pmu_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up perf_pmu_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up perf_pmu_text again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via perf_pmu_restart()), so that the user can continue scanning by
+	 * just pointing perf_pmu_in at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when perf_pmu_text is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int perf_pmu_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow perf_pmu_wrap()'s to do buffer switches
+ * instead of setting up a fresh perf_pmu_in.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void perf_pmu_restart (FILE *input_file  );
+void perf_pmu__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE perf_pmu__create_buffer (FILE *file,int size  );
+void perf_pmu__delete_buffer (YY_BUFFER_STATE b  );
+void perf_pmu__flush_buffer (YY_BUFFER_STATE b  );
+void perf_pmu_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void perf_pmu_pop_buffer_state (void );
+
+static void perf_pmu_ensure_buffer_stack (void );
+static void perf_pmu__load_buffer_state (void );
+static void perf_pmu__init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER perf_pmu__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE perf_pmu__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE perf_pmu__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE perf_pmu__scan_bytes (yyconst char *bytes,int len  );
+
+void *perf_pmu_alloc (yy_size_t  );
+void *perf_pmu_realloc (void *,yy_size_t  );
+void perf_pmu_free (void *  );
+
+#define yy_new_buffer perf_pmu__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        perf_pmu_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        perf_pmu_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *perf_pmu_in = (FILE *) 0, *perf_pmu_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int perf_pmu_lineno;
+
+int perf_pmu_lineno = 1;
+
+extern char *perf_pmu_text;
+#define yytext_ptr perf_pmu_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up perf_pmu_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	perf_pmu_leng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 9
+#define YY_END_OF_BUFFER 10
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[17] =
+    {   0,
+        0,    0,   10,    7,    8,    6,    4,    1,    1,    5,
+        3,    1,    0,    3,    2,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    2,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    3,    4,    1,    1,    5,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    7,    1,    1,
+        1,    1,    1,    1,    8,    8,    8,    8,    8,    8,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        1,    1,    1,    1,    9,    1,    8,    8,    8,    8,
+
+        8,    8,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,   10,
+        9,    9,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[11] =
+    {   0,
+        1,    1,    1,    1,    2,    2,    1,    3,    4,    5
+    } ;
+
+static yyconst flex_int16_t yy_base[20] =
+    {   0,
+        0,    0,   21,   22,   22,   22,   22,    3,    2,   22,
+        0,    0,    0,    0,    0,   22,    9,   13,   17
+    } ;
+
+static yyconst flex_int16_t yy_def[20] =
+    {   0,
+       16,    1,   16,   16,   16,   16,   16,   17,   17,   16,
+       18,    9,   19,   18,   19,    0,   16,   16,   16
+    } ;
+
+static yyconst flex_int16_t yy_nxt[33] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   11,   11,   11,
+       12,   16,   13,   12,   14,   14,   14,   14,   15,   15,
+       16,    3,   16,   16,   16,   16,   16,   16,   16,   16,
+       16,   16
+    } ;
+
+static yyconst flex_int16_t yy_chk[33] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+       17,    9,    8,   17,   18,   18,   18,   18,   19,   19,
+        3,   16,   16,   16,   16,   16,   16,   16,   16,   16,
+       16,   16
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int perf_pmu__flex_debug;
+int perf_pmu__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *perf_pmu_text;
+#line 1 "util/pmu.l"
+#line 4 "util/pmu.l"
+#include <stdlib.h>
+#include <linux/bitops.h>
+#include "pmu.h"
+#include "pmu-bison.h"
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(perf_pmu_text, NULL, base);
+	if (errno)
+		return PP_ERROR;
+
+	perf_pmu_lval.num = num;
+	return PP_VALUE;
+}
+
+static int str(void)
+{
+	perf_pmu_lval.str = strdup(perf_pmu_text);
+	return PP_NAME;
+}
+
+#line 502 "<stdout>"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int perf_pmu_lex_destroy (void );
+
+int perf_pmu_get_debug (void );
+
+void perf_pmu_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE perf_pmu_get_extra (void );
+
+void perf_pmu_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *perf_pmu_get_in (void );
+
+void perf_pmu_set_in  (FILE * in_str  );
+
+FILE *perf_pmu_get_out (void );
+
+void perf_pmu_set_out  (FILE * out_str  );
+
+int perf_pmu_get_leng (void );
+
+char *perf_pmu_get_text (void );
+
+int perf_pmu_get_lineno (void );
+
+void perf_pmu_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int perf_pmu_wrap (void );
+#else
+extern int perf_pmu_wrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( perf_pmu_text, perf_pmu_leng, 1, perf_pmu_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		unsigned n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( perf_pmu_in )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( perf_pmu_in ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, perf_pmu_in))==0 && ferror(perf_pmu_in)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(perf_pmu_in); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int perf_pmu_lex (void);
+
+#define YY_DECL int perf_pmu_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after perf_pmu_text and perf_pmu_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 34 "util/pmu.l"
+
+
+#line 687 "<stdout>"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! perf_pmu_in )
+			perf_pmu_in = stdin;
+
+		if ( ! perf_pmu_out )
+			perf_pmu_out = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			perf_pmu_ensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE );
+		}
+
+		perf_pmu__load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of perf_pmu_text. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 17 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 22 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 36 "util/pmu.l"
+{ return value(10); }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 37 "util/pmu.l"
+{ return value(16); }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 38 "util/pmu.l"
+{ return str(); }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 39 "util/pmu.l"
+{ return '-'; }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 40 "util/pmu.l"
+{ return ':'; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 41 "util/pmu.l"
+{ return ','; }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 42 "util/pmu.l"
+{ ; }
+	YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+#line 43 "util/pmu.l"
+{ ; }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 45 "util/pmu.l"
+ECHO;
+	YY_BREAK
+#line 816 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed perf_pmu_in at a new source and called
+			 * perf_pmu_lex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = perf_pmu_in;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( perf_pmu_wrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * perf_pmu_text, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of perf_pmu_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					perf_pmu_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			perf_pmu_restart(perf_pmu_in  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) perf_pmu_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 17 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    	register char *yy_cp = (yy_c_buf_p);
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 17 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 16);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up perf_pmu_text */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					perf_pmu_restart(perf_pmu_in );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( perf_pmu_wrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve perf_pmu_text */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void perf_pmu_restart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        perf_pmu_ensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE );
+	}
+
+	perf_pmu__init_buffer(YY_CURRENT_BUFFER,input_file );
+	perf_pmu__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void perf_pmu__switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		perf_pmu_pop_buffer_state();
+	 *		perf_pmu_push_buffer_state(new_buffer);
+     */
+	perf_pmu_ensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	perf_pmu__load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (perf_pmu_wrap()) processing, but the only time this flag
+	 * is looked at is after perf_pmu_wrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void perf_pmu__load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	perf_pmu_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE perf_pmu__create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) perf_pmu_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) perf_pmu_alloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	perf_pmu__init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with perf_pmu__create_buffer()
+ * 
+ */
+    void perf_pmu__delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		perf_pmu_free((void *) b->yy_ch_buf  );
+
+	perf_pmu_free((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a perf_pmu_restart() or at EOF.
+ */
+    static void perf_pmu__init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	perf_pmu__flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then perf_pmu__init_buffer was _probably_
+     * called from perf_pmu_restart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void perf_pmu__flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		perf_pmu__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void perf_pmu_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	perf_pmu_ensure_buffer_stack();
+
+	/* This block is copied from perf_pmu__switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from perf_pmu__switch_to_buffer. */
+	perf_pmu__load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void perf_pmu_pop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	perf_pmu__delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		perf_pmu__load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void perf_pmu_ensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)perf_pmu_alloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in perf_pmu_ensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)perf_pmu_realloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in perf_pmu_ensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE perf_pmu__scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) perf_pmu_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	perf_pmu__switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to perf_pmu_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       perf_pmu__scan_bytes() instead.
+ */
+YY_BUFFER_STATE perf_pmu__scan_string (yyconst char * yystr )
+{
+    
+	return perf_pmu__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to perf_pmu_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE perf_pmu__scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) perf_pmu_alloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = perf_pmu__scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in perf_pmu__scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up perf_pmu_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		perf_pmu_text[perf_pmu_leng] = (yy_hold_char); \
+		(yy_c_buf_p) = perf_pmu_text + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		perf_pmu_leng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int perf_pmu_get_lineno  (void)
+{
+        
+    return perf_pmu_lineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *perf_pmu_get_in  (void)
+{
+        return perf_pmu_in;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *perf_pmu_get_out  (void)
+{
+        return perf_pmu_out;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int perf_pmu_get_leng  (void)
+{
+        return perf_pmu_leng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *perf_pmu_get_text  (void)
+{
+        return perf_pmu_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void perf_pmu_set_lineno (int  line_number )
+{
+    
+    perf_pmu_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see perf_pmu__switch_to_buffer
+ */
+void perf_pmu_set_in (FILE *  in_str )
+{
+        perf_pmu_in = in_str ;
+}
+
+void perf_pmu_set_out (FILE *  out_str )
+{
+        perf_pmu_out = out_str ;
+}
+
+int perf_pmu_get_debug  (void)
+{
+        return perf_pmu__flex_debug;
+}
+
+void perf_pmu_set_debug (int  bdebug )
+{
+        perf_pmu__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from perf_pmu_lex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    perf_pmu_in = stdin;
+    perf_pmu_out = stdout;
+#else
+    perf_pmu_in = (FILE *) 0;
+    perf_pmu_out = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * perf_pmu_lex_init()
+     */
+    return 0;
+}
+
+/* perf_pmu_lex_destroy is for both reentrant and non-reentrant scanners. */
+int perf_pmu_lex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		perf_pmu__delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		perf_pmu_pop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	perf_pmu_free((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * perf_pmu_lex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *perf_pmu_alloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *perf_pmu_realloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void perf_pmu_free (void * ptr )
+{
+	free( (char *) ptr );	/* see perf_pmu_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 45 "util/pmu.l"
+
+
+
+int perf_pmu_wrap(void)
+{
+	return 1;
+}
+
diff --git a/tools/perf/util/pmu-flex.h b/tools/perf/util/pmu-flex.h
new file mode 100644
index 0000000..f65080c
--- /dev/null
+++ b/tools/perf/util/pmu-flex.h
@@ -0,0 +1,316 @@
+#ifndef perf_pmu_HEADER_H
+#define perf_pmu_HEADER_H 1
+#define perf_pmu_IN_HEADER 1
+
+#line 6 "util/pmu-flex.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int perf_pmu_leng;
+
+extern FILE *perf_pmu_in, *perf_pmu_out;
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void perf_pmu_restart (FILE *input_file  );
+void perf_pmu__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE perf_pmu__create_buffer (FILE *file,int size  );
+void perf_pmu__delete_buffer (YY_BUFFER_STATE b  );
+void perf_pmu__flush_buffer (YY_BUFFER_STATE b  );
+void perf_pmu_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void perf_pmu_pop_buffer_state (void );
+
+YY_BUFFER_STATE perf_pmu__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE perf_pmu__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE perf_pmu__scan_bytes (yyconst char *bytes,int len  );
+
+void *perf_pmu_alloc (yy_size_t  );
+void *perf_pmu_realloc (void *,yy_size_t  );
+void perf_pmu_free (void *  );
+
+/* Begin user sect3 */
+
+extern int perf_pmu_lineno;
+
+extern char *perf_pmu_text;
+#define yytext_ptr perf_pmu_text
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int perf_pmu_lex_destroy (void );
+
+int perf_pmu_get_debug (void );
+
+void perf_pmu_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE perf_pmu_get_extra (void );
+
+void perf_pmu_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *perf_pmu_get_in (void );
+
+void perf_pmu_set_in  (FILE * in_str  );
+
+FILE *perf_pmu_get_out (void );
+
+void perf_pmu_set_out  (FILE * out_str  );
+
+int perf_pmu_get_leng (void );
+
+char *perf_pmu_get_text (void );
+
+int perf_pmu_get_lineno (void );
+
+void perf_pmu_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int perf_pmu_wrap (void );
+#else
+extern int perf_pmu_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int perf_pmu_lex (void);
+
+#define YY_DECL int perf_pmu_lex (void)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 45 "util/pmu.l"
+
+
+#line 315 "util/pmu-flex.h"
+#undef perf_pmu_IN_HEADER
+#endif /* perf_pmu_HEADER_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
new file mode 100644
index 0000000..db46eb7
--- /dev/null
+++ b/tools/perf/util/pmu.c
@@ -0,0 +1,409 @@
+
+#include <linux/list.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "sysfs.h"
+#include "util.h"
+#include "pmu.h"
+#include "parse-events.h"
+
+int perf_pmu_parse(struct list_head *list);
+extern FILE *perf_pmu_in;
+
+static LIST_HEAD(pmus);
+
+static int pmu_format_parse(char *format, struct list_head *head)
+{
+	FILE *file;
+	int ret;
+
+	file = fopen(format, "r");
+	if (!file)
+		return -EINVAL;
+
+	perf_pmu_in = file;
+	ret = perf_pmu_parse(head);
+	fclose(file);
+	return ret;
+}
+
+static int pmu_format(char *name, struct list_head *format)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return -1;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/format", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	if (pmu_format_parse(path, format))
+		return -1;
+
+	return 0;
+}
+
+static int pmu_type(char *name, __u32 *type)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+	FILE *file;
+	int ret = 0;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return -1;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/type", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	file = fopen(path, "r");
+	if (!file)
+		return -EINVAL;
+
+	if (1 != fscanf(file, "%u", type))
+		ret = -1;
+
+	fclose(file);
+	return ret;
+}
+
+static struct perf_pmu* pmu_lookup(char *name)
+{
+	struct perf_pmu *pmu;
+	LIST_HEAD(format);
+	__u32 type;
+
+	if (pmu_format(name, &format))
+		return NULL;
+
+	if (pmu_type(name, &type))
+		return NULL;
+
+	pmu = zalloc(sizeof(*pmu));
+	if (!pmu)
+		return NULL;
+
+	INIT_LIST_HEAD(&pmu->format);
+	list_splice(&format, &pmu->format);
+	pmu->name = strdup(name);
+	pmu->type = type;
+	return pmu;
+}
+
+static struct perf_pmu* pmu_find(char *name)
+{
+	struct perf_pmu *pmu;
+
+	list_for_each_entry(pmu, &pmus, list)
+		if (!strcmp(pmu->name, name))
+			return pmu;
+
+	return NULL;
+}
+
+struct perf_pmu* perf_pmu__find(char *name)
+{
+	struct perf_pmu *pmu;
+
+	pmu = pmu_find(name);
+	if (pmu)
+		return pmu;
+
+	return pmu_lookup(name);
+}
+
+static struct perf_pmu__format*
+pmu_find_format(struct list_head *formats, char *name)
+{
+	struct perf_pmu__format *format;
+
+	list_for_each_entry(format, formats, list)
+		if (!strcmp(format->name, name))
+			return format;
+
+	return NULL;
+}
+
+/* TODO maybe optimize a little ;) */
+static __u64 pmu_format_value(unsigned long *format, __u64 value)
+{
+	unsigned long fbit, vbit;
+	__u64 v = 0;
+
+	for(fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
+
+		if (!test_bit(fbit, format))
+			continue;
+
+		if (!(value & (1 << vbit++)))
+			continue;
+
+		v |= (1llu << fbit);
+	}
+
+	return v;
+}
+
+static int pmu_config_term(struct list_head *formats, struct perf_event_attr *attr,
+			   struct parse_events__term *term)
+{
+	struct perf_pmu__format *format;
+	__u64 *vp;
+
+	/* Support only for numnerial terms. */
+	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+		return -EINVAL;
+
+	format = pmu_find_format(formats, term->config);
+	if (!format)
+		return -EINVAL;
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		vp = &attr->config;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		vp = &attr->config1;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		vp = &attr->config2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*vp |= pmu_format_value(format->bits, term->val.num);
+	return 0;
+}
+
+static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
+		      struct list_head *head_terms)
+{
+	struct parse_events__term *term, *h;
+
+	list_for_each_entry_safe(term, h, head_terms, list)
+		if (pmu_config_term(formats, attr, term))
+			return -EINVAL;
+
+	return 0;
+}
+
+int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
+		     struct list_head *head_terms)
+{
+	attr->type = pmu->type;
+	return pmu_config(&pmu->format, attr, head_terms);
+}
+
+static int format_value(char *value)
+{
+	int i;
+	static struct {
+		const char *name;
+		int value;
+	} vals[3] = {
+		{ "config",  PERF_PMU_FORMAT_VALUE_CONFIG  },
+		{ "config1", PERF_PMU_FORMAT_VALUE_CONFIG1 },
+		{ "config2", PERF_PMU_FORMAT_VALUE_CONFIG2 },
+	};
+
+	for (i = 0; i < 3; i++) {
+		if (!strcmp(vals[i].name, value))
+			return vals[i].value;
+	}
+
+	return -1;
+}
+
+int perf_pmu__new_format(struct list_head *list, char *name,
+			 char *value, unsigned long *bits)
+{
+	struct perf_pmu__format *format;
+	int val = format_value(value);
+
+	if (val == -1)
+		return -EINVAL;
+
+	format = zalloc(sizeof(*format));
+	if (!format)
+		return -ENOMEM;
+
+	format->name = strdup(name);
+	format->value = val;
+	memcpy(format->bits, bits, sizeof(format->bits));
+
+	list_add_tail(&format->list, list);
+	return 0;
+}
+
+void perf_pmu__delete_format(struct perf_pmu__format *format)
+{
+	free(format->name);
+	free(format);
+}
+
+void perf_pmut_set_format(unsigned long *bits, long from, long to)
+{
+	long b;
+
+	if (!to)
+		to = from;
+
+	memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
+	for(b = from; b <= to; b++)
+		set_bit(b, bits);
+}
+
+static const char *test_formats[] = {
+	"krava01	config:0-1,62-63\n",
+	"krava02	config:10-17\n",
+	"krava03	config:5\n",
+	"krava11	config1:0,2,4,6,8,20-28\n",
+	"krava12	config1:63\n",
+	"krava13	config1:45-47\n",
+	"krava21	config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n",
+	"krava22	config2:8,18,48,58\n",
+	"krava23	config2:28-29,38\n",
+	NULL,
+};
+
+static struct parse_events__term test_terms[] = {
+	{
+		.config  = (char*) "krava01",
+		.val.num = 15,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava02",
+		.val.num = 170,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava03",
+		.val.num = 1,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava11",
+		.val.num = 27,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava12",
+		.val.num = 1,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava13",
+		.val.num = 2,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava21",
+		.val.num = 119,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava22",
+		.val.num = 11,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char*) "krava23",
+		.val.num = 2,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+};
+#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
+
+static char *test_format_file(void)
+{
+	static char name[PATH_MAX];
+	const char **format = test_formats;
+	int fd;
+	FILE *file;
+
+	snprintf(name, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
+	fd = mkstemp(name);
+	if (fd < 0)
+		return NULL;
+
+	file = fdopen(fd, "w");
+	if (!file)
+		return NULL;
+
+	while (*format) {
+		if (1 != fwrite(*format, strlen(*format), 1, file))
+			break;
+
+		format++;
+	}
+
+	fclose(file);
+	return name;
+}
+
+static struct list_head* test_terms_list(void)
+{
+	static LIST_HEAD(terms);
+	unsigned int i;
+
+	for (i = 0; i < TERMS_CNT; i++)
+		list_add_tail(&test_terms[i].list, &terms);
+
+	return &terms;
+}
+
+#undef TERMS_CNT
+
+int perf_pmu__test(void)
+{
+	char *format = test_format_file();
+	LIST_HEAD(formats);
+	struct list_head *terms = test_terms_list();
+	int ret;
+
+	if (!format)
+		return -EINVAL;
+
+	do {
+		struct perf_event_attr attr;
+
+		memset(&attr, 0, sizeof(attr));
+
+		ret = pmu_format_parse(format, &formats);
+		if (ret)
+			break;
+
+		ret = pmu_config(&formats, &attr, terms);
+		if (ret)
+			break;
+
+		ret = -EINVAL;
+
+		if (attr.config  != 0xc00000000002a823)
+			break;
+		if (attr.config1 != 0x8000400000000145)
+			break;
+		if (attr.config2 != 0x0400000020041d07)
+			break;
+
+		ret = 0;
+	} while (0);
+
+	unlink(format);
+	return ret;
+}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
new file mode 100644
index 0000000..5f52a10
--- /dev/null
+++ b/tools/perf/util/pmu.h
@@ -0,0 +1,42 @@
+#ifndef __PMU_H
+#define __PMU_H
+
+#include <linux/bitops.h>
+#include <linux/perf_event.h>
+
+enum {
+	PERF_PMU_FORMAT_VALUE_CONFIG,
+	PERF_PMU_FORMAT_VALUE_CONFIG1,
+	PERF_PMU_FORMAT_VALUE_CONFIG2,
+};
+
+#define PERF_PMU_FORMAT_BITS 64
+
+struct perf_pmu__format {
+	char *name;
+	int value;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+	struct list_head list;
+};
+
+struct perf_pmu {
+	char *name;
+	__u32 type;
+	struct list_head format;
+	struct list_head list;
+};
+
+struct perf_pmu* perf_pmu__find(char *name);
+int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
+		     struct list_head *head_terms);
+
+int perf_pmu_wrap(void);
+void perf_pmu_error(struct list_head *list, char const *msg);
+
+int perf_pmu__new_format(struct list_head *format, char *name,
+			 char *value, unsigned long *bits);
+void perf_pmu__delete_format(struct perf_pmu__format *format);
+void perf_pmut_set_format(unsigned long *bits, long from, long to);
+
+int perf_pmu__test(void);
+#endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.l b/tools/perf/util/pmu.l
new file mode 100644
index 0000000..c0383f4
--- /dev/null
+++ b/tools/perf/util/pmu.l
@@ -0,0 +1,50 @@
+%option prefix="perf_pmu_"
+
+%{
+#include <stdlib.h>
+#include <linux/bitops.h>
+#include "pmu.h"
+#include "pmu-bison.h"
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(perf_pmu_text, NULL, base);
+	if (errno)
+		return PP_ERROR;
+
+	perf_pmu_lval.num = num;
+	return PP_VALUE;
+}
+
+static int str(void)
+{
+	perf_pmu_lval.str = strdup(perf_pmu_text);
+	return PP_NAME;
+}
+
+%}
+
+num_dec         [0-9]+
+num_hex         0x[a-fA-F0-9]+
+name            [a-zA-Z_][a-zA-Z0-9_]*
+
+%%
+
+{num_dec}	{ return value(10); }
+{num_hex}	{ return value(16); }
+{name}		{ return str(); }
+-		{ return '-'; }
+:		{ return ':'; }
+,		{ return ','; }
+.		{ ; }
+\n		{ ; }
+
+%%
+
+int perf_pmu_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
new file mode 100644
index 0000000..a5e87b8
--- /dev/null
+++ b/tools/perf/util/pmu.y
@@ -0,0 +1,76 @@
+
+%name-prefix "perf_pmu_"
+%parse-param {struct list_head *format}
+
+%{
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/bitmap.h>
+#include <string.h>
+#include "pmu.h"
+
+extern int perf_pmu_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+        if (val) \
+                YYABORT; \
+} while (0)
+
+%}
+
+%token PP_NAME PP_VALUE PP_ERROR
+%type <num> PP_VALUE
+%type <str> PP_NAME
+%type <bits> bit_term
+%type <bits> bits
+
+%union
+{
+	char *str;
+	unsigned long num;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+}
+
+%%
+
+format:
+format format_term
+|
+format_term
+
+format_term:
+PP_NAME PP_NAME ':' bits
+{
+	ABORT_ON(perf_pmu__new_format(format, $1, $2, $4));
+}
+
+bits:
+bits ',' bit_term
+{
+	bitmap_or($$, $1, $3, 64);
+}
+|
+bit_term
+{
+	memcpy($$, $1, sizeof($1));
+}
+
+bit_term:
+PP_VALUE '-' PP_VALUE
+{
+	perf_pmut_set_format($$, $1, $3);
+}
+|
+PP_VALUE
+{
+	perf_pmut_set_format($$, $1, 0);
+}
+
+%%
+
+void perf_pmu_error(struct list_head *list __used,
+		    char const *msg __used)
+{
+}
-- 
1.7.6.5


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

* [PATCH 9/9] perf, tool: Add support to specify pmu style event
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (7 preceding siblings ...)
  2012-01-16 12:31                       ` [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition Jiri Olsa
@ 2012-01-16 12:31                       ` Jiri Olsa
  2012-01-24 15:22                       ` [RFCv3 0/9] perf tool: parser generator for events parsing Peter Zijlstra
                                         ` (2 subsequent siblings)
  11 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-16 12:31 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Added new event rule to the event definition grammar:

event_def: event_pmu |
	   ...
event_pmu: PE_NAME '/' event_config '/'

Using this rule, event could be now specified like:
  cpu/config=1,config1=2,config2=3/u

where pmu name 'cpu' is looked up via following path:
  ${sysfs_mount}/bus/event_source/devices/${pmu}

and config options are bound to the pmu's format definiton:
  ${sysfs_mount}/bus/event_source/devices/${pmu}/format

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c            |   18 ++++
 tools/perf/util/parse-events-bison.c |  187 ++++++++++++++++++----------------
 tools/perf/util/parse-events.c       |   19 ++++
 tools/perf/util/parse-events.h       |    2 +
 tools/perf/util/parse-events.y       |   10 ++-
 5 files changed, 149 insertions(+), 87 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index c5d7494..f41569c 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -873,6 +873,20 @@ static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
 	return test__checkevent_genhw(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", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config", 3 == evsel->attr.config2);
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -954,6 +968,10 @@ static struct test__event_st {
 		.name  = "L1-dcache-load-miss:kp",
 		.check = test__checkevent_genhw_modifier,
 	},
+	{
+		.name  = "cpu/config=1,config1=2,config2=3/u",
+		.check = test__checkevent_pmu,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
index 32adc40..d3f4e62 100644
--- a/tools/perf/util/parse-events-bison.c
+++ b/tools/perf/util/parse-events-bison.c
@@ -380,18 +380,18 @@ union yyalloc
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  23
+#define YYFINAL  25
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   35
+#define YYLAST   43
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  19
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  14
+#define YYNNTS  15
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  30
+#define YYNRULES  32
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  50
+#define YYNSTATES  54
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -437,34 +437,34 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint8 yyprhs[] =
 {
-       0,     0,     3,     7,     9,    12,    14,    16,    19,    21,
-      24,    27,    30,    35,    38,    44,    48,    50,    56,    60,
-      64,    68,    70,    74,    76,    80,    84,    86,    87,    89,
-      91
+       0,     0,     3,     7,     9,    12,    14,    16,    18,    21,
+      23,    26,    29,    32,    37,    42,    45,    51,    55,    57,
+      63,    67,    71,    75,    77,    81,    83,    87,    91,    93,
+      94,    96,    98
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
       20,     0,    -1,    20,    14,    21,    -1,    21,    -1,    22,
-       7,    -1,    22,    -1,    23,    -1,    24,    31,    -1,    25,
-      -1,    26,    31,    -1,    27,    31,    -1,    28,    31,    -1,
-       4,    15,    29,    15,    -1,     4,    32,    -1,     9,    16,
-      10,    16,    10,    -1,     9,    16,    10,    -1,     9,    -1,
-      11,     3,    17,     8,    31,    -1,    11,     3,    31,    -1,
-       6,    17,     6,    -1,     3,    17,     3,    -1,     5,    -1,
-      29,    14,    30,    -1,    30,    -1,     6,    18,     6,    -1,
-       6,    18,     3,    -1,    17,    -1,    -1,    15,    -1,    17,
-      -1,    -1
+       7,    -1,    22,    -1,    23,    -1,    24,    -1,    25,    32,
+      -1,    26,    -1,    27,    32,    -1,    28,    32,    -1,    29,
+      32,    -1,     6,    15,    30,    15,    -1,     4,    15,    30,
+      15,    -1,     4,    33,    -1,     9,    16,    10,    16,    10,
+      -1,     9,    16,    10,    -1,     9,    -1,    11,     3,    17,
+       8,    32,    -1,    11,     3,    32,    -1,     6,    17,     6,
+      -1,     3,    17,     3,    -1,     5,    -1,    30,    14,    31,
+      -1,    31,    -1,     6,    18,     6,    -1,     6,    18,     3,
+      -1,    17,    -1,    -1,    15,    -1,    17,    -1,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
        0,    53,    53,    53,    56,    61,    63,    64,    65,    66,
-      67,    68,    71,    80,    89,    94,    99,   105,   110,   116,
-     122,   128,   134,   144,   156,   165,   174,   174,   176,   176,
-     176
+      67,    68,    69,    72,    79,    88,    97,   102,   107,   113,
+     118,   124,   130,   136,   142,   152,   164,   173,   182,   182,
+     184,   184,   184
 };
 #endif
 
@@ -477,7 +477,7 @@ static const char *const yytname[] =
   "PE_NAME", "PE_MODIFIER_EVENT", "PE_MODIFIER_BP", "PE_NAME_CACHE_TYPE",
   "PE_NAME_CACHE_OP_RESULT", "PE_PREFIX_MEM", "PE_PREFIX_RAW", "PE_ERROR",
   "','", "'/'", "'-'", "':'", "'='", "$accept", "events", "event",
-  "event_def", "event_legacy_symbol", "event_legacy_cache",
+  "event_def", "event_pmu", "event_legacy_symbol", "event_legacy_cache",
   "event_legacy_mem", "event_legacy_tracepoint", "event_legacy_numeric",
   "event_legacy_raw", "event_config", "event_term", "sep_dc",
   "sep_slash_dc", 0
@@ -498,18 +498,18 @@ static const yytype_uint16 yytoknum[] =
 static const yytype_uint8 yyr1[] =
 {
        0,    19,    20,    20,    21,    21,    22,    22,    22,    22,
-      22,    22,    23,    23,    24,    24,    24,    25,    25,    26,
-      27,    28,    29,    29,    30,    30,    31,    31,    32,    32,
-      32
+      22,    22,    22,    23,    24,    24,    25,    25,    25,    26,
+      26,    27,    28,    29,    30,    30,    31,    31,    32,    32,
+      33,    33,    33
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     3,     1,     2,     1,     1,     2,     1,     2,
-       2,     2,     4,     2,     5,     3,     1,     5,     3,     3,
-       3,     1,     3,     1,     3,     3,     1,     0,     1,     1,
-       0
+       0,     2,     3,     1,     2,     1,     1,     1,     2,     1,
+       2,     2,     2,     4,     4,     2,     5,     3,     1,     5,
+       3,     3,     3,     1,     3,     1,     3,     3,     1,     0,
+       1,     1,     0
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -517,37 +517,39 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,    30,    21,     0,    16,     0,     0,     3,     5,
-       6,    27,     8,    27,    27,    27,     0,    28,    29,    13,
-       0,     0,    27,     1,     0,     4,    26,     7,     9,    10,
-      11,    20,     0,     0,    23,    19,    15,    26,    18,     2,
-       0,     0,    12,     0,    27,    25,    24,    22,    14,    17
+       0,     0,    32,    23,     0,    18,     0,     0,     3,     5,
+       6,     7,    29,     9,    29,    29,    29,     0,    30,    31,
+      15,     0,     0,     0,    29,     1,     0,     4,    28,     8,
+      10,    11,    12,    22,     0,     0,    25,     0,    21,    17,
+      28,    20,     2,     0,     0,    14,    13,     0,    29,    27,
+      26,    24,    16,    19
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
       -1,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      33,    34,    27,    19
+      16,    35,    36,    29,    20
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -14
+#define YYPACT_NINF -15
 static const yytype_int8 yypact[] =
 {
-       1,    -3,    -2,   -14,    -1,     6,    17,     3,   -14,    14,
-     -14,     7,   -14,     7,     7,     7,    20,    19,   -14,   -14,
-      21,    16,    11,   -14,     1,   -14,   -14,   -14,   -14,   -14,
-     -14,   -14,    12,     4,   -14,   -14,    13,    24,   -14,   -14,
-       5,    19,   -14,    23,     7,   -14,   -14,   -14,   -14,   -14
+       2,   -13,    -1,   -15,     4,    11,    12,     3,   -15,    13,
+     -15,   -15,     1,   -15,     1,     1,     1,    23,    22,   -15,
+     -15,    22,    24,    19,    14,   -15,     2,   -15,   -15,   -15,
+     -15,   -15,   -15,   -15,    15,     8,   -15,    10,   -15,    16,
+      27,   -15,   -15,     6,    22,   -15,   -15,    26,     1,   -15,
+     -15,   -15,   -15,   -15
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -14,   -14,    10,   -14,   -14,   -14,   -14,   -14,   -14,   -14,
-     -14,    -6,   -13,   -14
+     -15,   -15,    17,   -15,   -15,   -15,   -15,   -15,   -15,   -15,
+     -15,    18,    -7,   -14,   -15
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -557,18 +559,20 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      28,    29,    30,    23,     1,     2,     3,     4,    45,    38,
-       5,    46,     6,    17,    16,    18,    20,    24,    41,    42,
-      22,    25,    21,    31,    26,    32,    36,    35,    37,    43,
-      40,    49,    44,    48,    39,    47
+      30,    31,    32,    25,    17,     1,     2,     3,     4,    49,
+      41,     5,    50,     6,    18,    24,    19,    26,    28,    21,
+      27,    22,    44,    45,    44,    46,    33,    23,    34,    39,
+      38,    40,    47,    43,    53,    48,    52,    51,     0,    37,
+       0,     0,     0,    42
 };
 
-static const yytype_uint8 yycheck[] =
+static const yytype_int8 yycheck[] =
 {
-      13,    14,    15,     0,     3,     4,     5,     6,     3,    22,
-       9,     6,    11,    15,    17,    17,    17,    14,    14,    15,
-       3,     7,    16,     3,    17,     6,    10,     6,    17,    16,
-      18,    44,     8,    10,    24,    41
+      14,    15,    16,     0,    17,     3,     4,     5,     6,     3,
+      24,     9,     6,    11,    15,     3,    17,    14,    17,    15,
+       7,    17,    14,    15,    14,    15,     3,    16,     6,    10,
+       6,    17,    16,    18,    48,     8,    10,    44,    -1,    21,
+      -1,    -1,    -1,    26
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -576,10 +580,11 @@ static const yytype_uint8 yycheck[] =
 static const yytype_uint8 yystos[] =
 {
        0,     3,     4,     5,     6,     9,    11,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    17,    15,    17,    32,
-      17,    16,     3,     0,    14,     7,    17,    31,    31,    31,
-      31,     3,     6,    29,    30,     6,    10,    17,    31,    21,
-      18,    14,    15,    16,     8,     3,     6,    30,    10,    31
+      23,    24,    25,    26,    27,    28,    29,    17,    15,    17,
+      33,    15,    17,    16,     3,     0,    14,     7,    17,    32,
+      32,    32,    32,     3,     6,    30,    31,    30,     6,    10,
+      17,    32,    21,    18,    14,    15,    15,    16,     8,     3,
+       6,    31,    10,    32
 };
 
 #define yyerrok		(yyerrstatus = 0)
@@ -1421,10 +1426,20 @@ yyreduce:
 ;}
     break;
 
-  case 12:
+  case 13:
+
+/* Line 1464 of yacc.c  */
+#line 73 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_pmu(list, idx, (yyvsp[(1) - (4)].str), (yyvsp[(3) - (4)].head)));
+	parse_events__free_terms((yyvsp[(3) - (4)].head));
+;}
+    break;
+
+  case 14:
 
 /* Line 1464 of yacc.c  */
-#line 72 "util/parse-events.y"
+#line 80 "util/parse-events.y"
     {
 	int type = (yyvsp[(1) - (4)].num) >> 16;
 	int config = (yyvsp[(1) - (4)].num) & 255;
@@ -1434,10 +1449,10 @@ yyreduce:
 ;}
     break;
 
-  case 13:
+  case 15:
 
 /* Line 1464 of yacc.c  */
-#line 81 "util/parse-events.y"
+#line 89 "util/parse-events.y"
     {
 	int type = (yyvsp[(1) - (2)].num) >> 16;
 	int config = (yyvsp[(1) - (2)].num) & 255;
@@ -1446,82 +1461,82 @@ yyreduce:
 ;}
     break;
 
-  case 14:
+  case 16:
 
 /* Line 1464 of yacc.c  */
-#line 90 "util/parse-events.y"
+#line 98 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
 ;}
     break;
 
-  case 15:
+  case 17:
 
 /* Line 1464 of yacc.c  */
-#line 95 "util/parse-events.y"
+#line 103 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
 ;}
     break;
 
-  case 16:
+  case 18:
 
 /* Line 1464 of yacc.c  */
-#line 100 "util/parse-events.y"
+#line 108 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
 ;}
     break;
 
-  case 17:
+  case 19:
 
 /* Line 1464 of yacc.c  */
-#line 106 "util/parse-events.y"
+#line 114 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
 ;}
     break;
 
-  case 18:
+  case 20:
 
 /* Line 1464 of yacc.c  */
-#line 111 "util/parse-events.y"
+#line 119 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
 ;}
     break;
 
-  case 19:
+  case 21:
 
 /* Line 1464 of yacc.c  */
-#line 117 "util/parse-events.y"
+#line 125 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
 ;}
     break;
 
-  case 20:
+  case 22:
 
 /* Line 1464 of yacc.c  */
-#line 123 "util/parse-events.y"
+#line 131 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
 ;}
     break;
 
-  case 21:
+  case 23:
 
 /* Line 1464 of yacc.c  */
-#line 129 "util/parse-events.y"
+#line 137 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
 ;}
     break;
 
-  case 22:
+  case 24:
 
 /* Line 1464 of yacc.c  */
-#line 135 "util/parse-events.y"
+#line 143 "util/parse-events.y"
     {
 	struct list_head *head = (yyvsp[(1) - (3)].head);
 	struct parse_events__term *term = (yyvsp[(3) - (3)].term);
@@ -1532,10 +1547,10 @@ yyreduce:
 ;}
     break;
 
-  case 23:
+  case 25:
 
 /* Line 1464 of yacc.c  */
-#line 145 "util/parse-events.y"
+#line 153 "util/parse-events.y"
     {
 	struct list_head *head = malloc(sizeof(*head));
 	struct parse_events__term *term = (yyvsp[(1) - (1)].term);
@@ -1547,10 +1562,10 @@ yyreduce:
 ;}
     break;
 
-  case 24:
+  case 26:
 
 /* Line 1464 of yacc.c  */
-#line 157 "util/parse-events.y"
+#line 165 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
@@ -1560,10 +1575,10 @@ yyreduce:
 ;}
     break;
 
-  case 25:
+  case 27:
 
 /* Line 1464 of yacc.c  */
-#line 166 "util/parse-events.y"
+#line 174 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
@@ -1576,7 +1591,7 @@ yyreduce:
 
 
 /* Line 1464 of yacc.c  */
-#line 1580 "util/parse-events-bison.c"
+#line 1595 "util/parse-events-bison.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1788,7 +1803,7 @@ yyreturn:
 
 
 /* Line 1684 of yacc.c  */
-#line 178 "util/parse-events.y"
+#line 186 "util/parse-events.y"
 
 
 void parse_events_error(struct list_head *list __used, int *idx __used,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 7423049..c791715 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -12,6 +12,7 @@
 #include "header.h"
 #include "debugfs.h"
 #include "parse-events-flex.h"
+#include "pmu.h"
 
 #define MAX_NAME_LEN 100
 
@@ -632,6 +633,24 @@ 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,
+			 char *name, struct list_head *head_config)
+{
+	struct perf_event_attr attr;
+	struct perf_pmu *pmu;
+
+	pmu = perf_pmu__find(name);
+	if (!pmu)
+		return -EINVAL;
+
+	memset(&attr, 0, sizeof(attr));
+
+	if (perf_pmu__config(pmu, &attr, head_config))
+		return -EINVAL;
+
+	return add_event(list, idx, &attr, (char*) "pmu");
+}
+
 int parse_events_modifier(struct list_head *list, char *str)
 {
 	struct perf_evsel *evsel;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2737f1e..0ebc68c 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -65,6 +65,8 @@ int parse_events_add_cache(struct list_head *list, int *idx,
 			   char *type, char *op_result1, char *op_result2);
 int parse_events_add_breakpoint(struct list_head *list, int *idx,
 				void *ptr, char *type);
+int parse_events_add_pmu(struct list_head *list, int *idx,
+			 char *pmu , struct list_head *head_config);
 void parse_events_error(struct list_head *list, int *idx,
 			char const *msg);
 
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 0be12dc..588f115 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -60,13 +60,21 @@ event_def PE_MODIFIER_EVENT
 |
 event_def
 
-event_def: event_legacy_symbol |
+event_def: event_pmu |
+	   event_legacy_symbol |
 	   event_legacy_cache sep_dc |
 	   event_legacy_mem |
 	   event_legacy_tracepoint sep_dc |
 	   event_legacy_numeric sep_dc |
 	   event_legacy_raw sep_dc
 
+event_pmu:
+PE_NAME '/' event_config '/'
+{
+	ABORT_ON(parse_events_add_pmu(list, idx, $1, $3));
+	parse_events__free_terms($3);
+}
+
 event_legacy_symbol:
 PE_VALUE_SYM '/' event_config '/'
 {
-- 
1.7.6.5


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

* Re: [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-16 12:31                       ` [PATCH 5/9] perf: Add sysfs format attribute for pmu device Jiri Olsa
@ 2012-01-23 15:13                         ` Eric W. Biederman
  2012-01-23 15:33                           ` Jiri Olsa
  2012-01-26 16:26                         ` Peter Zijlstra
  1 sibling, 1 reply; 91+ messages in thread
From: Eric W. Biederman @ 2012-01-23 15:13 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, a.p.zijlstra, mingo, paulus, cjashfor, linux-kernel

Jiri Olsa <jolsa@redhat.com> writes:

> Adding 'format' attribute for pmu device that contains
> a syntax description on how to construct raw events.
>
> The event configuration is described in following
> struct pefr_event_attr attributes:
>
>   config
>   config1
>   config2
>
> Each line of the format file describes mapping of name
> and bitfield definition within one of abve attributes.
>
> eg:
>   event   config:0-7
>   umask   config:8-15
>   usr     config:16
>   os      config:17
>   edge    config:18
>   any     config:21
>   inv     config:23
>   cmask   config:24-31
>
> Line syntax:
>   line:      NAME config ':' bits
>   config:    'config' | 'config1' | 'config2"
>   bits:      bits ',' bit_term | bit_term
>   bit_term:  VALUE '-' VALUE | VALUE
>
> Adding event_format callback to the struct pmu, which provides
> the format information. The pmu shall override this function
> and provide its own specific format information.
>
> If not overloaded the default format information is used:
>
>   config  config:0-63
>   config1 config1:0-63
>   config2 config2:0-63
>
> Signed-off-by: Jiri Olsa <jolsa@redhat.com>

> @@ -5492,8 +5492,31 @@ type_show(struct device *dev, struct device_attribute *attr, char *page)
>  	return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type);
>  }
>  
> +static ssize_t perf_default_event_format(struct pmu *pmu, char *page)
> +{
> +	ssize_t ret;
> +
> +	ret  = sprintf(page,       "config  config:0-63\n");
> +	ret += sprintf(page + ret, "config1 config1:0-63\n");
> +	ret += sprintf(page + ret, "config2 config2:0-63\n");

This looks like abuse of sysfs.  The rule is one value per file.
When you start adding newlines I can't see how this format attribute can
be considered one value.

Eric

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

* Re: [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-23 15:13                         ` Eric W. Biederman
@ 2012-01-23 15:33                           ` Jiri Olsa
  2012-01-24 15:22                             ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-23 15:33 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: acme, a.p.zijlstra, mingo, paulus, cjashfor, linux-kernel

On Mon, Jan 23, 2012 at 07:13:24AM -0800, Eric W. Biederman wrote:
> Jiri Olsa <jolsa@redhat.com> writes:
> 
> > Adding 'format' attribute for pmu device that contains
> > a syntax description on how to construct raw events.
> >
> > The event configuration is described in following
> > struct pefr_event_attr attributes:
> >
> >   config
> >   config1
> >   config2
> >
> > Each line of the format file describes mapping of name
> > and bitfield definition within one of abve attributes.
> >
> > eg:
> >   event   config:0-7
> >   umask   config:8-15
> >   usr     config:16
> >   os      config:17
> >   edge    config:18
> >   any     config:21
> >   inv     config:23
> >   cmask   config:24-31
> >
> > Line syntax:
> >   line:      NAME config ':' bits
> >   config:    'config' | 'config1' | 'config2"
> >   bits:      bits ',' bit_term | bit_term
> >   bit_term:  VALUE '-' VALUE | VALUE
> >
> > Adding event_format callback to the struct pmu, which provides
> > the format information. The pmu shall override this function
> > and provide its own specific format information.
> >
> > If not overloaded the default format information is used:
> >
> >   config  config:0-63
> >   config1 config1:0-63
> >   config2 config2:0-63
> >
> > Signed-off-by: Jiri Olsa <jolsa@redhat.com>
> 
> > @@ -5492,8 +5492,31 @@ type_show(struct device *dev, struct device_attribute *attr, char *page)
> >  	return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type);
> >  }
> >  
> > +static ssize_t perf_default_event_format(struct pmu *pmu, char *page)
> > +{
> > +	ssize_t ret;
> > +
> > +	ret  = sprintf(page,       "config  config:0-63\n");
> > +	ret += sprintf(page + ret, "config1 config1:0-63\n");
> > +	ret += sprintf(page + ret, "config2 config2:0-63\n");
> 
> This looks like abuse of sysfs.  The rule is one value per file.
> When you start adding newlines I can't see how this format attribute can
> be considered one value.

ops, missed that rule.. I think we can carry the syntax files
within perf, or have it builtin somehow.. or procfs? :) PeterZ?

thanks,
jirka

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

* Re: [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-23 15:33                           ` Jiri Olsa
@ 2012-01-24 15:22                             ` Peter Zijlstra
  2012-01-24 19:40                               ` Eric W. Biederman
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-24 15:22 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: Eric W. Biederman, acme, mingo, paulus, cjashfor, linux-kernel

On Mon, 2012-01-23 at 16:33 +0100, Jiri Olsa wrote:
>   
> > > +static ssize_t perf_default_event_format(struct pmu *pmu, char *page)
> > > +{
> > > +	ssize_t ret;
> > > +
> > > +	ret  = sprintf(page,       "config  config:0-63\n");
> > > +	ret += sprintf(page + ret, "config1 config1:0-63\n");
> > > +	ret += sprintf(page + ret, "config2 config2:0-63\n");
> > 
> > This looks like abuse of sysfs.  The rule is one value per file.
> > When you start adding newlines I can't see how this format attribute can
> > be considered one value.
> 
> ops, missed that rule.. I think we can carry the syntax files
> within perf, or have it builtin somehow.. or procfs? :) PeterZ?

There's plenty of exceptions to this rule though and touching procfs is
even less appreciated.

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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (8 preceding siblings ...)
  2012-01-16 12:31                       ` [PATCH 9/9] perf, tool: Add support to specify pmu style event Jiri Olsa
@ 2012-01-24 15:22                       ` Peter Zijlstra
  2012-01-24 16:26                       ` Peter Zijlstra
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
  11 siblings, 0 replies; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-24 15:22 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Mon, 2012-01-16 at 13:31 +0100, Jiri Olsa wrote:
> I'd never imagine how much code I need to introduce before
> I could push through the event grouping patch.. 

haha, I think you're going well beyond what's required, but let me have
a peek at all this new stuff ;-)

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

* Re: [PATCH 6/9] perf, tool: Add parser generator for events parsing
  2012-01-16 12:31                       ` [PATCH 6/9] perf, tool: Add parser generator for events parsing Jiri Olsa
@ 2012-01-24 16:02                         ` Peter Zijlstra
  2012-01-25  8:42                           ` Jiri Olsa
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-24 16:02 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Mon, 2012-01-16 at 13:31 +0100, Jiri Olsa wrote:
> +r{num_dec}             { return raw(10); }
> +r{num_hex}             { return raw(16); } 

Not sure that's compatible with the current stuff (not that I greatly
mind though), iirc rXXX is always hex.

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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (9 preceding siblings ...)
  2012-01-24 15:22                       ` [RFCv3 0/9] perf tool: parser generator for events parsing Peter Zijlstra
@ 2012-01-24 16:26                       ` Peter Zijlstra
  2012-01-25  0:53                         ` Greg KH
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
  11 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-24 16:26 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel, Greg KH

On Mon, 2012-01-16 at 13:31 +0100, Jiri Olsa wrote:
> Here's new version of event parsing patchset. To summarize:
>  - adding event parser bison/flex generator
>  - the event syntax stays as it was
>  - adding event format file sysfs attribute
>    for pmu device

Added Greg to CC, please also see: https://lkml.org/lkml/2012/1/16/148

Right, lets hope we can convince the sysfs people that a few lines are
ok.. if not we need to find another way to represent all this muck, one
alternative is exploding the whole thing into a sysfs hierarchy like:


format/event: config:0-7
...

format/config: config:0-63
format/config1: config1:0-63
format/config2: config2:0-63

that will of course consume loads more resources but if that's what it
takes :-(

>  - adding new syntax to specify raw events based
>    on the sysfs pmu's format attribute
>    eg. "cpu/config=1,config1=2,config2=3/u" 

fair enough, so we have the attributes from the $FORMAT thingy and (for
now) one hardcoded 'period' thing.

Should we worry about namespace collisions for the built-in vs format
provided names?

I suppose that once we get all this in (and it looks good from my pov),
we can start thinking about doing things like:

events/cycles: event=0x3c

Which together with:

format/event: config:0-7

would allow us to write something like:

cpu/event=cycles/u



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

* Re: [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-24 15:22                             ` Peter Zijlstra
@ 2012-01-24 19:40                               ` Eric W. Biederman
  2012-01-25  8:54                                 ` Jiri Olsa
  0 siblings, 1 reply; 91+ messages in thread
From: Eric W. Biederman @ 2012-01-24 19:40 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, linux-kernel

Peter Zijlstra <a.p.zijlstra@chello.nl> writes:

> On Mon, 2012-01-23 at 16:33 +0100, Jiri Olsa wrote:
>>   
>> > > +static ssize_t perf_default_event_format(struct pmu *pmu, char *page)
>> > > +{
>> > > +	ssize_t ret;
>> > > +
>> > > +	ret  = sprintf(page,       "config  config:0-63\n");
>> > > +	ret += sprintf(page + ret, "config1 config1:0-63\n");
>> > > +	ret += sprintf(page + ret, "config2 config2:0-63\n");
>> > 
>> > This looks like abuse of sysfs.  The rule is one value per file.
>> > When you start adding newlines I can't see how this format attribute can
>> > be considered one value.
>> 
>> ops, missed that rule.. I think we can carry the syntax files
>> within perf, or have it builtin somehow.. or procfs? :) PeterZ?
>
> There's plenty of exceptions to this rule though and touching procfs is
> even less appreciated.

There may be exceptions but certainly not plenty of exceptions.

There is also a practical scaling problem.  You have to be careful
with how big you make that value before you have problems.

Perhaps what you want is a directory with a bunch of sysfs attributes?

All I know is I see buffer overflows waiting to happen whenever I look
at the code snippet above.

Eric

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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-24 16:26                       ` Peter Zijlstra
@ 2012-01-25  0:53                         ` Greg KH
  2012-01-25 10:49                           ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Greg KH @ 2012-01-25  0:53 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, linux-kernel

On Tue, Jan 24, 2012 at 05:26:04PM +0100, Peter Zijlstra wrote:
> On Mon, 2012-01-16 at 13:31 +0100, Jiri Olsa wrote:
> > Here's new version of event parsing patchset. To summarize:
> >  - adding event parser bison/flex generator
> >  - the event syntax stays as it was
> >  - adding event format file sysfs attribute
> >    for pmu device
> 
> Added Greg to CC, please also see: https://lkml.org/lkml/2012/1/16/148
> 
> Right, lets hope we can convince the sysfs people that a few lines are
> ok.. if not we need to find another way to represent all this muck, one
> alternative is exploding the whole thing into a sysfs hierarchy like:
> 
> 
> format/event: config:0-7
> ...
> 
> format/config: config:0-63
> format/config1: config1:0-63
> format/config2: config2:0-63
> 
> that will of course consume loads more resources but if that's what it
> takes :-(

Well, what's to keep someone from exploding one of those files to go
over the buffer size without knowing it?

Even after reading the above link, I can't really understand what this
is being used for.  As it's sysfs files, why aren't Documentation/ABI/
files also being created with the patch explaining it all?

Again, if at all possible, sysfs should be one value per file.  Please
NEVER create a sysfs file that requires a parser to determine what is
going on in it.  It should be a simple 'read the value' type thing.

So yes, multiple sysfs files do make sense, the resource load should be
almost non-existant for new ones.

thanks,

greg k-h

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

* Re: [PATCH 6/9] perf, tool: Add parser generator for events parsing
  2012-01-24 16:02                         ` Peter Zijlstra
@ 2012-01-25  8:42                           ` Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-25  8:42 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Tue, Jan 24, 2012 at 05:02:05PM +0100, Peter Zijlstra wrote:
> On Mon, 2012-01-16 at 13:31 +0100, Jiri Olsa wrote:
> > +r{num_dec}             { return raw(10); }
> > +r{num_hex}             { return raw(16); } 
> 
> Not sure that's compatible with the current stuff (not that I greatly
> mind though), iirc rXXX is always hex.
right, I'll fix it
thanks

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

* Re: [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-24 19:40                               ` Eric W. Biederman
@ 2012-01-25  8:54                                 ` Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-25  8:54 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Peter Zijlstra, acme, mingo, paulus, cjashfor, linux-kernel

On Tue, Jan 24, 2012 at 11:40:28AM -0800, Eric W. Biederman wrote:
> Peter Zijlstra <a.p.zijlstra@chello.nl> writes:
> 
> > On Mon, 2012-01-23 at 16:33 +0100, Jiri Olsa wrote:
> >>   
> >> > > +static ssize_t perf_default_event_format(struct pmu *pmu, char *page)
> >> > > +{
> >> > > +	ssize_t ret;
> >> > > +
> >> > > +	ret  = sprintf(page,       "config  config:0-63\n");
> >> > > +	ret += sprintf(page + ret, "config1 config1:0-63\n");
> >> > > +	ret += sprintf(page + ret, "config2 config2:0-63\n");
> >> > 
> >> > This looks like abuse of sysfs.  The rule is one value per file.
> >> > When you start adding newlines I can't see how this format attribute can
> >> > be considered one value.
> >> 
> >> ops, missed that rule.. I think we can carry the syntax files
> >> within perf, or have it builtin somehow.. or procfs? :) PeterZ?
> >
> > There's plenty of exceptions to this rule though and touching procfs is
> > even less appreciated.
> 
> There may be exceptions but certainly not plenty of exceptions.
> 
> There is also a practical scaling problem.  You have to be careful
> with how big you make that value before you have problems.
> 
> Perhaps what you want is a directory with a bunch of sysfs attributes?
> 
yep, Peter outlined this possibility in here
https://lkml.org/lkml/2012/1/24/206

> All I know is I see buffer overflows waiting to happen whenever I look
> at the code snippet above.

from this point of view, the above data should always be static/hardcoded
for given pmu.. so we will be fine with the page size buffer,
it could be valifated with some sort of BUILD_BUG_ON(data_size < pagesize)

jirka

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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-25  0:53                         ` Greg KH
@ 2012-01-25 10:49                           ` Peter Zijlstra
  2012-01-25 14:37                             ` Jiri Olsa
  2012-01-25 17:01                             ` Greg KH
  0 siblings, 2 replies; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-25 10:49 UTC (permalink / raw)
  To: Greg KH; +Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, linux-kernel

On Tue, 2012-01-24 at 16:53 -0800, Greg KH wrote:

> Well, what's to keep someone from exploding one of those files to go
> over the buffer size without knowing it?

The content is known at compile time, we could put checks in. But yeah
4k isn't that much text..

> Even after reading the above link, I can't really understand what this
> is being used for.  As it's sysfs files, why aren't Documentation/ABI/
> files also being created with the patch explaining it all?

Ah, yeah, documentation, wasn't that written in C :-)

But fair enough... Anyway, the purpose is to describe the magic bits
that go into perf_event_attr::config[012] for a particular pmu.

Basically they're the 'hardware' bitmasks we want to export, so that
userspace can deal with sane name/value pairs.

> Again, if at all possible, sysfs should be one value per file.  Please
> NEVER create a sysfs file that requires a parser to determine what is
> going on in it.  It should be a simple 'read the value' type thing.

The whole purpose was to drive a parser :-) Anyway, is:
"config:0-7,32-35" acceptable for a single file?

This means, the 'config' member of struct perf_event_attr bits 0-7,32-35
form a bitfield whose name is then given by the filename that has this
content.

> So yes, multiple sysfs files do make sense, the resource load should be
> almost non-existant for new ones.

Surely all these attribute objects take more space than a few lines of
text, but ok, I guess multiple files it is.


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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-25 10:49                           ` Peter Zijlstra
@ 2012-01-25 14:37                             ` Jiri Olsa
  2012-01-26 16:23                               ` Peter Zijlstra
  2012-01-25 17:01                             ` Greg KH
  1 sibling, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-25 14:37 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Greg KH, acme, mingo, paulus, cjashfor, linux-kernel

On Wed, Jan 25, 2012 at 11:49:33AM +0100, Peter Zijlstra wrote:
> On Tue, 2012-01-24 at 16:53 -0800, Greg KH wrote:
> 
> > Well, what's to keep someone from exploding one of those files to go
> > over the buffer size without knowing it?
> 
> The content is known at compile time, we could put checks in. But yeah
> 4k isn't that much text..
> 
> > Even after reading the above link, I can't really understand what this
> > is being used for.  As it's sysfs files, why aren't Documentation/ABI/
> > files also being created with the patch explaining it all?
> 
> Ah, yeah, documentation, wasn't that written in C :-)
> 
> But fair enough... Anyway, the purpose is to describe the magic bits
> that go into perf_event_attr::config[012] for a particular pmu.
> 
> Basically they're the 'hardware' bitmasks we want to export, so that
> userspace can deal with sane name/value pairs.
> 
> > Again, if at all possible, sysfs should be one value per file.  Please
> > NEVER create a sysfs file that requires a parser to determine what is
> > going on in it.  It should be a simple 'read the value' type thing.
> 
> The whole purpose was to drive a parser :-) Anyway, is:
> "config:0-7,32-35" acceptable for a single file?
> 
> This means, the 'config' member of struct perf_event_attr bits 0-7,32-35
> form a bitfield whose name is then given by the filename that has this
> content.
> 
> > So yes, multiple sysfs files do make sense, the resource load should be
> > almost non-existant for new ones.
> 
> Surely all these attribute objects take more space than a few lines of
> text, but ok, I guess multiple files it is.
> 

please check attached patch, would something like this be ok?

jirka
---
 .../testing/sysfs-bus-event_source-devices-format  |   14 ++++++++++++
 include/linux/perf_event.h                         |   22 ++++++++++++++++++++
 kernel/events/core.c                               |   22 ++++++++++++++++++++
 3 files changed, 58 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-event_source-devices-format

diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-format b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
new file mode 100644
index 0000000..5a15221
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
@@ -0,0 +1,14 @@
+Where:		/sys/bus/event_source/devices/<dev>/format
+Date:		January 2012
+Kernel Version: 3.3
+Contact:	Jiri Olsa <jolsa@redhat.com>
+Description:
+		Attribute group for to describe the magic bits that go into
+		perf_event_attr::config[012] for a particular pmu.
+		Each attribute of this group defines the 'hardware' bitmask
+		we want to export, so that userspace can deal with sane
+		name/value pairs.
+
+		Example: 'config1:1,6-10,44'
+		Defines contents of attribute that occupies bits 1,6-10,44 of
+		perf_event_attr::config1.
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0b91db2..e2bf1c7 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -516,6 +516,7 @@ struct perf_guest_info_callbacks {
 #include <linux/irq_work.h>
 #include <linux/jump_label.h>
 #include <linux/atomic.h>
+#include <linux/sysfs.h>
 #include <asm/local.h>
 
 #define PERF_MAX_STACK_DEPTH		255
@@ -626,6 +627,12 @@ struct pmu {
 	int				task_ctx_nr;
 
 	/*
+	 * True if the pmu defines its own set of format attributes within
+	 * attr_groups. If false, default format attributes are used.
+	 */
+	bool				format_defined;
+
+	/*
 	 * Fully disable/enable this PMU, can be used to protect from the PMI
 	 * as well as for lazy/batch writing of the MSRs.
 	 */
@@ -1215,5 +1222,20 @@ do {									\
 	register_cpu_notifier(&fn##_nb);				\
 } while (0)
 
+
+#define PMU_FORMAT_ATTR(_name, _format)				\
+static ssize_t							\
+pmu_format_attr_##_name##_show(struct device *dev,		\
+			       struct device_attribute *attr,	\
+			       char *page)			\
+{								\
+	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);		\
+	return sprintf(page, _format "\n");			\
+}								\
+								\
+static struct device_attribute format_attr_##_name =		\
+	__ATTR(_name, 0444,					\
+	       pmu_format_attr_##_name##_show, NULL)
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_PERF_EVENT_H */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index de859fb..8d2d6f3 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5503,6 +5503,22 @@ static struct bus_type pmu_bus = {
 	.dev_attrs	= pmu_dev_attrs,
 };
 
+/* Default format attributes. */
+PMU_FORMAT_ATTR(config,  "config:0-63");
+PMU_FORMAT_ATTR(config1, "config1:0-63");
+PMU_FORMAT_ATTR(config2, "config2:0-63");
+
+static struct attribute *format_attrs[] = {
+	&format_attr_config.attr,
+	&format_attr_config1.attr,
+	&format_attr_config2.attr,
+};
+
+static struct attribute_group format_attr_group = {
+	.name   = "format",
+	.attrs  = format_attrs,
+};
+
 static void pmu_dev_release(struct device *dev)
 {
 	kfree(dev);
@@ -5529,6 +5545,12 @@ static int pmu_dev_alloc(struct pmu *pmu)
 	if (ret)
 		goto free_dev;
 
+	if (!pmu->format_defined) {
+		ret = sysfs_create_group(&pmu->dev->kobj, &format_attr_group);
+		if (ret)
+			goto free_dev;
+	}
+
 out:
 	return ret;
 
-- 
1.7.1


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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-25 10:49                           ` Peter Zijlstra
  2012-01-25 14:37                             ` Jiri Olsa
@ 2012-01-25 17:01                             ` Greg KH
  1 sibling, 0 replies; 91+ messages in thread
From: Greg KH @ 2012-01-25 17:01 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, linux-kernel

On Wed, Jan 25, 2012 at 11:49:33AM +0100, Peter Zijlstra wrote:
> On Tue, 2012-01-24 at 16:53 -0800, Greg KH wrote:
> 
> > Well, what's to keep someone from exploding one of those files to go
> > over the buffer size without knowing it?
> 
> The content is known at compile time, we could put checks in. But yeah
> 4k isn't that much text..
> 
> > Even after reading the above link, I can't really understand what this
> > is being used for.  As it's sysfs files, why aren't Documentation/ABI/
> > files also being created with the patch explaining it all?
> 
> Ah, yeah, documentation, wasn't that written in C :-)
> 
> But fair enough... Anyway, the purpose is to describe the magic bits
> that go into perf_event_attr::config[012] for a particular pmu.
> 
> Basically they're the 'hardware' bitmasks we want to export, so that
> userspace can deal with sane name/value pairs.
> 
> > Again, if at all possible, sysfs should be one value per file.  Please
> > NEVER create a sysfs file that requires a parser to determine what is
> > going on in it.  It should be a simple 'read the value' type thing.
> 
> The whole purpose was to drive a parser :-) Anyway, is:
> "config:0-7,32-35" acceptable for a single file?
> 
> This means, the 'config' member of struct perf_event_attr bits 0-7,32-35
> form a bitfield whose name is then given by the filename that has this
> content.

Yes, that would be fine.

> > So yes, multiple sysfs files do make sense, the resource load should be
> > almost non-existant for new ones.
> 
> Surely all these attribute objects take more space than a few lines of
> text, but ok, I guess multiple files it is.

Great, thanks for asking.

greg k-h

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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-25 14:37                             ` Jiri Olsa
@ 2012-01-26 16:23                               ` Peter Zijlstra
  2012-01-26 16:27                                 ` Greg KH
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-26 16:23 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: Greg KH, acme, mingo, paulus, cjashfor, linux-kernel

On Wed, 2012-01-25 at 15:37 +0100, Jiri Olsa wrote:
> please check attached patch, would something like this be ok?

Looks fine to me, Greg is that Documentation thing good enough

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

* Re: [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-16 12:31                       ` [PATCH 5/9] perf: Add sysfs format attribute for pmu device Jiri Olsa
  2012-01-23 15:13                         ` Eric W. Biederman
@ 2012-01-26 16:26                         ` Peter Zijlstra
  2012-01-27 12:32                           ` Jiri Olsa
  1 sibling, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-26 16:26 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Mon, 2012-01-16 at 13:31 +0100, Jiri Olsa wrote:
> Adding 'format' attribute for pmu device that contains
> a syntax description on how to construct raw events.
> 
> The event configuration is described in following
> struct pefr_event_attr attributes:
> 
>   config
>   config1
>   config2
> 
> Each line of the format file describes mapping of name
> and bitfield definition within one of abve attributes.
> 
> eg:
>   event   config:0-7
>   umask   config:8-15
>   usr     config:16
>   os      config:17
>   edge    config:18
>   any     config:21
>   inv     config:23
>   cmask   config:24-31
> 
> Line syntax:
>   line:      NAME config ':' bits
>   config:    'config' | 'config1' | 'config2"
>   bits:      bits ',' bit_term | bit_term
>   bit_term:  VALUE '-' VALUE | VALUE
> 
> Adding event_format callback to the struct pmu, which provides
> the format information. The pmu shall override this function
> and provide its own specific format information.
> 
> If not overloaded the default format information is used:
> 
>   config  config:0-63
>   config1 config1:0-63
>   config2 config2:0-63 

Shouldn't config[012] be hard-coded like period? They are struct
perf_event_attr members after all and it doesn't really make sense to
have them dynamic if we're going to have to add them to all pmu/format
things.



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

* Re: [RFCv3 0/9] perf tool: parser generator for events parsing
  2012-01-26 16:23                               ` Peter Zijlstra
@ 2012-01-26 16:27                                 ` Greg KH
  0 siblings, 0 replies; 91+ messages in thread
From: Greg KH @ 2012-01-26 16:27 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, linux-kernel

On Thu, Jan 26, 2012 at 05:23:09PM +0100, Peter Zijlstra wrote:
> On Wed, 2012-01-25 at 15:37 +0100, Jiri Olsa wrote:
> > please check attached patch, would something like this be ok?
> 
> Looks fine to me, Greg is that Documentation thing good enough

Yes, looks good to me, thanks.

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

* Re: [PATCH 5/9] perf: Add sysfs format attribute for pmu device
  2012-01-26 16:26                         ` Peter Zijlstra
@ 2012-01-27 12:32                           ` Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 12:32 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Thu, Jan 26, 2012 at 05:26:49PM +0100, Peter Zijlstra wrote:
> On Mon, 2012-01-16 at 13:31 +0100, Jiri Olsa wrote:
> > Adding 'format' attribute for pmu device that contains
> > a syntax description on how to construct raw events.
> > 
> > The event configuration is described in following
> > struct pefr_event_attr attributes:
> > 
> >   config
> >   config1
> >   config2
> > 
> > Each line of the format file describes mapping of name
> > and bitfield definition within one of abve attributes.
> > 
> > eg:
> >   event   config:0-7
> >   umask   config:8-15
> >   usr     config:16
> >   os      config:17
> >   edge    config:18
> >   any     config:21
> >   inv     config:23
> >   cmask   config:24-31
> > 
> > Line syntax:
> >   line:      NAME config ':' bits
> >   config:    'config' | 'config1' | 'config2"
> >   bits:      bits ',' bit_term | bit_term
> >   bit_term:  VALUE '-' VALUE | VALUE
> > 
> > Adding event_format callback to the struct pmu, which provides
> > the format information. The pmu shall override this function
> > and provide its own specific format information.
> > 
> > If not overloaded the default format information is used:
> > 
> >   config  config:0-63
> >   config1 config1:0-63
> >   config2 config2:0-63 
> 
> Shouldn't config[012] be hard-coded like period? They are struct
> perf_event_attr members after all and it doesn't really make sense to
> have them dynamic if we're going to have to add them to all pmu/format
> things.

Well, let me clarify that config[12] and 'period' are different stuff.
Also I remember you asked me about the config terms namespace in some
other email and I forgot to answer :)


So, while period is event term that user can specify in the event config
section like:
      cycles/period=100000/

the config[12] are values that are specified in the format definitions
as values that are changed by event terms.. like:
	config1:1,6-10,44

Now for event terms.. whatever term name is specified in the pmu
format definition, it is considered as valid term, when the 'pmu' event
is configured.. eg events like:
	cpu/krava=1/u

Apart from that we recognize the term 'period', which could be specified
only for symbolic events so far:
      cycles/period=100000/

So there can't be name clash between 'period' term and the rest so far.
Once we would like to have say 'period' term inside 'pmu' events like:
	cpu/krava=1,period=1000/u

we would need to consider some namespace rules or smth.


Now for config[12] formats.. they are parsed as simple strings and
'hardcoded' in function format_value. I think what you suggest is
to 'hardcode' them into the grammar... right?

So instead of using rule:
format_term: PP_NAME ':' bits

there'll be 3 rules like:

format_term: 'config':' bits
format_term: 'config1' ':' bits
format_term: 'config2' ':' bits

I dont have strong feelings one way or the other... but since we already
have the parser in place we could use it.. ehm :)


thanks,
jirka

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

* [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
                                         ` (10 preceding siblings ...)
  2012-01-24 16:26                       ` Peter Zijlstra
@ 2012-01-27 14:34                       ` Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
                                           ` (10 more replies)
  11 siblings, 11 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel

hi,
Here's new version of event parsing patchset. To summarize:
 - adding event parser bison/flex generator
 - the event syntax stays as it was
 - adding event format sysfs group attribute
   for pmu device
 - adding new syntax to specify raw events based
   on the sysfs pmu's format attribute
   eg. "cpu/config=1,config1=2,config2=3/u"

There are helping patches 1-4, which I did not want to
mangle with the actual change. Patches 5-9 implement
the feature itself.

v4 changes:
 - 5/9 changed sysfs pmu format definitions to the group attribute,
       each line (in previous patch) is now represented by single
       sysfs attribute under format group
 - 6/9 fix raw events so the number is always considered to be hex number
 - 8/9 move config[12] definitions to be processed by the parser

Attached patches:
 1/9 perf, tool: Make perf_evlist__splice_list_tail global
 2/9 perf, tool: Remove unused functions from debugfs object
 3/9 perf, tool: Add sysfs mountpoint interface
 4/9 perf, tool: Add bitmap_or function into bitmap object
 5/9 perf: Adding sysfs group format attribute for pmu device
 6/9 perf, tool: Add parser generator for events parsing
 7/9 perf, tool: Add config options support for event parsing
 8/9 perf, tool: Add perf pmu object to access pmu format definition
 9/9 perf, tool: Add support to specify pmu style event


thanks,
jirka
---
 .../testing/sysfs-bus-event_source-devices-format  |   14 +
 include/linux/perf_event.h                         |   22 +
 kernel/events/core.c                               |   22 +
 tools/perf/Makefile                                |   31 +
 tools/perf/builtin-test.c                          |   52 +-
 tools/perf/util/bitmap.c                           |   10 +
 tools/perf/util/debugfs.c                          |  141 --
 tools/perf/util/debugfs.h                          |    6 -
 tools/perf/util/evlist.c                           |    6 +-
 tools/perf/util/evlist.h                           |    5 +
 tools/perf/util/include/linux/bitmap.h             |   11 +
 tools/perf/util/parse-events-bison.c               | 1813 ++++++++++++++++
 tools/perf/util/parse-events-bison.h               |   81 +
 tools/perf/util/parse-events-flex.c                | 2225 ++++++++++++++++++++
 tools/perf/util/parse-events-flex.h                |  316 +++
 tools/perf/util/parse-events.c                     |  552 ++---
 tools/perf/util/parse-events.h                     |   37 +
 tools/perf/util/parse-events.l                     |  107 +
 tools/perf/util/parse-events.y                     |  191 ++
 tools/perf/util/pmu-bison.c                        | 1663 +++++++++++++++
 tools/perf/util/pmu-bison.h                        |   73 +
 tools/perf/util/pmu-flex.c                         | 1821 ++++++++++++++++
 tools/perf/util/pmu-flex.h                         |  316 +++
 tools/perf/util/pmu.c                              |  462 ++++
 tools/perf/util/pmu.h                              |   41 +
 tools/perf/util/pmu.l                              |   43 +
 tools/perf/util/pmu.y                              |   93 +
 tools/perf/util/sysfs.c                            |   60 +
 tools/perf/util/sysfs.h                            |    6 +
 29 files changed, 9740 insertions(+), 480 deletions(-)

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

* [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-02-07 19:31                           ` [tip:perf/core] perf evlist: Make splice_list_tail method public tip-bot for Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 2/9] perf, tool: Remove unused functions from debugfs object Jiri Olsa
                                           ` (9 subsequent siblings)
  10 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Making perf_evlist__splice_list_tail globaly accessible.
It is used in the upcomming paches.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/evlist.c |    6 +++---
 tools/perf/util/evlist.h |    5 +++++
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index a6d50e3..a57a8cf 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -97,9 +97,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 	++evlist->nr_entries;
 }
 
-static void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
-					  struct list_head *list,
-					  int nr_entries)
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries)
 {
 	list_splice_tail(list, &evlist->entries);
 	evlist->nr_entries += nr_entries;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 9c51660..1b4282b 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -117,4 +117,9 @@ u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
 
 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
+
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries);
+
 #endif /* __PERF_EVLIST_H */
-- 
1.7.4.4


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

* [PATCH 2/9] perf, tool: Remove unused functions from debugfs object
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-02-17  9:51                           ` [tip:perf/core] perf tools: " tip-bot for Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 3/9] perf, tool: Add sysfs mountpoint interface Jiri Olsa
                                           ` (8 subsequent siblings)
  10 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Following debugfs object functions are not referenced
within the code:

  int debugfs_valid_entry(const char *path);
  int debugfs_umount(void);
  int debugfs_write(const char *entry, const char *value);
  int debugfs_read(const char *entry, char *buffer, size_t size);
  void debugfs_force_cleanup(void);
  int debugfs_make_path(const char *element, char *buffer, int size);

Removing them.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/debugfs.c |  141 ---------------------------------------------
 tools/perf/util/debugfs.h |    6 --
 2 files changed, 0 insertions(+), 147 deletions(-)

diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index ffc35e7..dd8b193 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -15,32 +15,6 @@ static const char *debugfs_known_mountpoints[] = {
 	0,
 };
 
-/* use this to force a umount */
-void debugfs_force_cleanup(void)
-{
-	debugfs_find_mountpoint();
-	debugfs_premounted = 0;
-	debugfs_umount();
-}
-
-/* construct a full path to a debugfs element */
-int debugfs_make_path(const char *element, char *buffer, int size)
-{
-	int len;
-
-	if (strlen(debugfs_mountpoint) == 0) {
-		buffer[0] = '\0';
-		return -1;
-	}
-
-	len = strlen(debugfs_mountpoint) + strlen(element) + 1;
-	if (len >= size)
-		return len+1;
-
-	snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
-	return 0;
-}
-
 static int debugfs_found;
 
 /* find the path to the mounted debugfs */
@@ -97,17 +71,6 @@ int debugfs_valid_mountpoint(const char *debugfs)
 	return 0;
 }
 
-
-int debugfs_valid_entry(const char *path)
-{
-	struct stat st;
-
-	if (stat(path, &st))
-		return -errno;
-
-	return 0;
-}
-
 static void debugfs_set_tracing_events_path(const char *mountpoint)
 {
 	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -149,107 +112,3 @@ void debugfs_set_path(const char *mountpoint)
 	snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
 	debugfs_set_tracing_events_path(mountpoint);
 }
-
-/* umount the debugfs */
-
-int debugfs_umount(void)
-{
-	char umountcmd[128];
-	int ret;
-
-	/* if it was already mounted, leave it */
-	if (debugfs_premounted)
-		return 0;
-
-	/* make sure it's a valid mount point */
-	ret = debugfs_valid_mountpoint(debugfs_mountpoint);
-	if (ret)
-		return ret;
-
-	snprintf(umountcmd, sizeof(umountcmd),
-		 "/bin/umount %s", debugfs_mountpoint);
-	return system(umountcmd);
-}
-
-int debugfs_write(const char *entry, const char *value)
-{
-	char path[PATH_MAX + 1];
-	int ret, count;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* get how many chars we're going to write */
-	count = strlen(value);
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDWR);
-	if (fd < 0)
-		return -errno;
-
-	while (count > 0) {
-		/* write it */
-		ret = write(fd, value, count);
-		if (ret <= 0) {
-			if (ret == EAGAIN)
-				continue;
-			close(fd);
-			return -errno;
-		}
-		count -= ret;
-	}
-
-	/* close it */
-	close(fd);
-
-	/* return success */
-	return 0;
-}
-
-/*
- * read a debugfs entry
- * returns the number of chars read or a negative errno
- */
-int debugfs_read(const char *entry, char *buffer, size_t size)
-{
-	char path[PATH_MAX + 1];
-	int ret;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDONLY);
-	if (fd < 0)
-		return -errno;
-
-	do {
-		/* read it */
-		ret = read(fd, buffer, size);
-		if (ret == 0) {
-			close(fd);
-			return EOF;
-		}
-	} while (ret < 0 && errno == EAGAIN);
-
-	/* close it */
-	close(fd);
-
-	/* make *sure* there's a null character at the end */
-	buffer[ret] = '\0';
-
-	/* return the number of chars read */
-	return ret;
-}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 4a878f7..68f3e87 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -3,14 +3,8 @@
 
 const char *debugfs_find_mountpoint(void);
 int debugfs_valid_mountpoint(const char *debugfs);
-int debugfs_valid_entry(const char *path);
 char *debugfs_mount(const char *mountpoint);
-int debugfs_umount(void);
 void debugfs_set_path(const char *mountpoint);
-int debugfs_write(const char *entry, const char *value);
-int debugfs_read(const char *entry, char *buffer, size_t size);
-void debugfs_force_cleanup(void);
-int debugfs_make_path(const char *element, char *buffer, int size);
 
 extern char debugfs_mountpoint[];
 extern char tracing_events_path[];
-- 
1.7.4.4


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

* [PATCH 3/9] perf, tool: Add sysfs mountpoint interface
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 2/9] perf, tool: Remove unused functions from debugfs object Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-02-17  9:52                           ` [tip:perf/core] perf tools: " tip-bot for Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object Jiri Olsa
                                           ` (7 subsequent siblings)
  10 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding sysfs object to provide sysfs mount information
in the same way as debugfs object does.

The object provides following function:
  sysfs_find_mountpoint

which returns the sysfs mount mount.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile     |    2 +
 tools/perf/util/sysfs.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/sysfs.h |    6 ++++
 3 files changed, 68 insertions(+), 0 deletions(-)
 create mode 100644 tools/perf/util/sysfs.c
 create mode 100644 tools/perf/util/sysfs.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index d64f581..f170235 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -256,6 +256,7 @@ LIB_H += util/callchain.h
 LIB_H += util/build-id.h
 LIB_H += util/debug.h
 LIB_H += util/debugfs.h
+LIB_H += util/sysfs.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
 LIB_H += util/evlist.h
@@ -302,6 +303,7 @@ LIB_OBJS += $(OUTPUT)util/build-id.o
 LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
+LIB_OBJS += $(OUTPUT)util/sysfs.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
 LIB_OBJS += $(OUTPUT)util/evlist.o
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
new file mode 100644
index 0000000..48c6902
--- /dev/null
+++ b/tools/perf/util/sysfs.c
@@ -0,0 +1,60 @@
+
+#include "util.h"
+#include "sysfs.h"
+
+static const char * const sysfs_known_mountpoints[] = {
+	"/sys",
+	0,
+};
+
+static int sysfs_found;
+char sysfs_mountpoint[PATH_MAX];
+
+static int sysfs_valid_mountpoint(const char *sysfs)
+{
+	struct statfs st_fs;
+
+	if (statfs(sysfs, &st_fs) < 0)
+		return -ENOENT;
+	else if (st_fs.f_type != (long) SYSFS_MAGIC)
+		return -ENOENT;
+
+	return 0;
+}
+
+const char *sysfs_find_mountpoint(void)
+{
+	const char * const *ptr;
+	char type[100];
+	FILE *fp;
+
+	if (sysfs_found)
+		return (const char *) sysfs_mountpoint;
+
+	ptr = sysfs_known_mountpoints;
+	while (*ptr) {
+		if (sysfs_valid_mountpoint(*ptr) == 0) {
+			sysfs_found = 1;
+			strcpy(sysfs_mountpoint, *ptr);
+			return sysfs_mountpoint;
+		}
+		ptr++;
+	}
+
+	/* give up and parse /proc/mounts */
+	fp = fopen("/proc/mounts", "r");
+	if (fp == NULL)
+		return NULL;
+
+	while (!sysfs_found &&
+	       fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
+		      sysfs_mountpoint, type) == 2) {
+
+		if (strcmp(type, "sysfs") == 0)
+			sysfs_found = 1;
+	}
+
+	fclose(fp);
+
+	return sysfs_found ? sysfs_mountpoint : NULL;
+}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
new file mode 100644
index 0000000..a813b72
--- /dev/null
+++ b/tools/perf/util/sysfs.h
@@ -0,0 +1,6 @@
+#ifndef __SYSFS_H__
+#define __SYSFS_H__
+
+const char *sysfs_find_mountpoint(void);
+
+#endif /* __DEBUGFS_H__ */
-- 
1.7.4.4


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

* [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (2 preceding siblings ...)
  2012-01-27 14:34                         ` [PATCH 3/9] perf, tool: Add sysfs mountpoint interface Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-02-17  9:53                           ` [tip:perf/core] perf tools: " tip-bot for Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device Jiri Olsa
                                           ` (6 subsequent siblings)
  10 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding implementation os bitmap_or function to the bitmap
object. It is stolen from the kernel lib/bitmap.o object.

It is used in upcomming patches.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/bitmap.c               |   10 ++++++++++
 tools/perf/util/include/linux/bitmap.h |   11 +++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
index 5e230ac..0a1adc1 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/perf/util/bitmap.c
@@ -19,3 +19,13 @@ int __bitmap_weight(const unsigned long *bitmap, int bits)
 
 	return w;
 }
+
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits)
+{
+	int k;
+	int nr = BITS_TO_LONGS(bits);
+
+	for (k = 0; k < nr; k++)
+		dst[k] = bitmap1[k] | bitmap2[k];
+}
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index eda4416..bb162e4 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -5,6 +5,8 @@
 #include <linux/bitops.h>
 
 int __bitmap_weight(const unsigned long *bitmap, int bits);
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits);
 
 #define BITMAP_LAST_WORD_MASK(nbits)					\
 (									\
@@ -32,4 +34,13 @@ static inline int bitmap_weight(const unsigned long *src, int nbits)
 	return __bitmap_weight(src, nbits);
 }
 
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+			     const unsigned long *src2, int nbits)
+{
+	if (small_const_nbits(nbits))
+		*dst = *src1 | *src2;
+	else
+		__bitmap_or(dst, src1, src2, nbits);
+}
+
 #endif /* _PERF_BITOPS_H */
-- 
1.7.4.4


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

* [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (3 preceding siblings ...)
  2012-01-27 14:34                         ` [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-01-27 21:08                           ` Corey Ashford
  2012-01-27 14:34                         ` [PATCH 6/9] perf, tool: Add parser generator for events parsing Jiri Olsa
                                           ` (5 subsequent siblings)
  10 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding sysfs group 'format' attribute for pmu device that
contains a syntax description on how to construct raw events.

The event configuration is described in following
struct pefr_event_attr attributes:

  config
  config1
  config2

Each sysfs attribute within the format attribute group,
describes mapping of name and bitfield definition within
one of above attributes.

eg:
  "/sys/...<dev>/format/event" contains "config:0-7"
  "/sys/...<dev>/format/umask" contains "config:8-15"
  "/sys/...<dev>/format/usr"   contains "config:16"

the attribute value syntax is:

  line:      config ':' bits
  config:    'config' | 'config1' | 'config2"
  bits:      bits ',' bit_term | bit_term
  bit_term:  VALUE '-' VALUE | VALUE

Adding format_defined bool to the struct pmu to specify wether
pmu defines its own set of format attributes (within the
attr_groups member) or the default format attributes should be
used:
  "/sys/...<dev>/format/config"  contains "config:0-63"
  "/sys/...<dev>/format/config1" contains "config1:0-63"
  "/sys/...<dev>/format/config2" contains "config2:0-63"

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 .../testing/sysfs-bus-event_source-devices-format  |   14 ++++++++++++
 include/linux/perf_event.h                         |   22 ++++++++++++++++++++
 kernel/events/core.c                               |   22 ++++++++++++++++++++
 3 files changed, 58 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-event_source-devices-format

diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-format b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
new file mode 100644
index 0000000..079afc7
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
@@ -0,0 +1,14 @@
+Where:		/sys/bus/event_source/devices/<dev>/format
+Date:		January 2012
+Kernel Version: 3.3
+Contact:	Jiri Olsa <jolsa@redhat.com>
+Description:
+		Attribute group to describe the magic bits that go into
+		perf_event_attr::config[012] for a particular pmu.
+		Each attribute of this group defines the 'hardware' bitmask
+		we want to export, so that userspace can deal with sane
+		name/value pairs.
+
+		Example: 'config1:1,6-10,44'
+		Defines contents of attribute that occupies bits 1,6-10,44 of
+		perf_event_attr::config1.
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0b91db2..e2bf1c7 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -516,6 +516,7 @@ struct perf_guest_info_callbacks {
 #include <linux/irq_work.h>
 #include <linux/jump_label.h>
 #include <linux/atomic.h>
+#include <linux/sysfs.h>
 #include <asm/local.h>
 
 #define PERF_MAX_STACK_DEPTH		255
@@ -626,6 +627,12 @@ struct pmu {
 	int				task_ctx_nr;
 
 	/*
+	 * True if the pmu defines its own set of format attributes within
+	 * attr_groups. If false, default format attributes are used.
+	 */
+	bool				format_defined;
+
+	/*
 	 * Fully disable/enable this PMU, can be used to protect from the PMI
 	 * as well as for lazy/batch writing of the MSRs.
 	 */
@@ -1215,5 +1222,20 @@ do {									\
 	register_cpu_notifier(&fn##_nb);				\
 } while (0)
 
+
+#define PMU_FORMAT_ATTR(_name, _format)				\
+static ssize_t							\
+pmu_format_attr_##_name##_show(struct device *dev,		\
+			       struct device_attribute *attr,	\
+			       char *page)			\
+{								\
+	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);		\
+	return sprintf(page, _format "\n");			\
+}								\
+								\
+static struct device_attribute format_attr_##_name =		\
+	__ATTR(_name, 0444,					\
+	       pmu_format_attr_##_name##_show, NULL)
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_PERF_EVENT_H */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index de859fb..8d2d6f3 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5503,6 +5503,22 @@ static struct bus_type pmu_bus = {
 	.dev_attrs	= pmu_dev_attrs,
 };
 
+/* Default format attributes. */
+PMU_FORMAT_ATTR(config,  "config:0-63");
+PMU_FORMAT_ATTR(config1, "config1:0-63");
+PMU_FORMAT_ATTR(config2, "config2:0-63");
+
+static struct attribute *format_attrs[] = {
+	&format_attr_config.attr,
+	&format_attr_config1.attr,
+	&format_attr_config2.attr,
+};
+
+static struct attribute_group format_attr_group = {
+	.name   = "format",
+	.attrs  = format_attrs,
+};
+
 static void pmu_dev_release(struct device *dev)
 {
 	kfree(dev);
@@ -5529,6 +5545,12 @@ static int pmu_dev_alloc(struct pmu *pmu)
 	if (ret)
 		goto free_dev;
 
+	if (!pmu->format_defined) {
+		ret = sysfs_create_group(&pmu->dev->kobj, &format_attr_group);
+		if (ret)
+			goto free_dev;
+	}
+
 out:
 	return ret;
 
-- 
1.7.4.4


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

* [PATCH 6/9] perf, tool: Add parser generator for events parsing
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (4 preceding siblings ...)
  2012-01-27 14:34                         ` [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 7/9] perf, tool: Add config options support for event parsing Jiri Olsa
                                           ` (4 subsequent siblings)
  10 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Changing event parsing to use flex/bison parse generator.
The event syntax stays as it was.

grammar description:

events: events ',' event | event

event:  event_def PE_MODIFIER_EVENT | event_def

event_def: event_legacy_symbol sep_dc     |
           event_legacy_cache sep_dc      |
           event_legacy_breakpoint sep_dc |
           event_legacy_tracepoint sep_dc |
           event_legacy_numeric sep_dc    |
           event_legacy_raw sep_dc

event_legacy_symbol:      PE_NAME_SYM

event_legacy_cache:       PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
                          PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT  |
                          PE_NAME_CACHE_TYPE

event_legacy_raw:         PE_SEP_RAW PE_VALUE

event_legacy_numeric:     PE_VALUE ':' PE_VALUE

event_legacy_breakpoint:  PE_SEP_BP ':' PE_VALUE ':' PE_MODIFIER_BP

event_breakpoint_type:    PE_MODIFIER_BPTYPE | empty

PE_NAME_SYM:              cpu-cycles|cycles                              |
                          stalled-cycles-frontend|idle-cycles-frontend   |
                          stalled-cycles-backend|idle-cycles-backend     |
                          instructions                                   |
                          cache-references                               |
                          cache-misses                                   |
                          branch-instructions|branches                   |
                          branch-misses                                  |
                          bus-cycles                                     |
                          cpu-clock                                      |
                          task-clock                                     |
                          page-faults|faults                             |
                          minor-faults                                   |
                          major-faults                                   |
                          context-switches|cs                            |
                          cpu-migrations|migrations                      |
                          alignment-faults                               |
                          emulation-faults

PE_NAME_CACHE_TYPE:       L1-dcache|l1-d|l1d|L1-data             |
                          L1-icache|l1-i|l1i|L1-instruction      |
                          LLC|L2                                 |
                          dTLB|d-tlb|Data-TLB                    |
                          iTLB|i-tlb|Instruction-TLB             |
                          branch|branches|bpu|btb|bpc            |
                          node

PE_NAME_CACHE_OP_RESULT:  load|loads|read                        |
                          store|stores|write                     |
                          prefetch|prefetches                    |
                          speculative-read|speculative-load      |
                          refs|Reference|ops|access              |
                          misses|miss

PE_MODIFIER_EVENT:        [ukhp]{0,5}

PE_MODIFIER_BP:           [rwx]

PE_SEP_BP:                'mem'

PE_SEP_RAW:               'r'

sep_dc:                   ':' |

Added flex/bison files for event grammar parsing. The generated
parser is part of the patch. Added makefile rule 'event-parser'
to generate the parser code out of the bison/flex sources.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile                  |   17 +
 tools/perf/builtin-test.c            |    6 +-
 tools/perf/util/parse-events-bison.c | 1715 ++++++++++++++++++++++++++
 tools/perf/util/parse-events-bison.h |   79 ++
 tools/perf/util/parse-events-flex.c  | 2225 ++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events-flex.h  |  316 +++++
 tools/perf/util/parse-events.c       |  486 +++------
 tools/perf/util/parse-events.h       |   15 +
 tools/perf/util/parse-events.l       |  107 ++
 tools/perf/util/parse-events.y       |  127 ++
 10 files changed, 4752 insertions(+), 341 deletions(-)
 create mode 100644 tools/perf/util/parse-events-bison.c
 create mode 100644 tools/perf/util/parse-events-bison.h
 create mode 100644 tools/perf/util/parse-events-flex.c
 create mode 100644 tools/perf/util/parse-events-flex.h
 create mode 100644 tools/perf/util/parse-events.l
 create mode 100644 tools/perf/util/parse-events.y

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index f170235..ee48082 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -47,6 +47,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
+FLEX = $(CROSS_COMPILE)flex
+BISON= $(CROSS_COMPILE)bison
 
 # Additional ARCH settings for x86
 ifeq ($(ARCH),i386)
@@ -340,6 +342,8 @@ LIB_OBJS += $(OUTPUT)util/session.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
+LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
+LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -628,6 +632,8 @@ ifndef V
 	QUIET_LINK     = @echo '   ' LINK $@;
 	QUIET_MKDIR    = @echo '   ' MKDIR $@;
 	QUIET_GEN      = @echo '   ' GEN $@;
+	QUIET_FLEX     = @echo '   ' FLEX $@;
+	QUIET_BISON    = @echo '   ' BISON $@;
 endif
 endif
 
@@ -708,6 +714,9 @@ $(OUTPUT)perf.o perf.spec \
 	$(SCRIPTS) \
 	: $(OUTPUT)PERF-VERSION-FILE
 
+.SUFFIXES:
+.SUFFIXES: .o .c .S .s
+
 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
 $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
@@ -740,6 +749,9 @@ $(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+$(OUTPUT)util/parse-events-flex.o: util/parse-events-flex.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
@@ -776,6 +788,7 @@ help:
 	@echo '  html		- make html documentation'
 	@echo '  info		- make GNU info documentation (access with info <foo>)'
 	@echo '  pdf		- make pdf documentation'
+	@echo '  event-parser	- make event parser code'
 	@echo '  TAGS		- use etags to make tag information for source browsing'
 	@echo '  tags		- use ctags to make tag information for source browsing'
 	@echo '  cscope	- use cscope to make interactive browsing database'
@@ -826,6 +839,10 @@ cscope:
 	$(RM) cscope*
 	$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
 
+event-parser:
+	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o util/parse-events-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=util/parse-events-flex.h -t util/parse-events.l > util/parse-events-flex.c
+
 ### Detect prefix changes
 TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
              $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 70c4eb2..adf959f 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -650,7 +650,7 @@ static int test__checkevent_raw(struct perf_evlist *evlist)
 
 	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 config", 0x1a == evsel->attr.config);
 	return 0;
 }
 
@@ -872,7 +872,7 @@ static struct test__event_st {
 		.check = test__checkevent_tracepoint_multi,
 	},
 	{
-		.name  = "r1",
+		.name  = "r1a",
 		.check = test__checkevent_raw,
 	},
 	{
@@ -916,7 +916,7 @@ static struct test__event_st {
 		.check = test__checkevent_tracepoint_multi_modifier,
 	},
 	{
-		.name  = "r1:kp",
+		.name  = "r1a:kp",
 		.check = test__checkevent_raw_modifier,
 	},
 	{
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
new file mode 100644
index 0000000..20fca26
--- /dev/null
+++ b/tools/perf/util/parse-events-bison.c
@@ -0,0 +1,1715 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.4.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse         parse_events_parse
+#define yylex           parse_events_lex
+#define yyerror         parse_events_error
+#define yylval          parse_events_lval
+#define yychar          parse_events_char
+#define yydebug         parse_events_debug
+#define yynerrs         parse_events_nerrs
+
+
+/* Copy the first part of user declarations.  */
+
+/* Line 189 of yacc.c  */
+#line 6 "util/parse-events.y"
+
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+
+
+/* Line 189 of yacc.c  */
+#line 101 "util/parse-events-bison.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PE_VALUE = 258,
+     PE_VALUE_SYM = 259,
+     PE_RAW = 260,
+     PE_NAME = 261,
+     PE_MODIFIER_EVENT = 262,
+     PE_MODIFIER_BP = 263,
+     PE_NAME_CACHE_TYPE = 264,
+     PE_NAME_CACHE_OP_RESULT = 265,
+     PE_PREFIX_MEM = 266,
+     PE_PREFIX_RAW = 267,
+     PE_ERROR = 268
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c  */
+#line 42 "util/parse-events.y"
+
+	char *str;
+	unsigned long num;
+
+
+
+/* Line 214 of yacc.c  */
+#line 157 "util/parse-events-bison.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 264 of yacc.c  */
+#line 169 "util/parse-events-bison.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  20
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   27
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  17
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  11
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  22
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  39
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   268
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    14,    15,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    16,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     7,     9,    12,    14,    17,    20,    22,
+      25,    28,    31,    33,    39,    43,    45,    51,    55,    59,
+      63,    65,    67
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      18,     0,    -1,    18,    14,    19,    -1,    19,    -1,    20,
+       7,    -1,    20,    -1,    21,    27,    -1,    22,    27,    -1,
+      23,    -1,    24,    27,    -1,    25,    27,    -1,    26,    27,
+      -1,     4,    -1,     9,    15,    10,    15,    10,    -1,     9,
+      15,    10,    -1,     9,    -1,    11,     3,    16,     8,    27,
+      -1,    11,     3,    27,    -1,     6,    16,     6,    -1,     3,
+      16,     3,    -1,     5,    -1,    16,    -1,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,    49,    49,    49,    52,    57,    59,    60,    61,    62,
+      63,    64,    67,    76,    81,    86,    92,    97,   103,   109,
+     115,   120,   120
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "PE_VALUE", "PE_VALUE_SYM", "PE_RAW",
+  "PE_NAME", "PE_MODIFIER_EVENT", "PE_MODIFIER_BP", "PE_NAME_CACHE_TYPE",
+  "PE_NAME_CACHE_OP_RESULT", "PE_PREFIX_MEM", "PE_PREFIX_RAW", "PE_ERROR",
+  "','", "'-'", "':'", "$accept", "events", "event", "event_def",
+  "event_legacy_symbol", "event_legacy_cache", "event_legacy_mem",
+  "event_legacy_tracepoint", "event_legacy_numeric", "event_legacy_raw",
+  "sep_dc", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,    44,    45,    58
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    17,    18,    18,    19,    19,    20,    20,    20,    20,
+      20,    20,    21,    22,    22,    22,    23,    23,    24,    25,
+      26,    27,    27
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     3,     1,     2,     1,     2,     2,     1,     2,
+       2,     2,     1,     5,     3,     1,     5,     3,     3,     3,
+       1,     1,     0
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,     0,    12,    20,     0,    15,     0,     0,     3,     5,
+      22,    22,     8,    22,    22,    22,     0,     0,     0,    22,
+       1,     0,     4,    21,     6,     7,     9,    10,    11,    19,
+      18,    14,    21,    17,     2,     0,    22,    13,    16
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      24
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -12
+static const yytype_int8 yypact[] =
+{
+       7,   -10,   -12,   -12,    -9,    -6,     2,     1,   -12,    10,
+      -2,    -2,   -12,    -2,    -2,    -2,    16,    14,    11,     6,
+     -12,     7,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
+     -12,     8,    18,   -12,   -12,    17,    -2,   -12,   -12
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -12,   -12,     3,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
+     -11
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+      25,    20,    26,    27,    28,    19,    16,    17,    33,    18,
+       1,     2,     3,     4,    23,    21,     5,    22,     6,    29,
+      30,    31,    32,    35,    34,    38,    36,    37
+};
+
+static const yytype_uint8 yycheck[] =
+{
+      11,     0,    13,    14,    15,     3,    16,    16,    19,    15,
+       3,     4,     5,     6,    16,    14,     9,     7,    11,     3,
+       6,    10,    16,    15,    21,    36,     8,    10
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,     4,     5,     6,     9,    11,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    16,    16,    15,     3,
+       0,    14,     7,    16,    27,    27,    27,    27,    27,     3,
+       6,    10,    16,    27,    19,    15,     8,    10,    27
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  However,
+   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
+   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+   discussed.  */
+
+#define YYFAIL		goto yyerrlab
+#if defined YYFAIL
+  /* This is here to suppress warnings from the GCC cpp's
+     -Wunused-macros.  Normally we don't worry about that warning, but
+     some users do, and we want to make it easy for users to remove
+     YYFAIL uses, which will produce warnings from Bison 2.5.  */
+#endif
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (list, idx, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, list, idx); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list, int *idx)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (list);
+  YYUSE (idx);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list, int *idx)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, list, idx)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, struct list_head *list, int *idx)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, list, idx)
+    YYSTYPE *yyvsp;
+    int yyrule;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       , list, idx);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule, list, idx); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct list_head *list, int *idx)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, list, idx)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    struct list_head *list;
+    int *idx;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (list);
+  YYUSE (idx);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (struct list_head *list, int *idx);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (struct list_head *list, int *idx)
+#else
+int
+yyparse (list, idx)
+    struct list_head *list;
+    int *idx;
+#endif
+#endif
+{
+
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+
+/* Line 1464 of yacc.c  */
+#line 53 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_modifier(list, (yyvsp[(2) - (2)].str)));
+;}
+    break;
+
+  case 12:
+
+/* Line 1464 of yacc.c  */
+#line 68 "util/parse-events.y"
+    {
+	int type = (yyvsp[(1) - (1)].num) >> 16;
+	int config = (yyvsp[(1) - (1)].num) & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+;}
+    break;
+
+  case 13:
+
+/* Line 1464 of yacc.c  */
+#line 77 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
+;}
+    break;
+
+  case 14:
+
+/* Line 1464 of yacc.c  */
+#line 82 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
+;}
+    break;
+
+  case 15:
+
+/* Line 1464 of yacc.c  */
+#line 87 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
+;}
+    break;
+
+  case 16:
+
+/* Line 1464 of yacc.c  */
+#line 93 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
+;}
+    break;
+
+  case 17:
+
+/* Line 1464 of yacc.c  */
+#line 98 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
+;}
+    break;
+
+  case 18:
+
+/* Line 1464 of yacc.c  */
+#line 104 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
+;}
+    break;
+
+  case 19:
+
+/* Line 1464 of yacc.c  */
+#line 110 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num)));
+;}
+    break;
+
+  case 20:
+
+/* Line 1464 of yacc.c  */
+#line 116 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num)));
+;}
+    break;
+
+
+
+/* Line 1464 of yacc.c  */
+#line 1497 "util/parse-events-bison.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (list, idx, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (list, idx, yymsg);
+	  }
+	else
+	  {
+	    yyerror (list, idx, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, list, idx);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, list, idx);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (list, idx, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, list, idx);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, list, idx);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+/* Line 1684 of yacc.c  */
+#line 122 "util/parse-events.y"
+
+
+void parse_events_error(struct list_head *list __used, int *idx __used,
+			char const *msg __used)
+{
+}
+
diff --git a/tools/perf/util/parse-events-bison.h b/tools/perf/util/parse-events-bison.h
new file mode 100644
index 0000000..097a632
--- /dev/null
+++ b/tools/perf/util/parse-events-bison.h
@@ -0,0 +1,79 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PE_VALUE = 258,
+     PE_VALUE_SYM = 259,
+     PE_RAW = 260,
+     PE_NAME = 261,
+     PE_MODIFIER_EVENT = 262,
+     PE_MODIFIER_BP = 263,
+     PE_NAME_CACHE_TYPE = 264,
+     PE_NAME_CACHE_OP_RESULT = 265,
+     PE_PREFIX_MEM = 266,
+     PE_PREFIX_RAW = 267,
+     PE_ERROR = 268
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1685 of yacc.c  */
+#line 42 "util/parse-events.y"
+
+	char *str;
+	unsigned long num;
+
+
+
+/* Line 1685 of yacc.c  */
+#line 71 "util/parse-events-bison.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE parse_events_lval;
+
+
diff --git a/tools/perf/util/parse-events-flex.c b/tools/perf/util/parse-events-flex.c
new file mode 100644
index 0000000..9e77ed6
--- /dev/null
+++ b/tools/perf/util/parse-events-flex.c
@@ -0,0 +1,2225 @@
+
+#line 3 "<stdout>"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer parse_events__create_buffer
+#define yy_delete_buffer parse_events__delete_buffer
+#define yy_flex_debug parse_events__flex_debug
+#define yy_init_buffer parse_events__init_buffer
+#define yy_flush_buffer parse_events__flush_buffer
+#define yy_load_buffer_state parse_events__load_buffer_state
+#define yy_switch_to_buffer parse_events__switch_to_buffer
+#define yyin parse_events_in
+#define yyleng parse_events_leng
+#define yylex parse_events_lex
+#define yylineno parse_events_lineno
+#define yyout parse_events_out
+#define yyrestart parse_events_restart
+#define yytext parse_events_text
+#define yywrap parse_events_wrap
+#define yyalloc parse_events_alloc
+#define yyrealloc parse_events_realloc
+#define yyfree parse_events_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE parse_events_restart(parse_events_in  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int parse_events_leng;
+
+extern FILE *parse_events_in, *parse_events_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up parse_events_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up parse_events_text again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via parse_events_restart()), so that the user can continue scanning by
+	 * just pointing parse_events_in at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when parse_events_text is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int parse_events_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow parse_events_wrap()'s to do buffer switches
+ * instead of setting up a fresh parse_events_in.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void parse_events_restart (FILE *input_file  );
+void parse_events__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE parse_events__create_buffer (FILE *file,int size  );
+void parse_events__delete_buffer (YY_BUFFER_STATE b  );
+void parse_events__flush_buffer (YY_BUFFER_STATE b  );
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void parse_events_pop_buffer_state (void );
+
+static void parse_events_ensure_buffer_stack (void );
+static void parse_events__load_buffer_state (void );
+static void parse_events__init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER parse_events__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE parse_events__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE parse_events__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE parse_events__scan_bytes (yyconst char *bytes,int len  );
+
+void *parse_events_alloc (yy_size_t  );
+void *parse_events_realloc (void *,yy_size_t  );
+void parse_events_free (void *  );
+
+#define yy_new_buffer parse_events__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        parse_events_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        parse_events_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *parse_events_in = (FILE *) 0, *parse_events_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int parse_events_lineno;
+
+int parse_events_lineno = 1;
+
+extern char *parse_events_text;
+#define yytext_ptr parse_events_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up parse_events_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	parse_events_leng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 44
+#define YY_END_OF_BUFFER 45
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[425] =
+    {   0,
+        0,    0,   45,   44,   38,   41,   40,   39,   34,   34,
+       42,   43,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,   38,   36,   38,   38,   38,   38,   38,   36,   37,
+       38,   38,   37,   37,   38,   34,    0,   38,   38,   38,
+       21,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,   38,   15,   38,    0,   38,   38,   38,   36,    0,
+       38,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,   38,   33,   33,   38,   38,   38,   38,   35,   38,
+       38,    0,   38,   38,   38,   24,   38,   38,   38,   38,
+       38,   38,    0,   38,   38,   38,   36,    0,   38,   38,
+
+       38,    0,   19,   20,   38,   38,   38,   38,   38,   38,
+       38,   30,   38,   38,   33,   33,   38,   38,   38,   38,
+       38,   38,   38,    0,    0,   38,   38,   38,   38,    0,
+       38,   38,    0,   38,    0,   22,   38,   38,   36,    0,
+       23,   38,   38,   19,   20,   26,   38,   32,   38,   38,
+       31,   25,   38,   38,   26,   38,   38,   38,   38,   38,
+        0,   38,    0,    0,    0,    0,   38,   38,   38,   38,
+        0,   38,   38,    0,    0,   38,   22,   38,   38,   36,
+       23,    0,   38,   26,   38,   38,   38,   38,    0,   38,
+       38,   38,   27,    0,   27,    0,   38,    0,    0,    0,
+
+        0,   38,   38,   24,    0,    0,   38,    0,    0,    0,
+        1,   38,   12,    0,   38,    0,   38,    0,   31,    0,
+       38,   38,   38,    0,    0,   38,    0,    0,    0,   38,
+       38,    0,   38,    0,    0,    0,   38,    0,    0,    0,
+       38,    0,   38,    0,   38,    0,    0,   38,   38,   38,
+        0,   38,    0,    0,    0,   38,   38,    0,    0,    7,
+        0,    0,    0,    0,    0,    0,    0,   38,    0,   38,
+        0,   38,    0,    0,   28,   38,    0,    0,   38,    0,
+       38,    0,    0,    0,    0,    0,    0,   10,    0,    0,
+       38,    0,   38,    0,   38,    0,    0,   38,   38,    0,
+
+        0,   38,    0,    0,    0,    0,    9,    0,    0,    0,
+        1,    0,    0,    0,   38,    0,   16,    0,    0,   28,
+       38,    0,   11,   38,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,   38,    0,    0,   12,   38,    0,
+        0,    0,    0,    0,    0,    6,    0,    0,    0,    0,
+        0,    4,   14,   13,    0,    0,    0,    0,    0,    0,
+        8,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,   16,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   17,    0,    5,   15,   18,    0,    0,   29,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    7,    3,    0,    0,    0,    2,    0,    0,
+        0,    0,    0,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    3,    4,    1,    5,    6,    7,    8,
+        9,    9,    9,    9,    9,    9,    9,   10,    1,    1,
+       11,    1,    2,    1,   12,   13,   14,   15,   12,   12,
+        2,    2,   16,    2,    2,   17,    2,    2,    2,    2,
+        2,   18,    2,   19,    2,    2,    2,    2,    2,    2,
+        1,    1,    1,    1,    2,    1,   20,   21,   22,   23,
+
+       24,   25,   26,   27,   28,   29,   30,   31,   32,   33,
+       34,   35,    2,   36,   37,   38,   39,   40,   41,   42,
+       43,    2,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[44] =
+    {   0,
+        1,    2,    1,    1,    1,    3,    3,    3,    3,    1,
+        1,    3,    3,    3,    3,    2,    2,    2,    2,    3,
+        3,    3,    3,    3,    3,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2
+    } ;
+
+static yyconst flex_int16_t yy_base[427] =
+    {   0,
+        0,    0,  494,  495,    0,  495,  495,  495,   38,   42,
+      495,  495,  473,  459,   45,  467,   32,   20,   40,   53,
+      458,  469,   34,   62,   58,   58,  454,  452,   64,   98,
+       32,  466,  449,    0,    0,   81,    0,  446,  446,  478,
+        0,  467,  455,  457,  450,   54,  457,  455,  438,  452,
+      440,  433,    0,  449,  432,  452,  429,  428,   97,  428,
+      448,  433,  426,  105,  442,  432,  428,  104,  436,  421,
+      431,  432,  431,   77,  430,   95,  416,  424,    0,  431,
+      412,  103,  425,  424,  421,    0,  413,  441,  417,  405,
+      438,  410,  409,  426,  407,  406,  108,  405,  422,  410,
+
+      395,  111,    0,    0,  409,  397,  420,  393,  394,  390,
+      402,    0,  401,  399,   93,  116,  401,  391,  385,  390,
+      381,  414,  381,   76,   46,  380,  378,  381,  391,  390,
+      387,  386,  120,  385,  387,    0,  387,  368,  119,  384,
+        0,  400,  367,  495,  495,  365,  365,  495,  380,  363,
+      374,    0,  393,  372,  371,  355,  362,  368,  387,  366,
+      370,  349,  349,  366,  365,  347,  359,  345,  349,  353,
+      336,  374,  335,  113,  348,  338,  495,  336,  336,    0,
+      495,  350,  332,    0,  366,  331,  364,  330,  341,  327,
+      333,  339,  325,  339,    0,  343,  337,  338,  335,  334,
+
+      317,  321,  329,  121,  330,  119,  313,  316,  327,  322,
+        0,  319,    0,  303,  323,  319,  315,  317,    0,  321,
+      318,  319,  315,  306,  323,  297,  307,  306,  296,  309,
+      297,  129,  292,  297,  299,  302,  321,  302,  292,  286,
+      287,  298,  281,  298,  283,  296,  276,  287,  275,  308,
+      277,  282,  285,  284,  268,  282,  267,  271,  275,    0,
+      278,  264,  275,  262,  268,  273,  276,  262,  263,  265,
+      253,  258,  251,  258,  264,  259,  264,  263,  250,  261,
+      278,  244,  243,  242,  241,  253,  235,  495,  238,  236,
+      269,  248,  237,  239,  232,  237,  229,  229,  225,  221,
+
+      233,  229,  223,  235,  221,  221,  495,  233,  220,  227,
+      495,  226,  228,  215,  218,  212,    0,  211,  211,    0,
+      223,  224,  495,  241,  216,  223,  206,  217,  203,  215,
+      200,  203,  216,  231,  197,  196,  195,  495,  227,  199,
+      210,  194,  188,  187,  188,  495,  191,  201,  189,  182,
+      138,    0,  495,  495,  129,  196,  202,  185,  186,  194,
+      495,  193,  187,  176,  181,  191,  174,  175,  184,  170,
+      193,  167,  166,  179,  178,  495,  163,  178,  165,  178,
+      177,  192,  158,  166,  156,  155,  154,  160,  156,  165,
+      164,  141,  495,  152,  495,  495,  495,  161,  146,  495,
+
+      163,  146,  148,  147,  155,  156,  143,  139,  152,  141,
+      143,  139,  495,  495,  148,  146,  131,  495,  131,  126,
+      125,   81,   85,  495,  165,   68
+    } ;
+
+static yyconst flex_int16_t yy_def[427] =
+    {   0,
+      424,    1,  424,  424,  425,  424,  424,  424,  424,  424,
+      424,  424,  425,  425,  425,  425,  425,  425,  425,  425,
+      425,  425,  425,  425,  425,  425,  425,  425,  425,  425,
+      425,  425,  425,  425,  425,  424,  426,  425,  425,  425,
+      425,  425,  425,  425,  425,  425,  425,  425,  425,  425,
+      425,  425,  425,  425,  424,  425,  425,  425,  425,  424,
+      425,  425,  425,  425,  425,  425,  425,  425,  425,  425,
+      425,  425,   30,   30,  425,  425,  425,  425,  426,  425,
+      425,  424,  425,  425,  425,  425,  425,  425,  425,  425,
+      425,  425,  424,  425,  425,  425,  425,  424,  425,  425,
+
+      425,  424,  425,  425,  425,  425,  425,  425,  425,  425,
+      425,  425,  425,  425,   30,   30,  425,  425,  425,  425,
+      425,  425,  425,  424,  424,  425,  425,  425,  425,  424,
+      425,  425,  424,  425,  424,  425,  425,  425,  425,  424,
+      425,  425,  425,  424,  424,  425,  425,  424,  425,  425,
+      425,  425,  425,  425,   30,  425,  425,  425,  425,  425,
+      424,  425,  424,  424,  424,  424,  425,  425,  425,  425,
+      424,  425,  425,  424,  424,  425,  424,  425,  425,  425,
+      424,  424,  425,  425,  425,  425,  425,  425,  424,  425,
+      425,  425,  425,  424,  425,  424,  425,  424,  424,  424,
+
+      424,  425,  425,  425,  424,  424,  425,  424,  424,  424,
+      425,  425,  425,  424,  425,  424,  425,  424,  425,  424,
+      425,  425,  425,  424,  424,  425,  424,  424,  424,  425,
+      425,  424,  425,  424,  424,  424,  425,  424,  424,  424,
+      425,  424,  425,  424,  425,  424,  424,  425,  425,  425,
+      424,  425,  424,  424,  424,  425,  425,  424,  424,  425,
+      424,  424,  424,  424,  424,  424,  424,  425,  424,  425,
+      424,  425,  424,  424,  425,  425,  424,  424,  425,  424,
+      425,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      425,  424,  425,  424,  425,  424,  424,  425,  425,  424,
+
+      424,  425,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  425,  424,  425,  424,  424,  425,
+      425,  424,  424,  425,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  425,  424,  424,  424,  425,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  425,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,    0,  424,  424
+    } ;
+
+static yyconst flex_int16_t yy_nxt[539] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   10,   10,   11,
+       12,    5,    5,    5,   13,   14,   15,   16,    5,   17,
+       18,   19,   20,   21,   22,    5,   23,   24,    5,   23,
+       25,   26,   27,   28,   29,   30,   31,   32,   23,    5,
+       33,   34,    5,   36,   36,   36,   36,   36,   36,   36,
+       36,   40,   41,   44,   46,   47,   55,   48,   49,   50,
+       59,   42,   45,   59,   64,   60,   75,  165,   59,   76,
+       79,   56,   59,   51,   52,   86,   53,   66,  166,   37,
+       61,   67,   54,   71,   62,   68,   36,   36,   36,   36,
+       59,   65,   86,   59,   63,  163,  115,  164,   59,   72,
+
+       73,  116,   59,   73,   73,   73,   73,  418,  102,   73,
+       73,   73,   73,  423,  118,  155,   73,   73,   73,   73,
+       73,   74,   73,   97,  232,  124,   97,  103,  119,  108,
+      125,   97,  104,  144,  139,   97,  109,  139,  145,   73,
+      110,  174,  139,  208,  233,  180,  139,  414,  180,  422,
+      235,  175,  112,  180,  236,  209,  258,  180,  366,  368,
+      259,  401,  367,  421,  369,  402,   35,   35,  420,  419,
+      418,  417,  416,  415,  414,  413,  412,  411,  410,  409,
+      408,  407,  406,  405,  404,  403,  400,  400,  399,  398,
+      397,  396,  395,  394,  393,  392,  391,  390,  389,  388,
+
+      387,  386,  385,  384,  383,  181,  382,  381,  380,  379,
+      378,  377,  376,  375,  374,  373,  372,  145,  371,  370,
+      365,  364,  363,  362,  361,  360,  359,  358,  357,  356,
+      355,  354,  353,  352,  351,  350,  349,  348,  347,  346,
+      345,  344,  343,  342,  341,  340,  339,  338,  337,  336,
+      335,  334,  333,  332,  331,  330,  329,  328,  327,  326,
+      325,  324,  323,  322,  321,  320,  319,  318,  317,  316,
+      315,  314,  313,  312,  311,  310,  309,  308,  307,  306,
+      305,  304,  303,  302,  301,  300,  299,  298,  297,  296,
+      295,  294,  293,  292,  291,  290,  289,  288,  287,  286,
+
+      285,  284,  283,  282,  281,  112,  280,  145,  144,  279,
+      278,  277,  276,  275,  274,  273,  272,  271,  270,  269,
+      268,  267,  266,  265,  264,  263,  262,  261,  260,  257,
+      256,  255,  254,  253,  252,  177,  251,  250,  249,  248,
+      247,  246,  245,  244,  243,  242,  241,  240,  239,  238,
+      237,  234,  231,  230,  229,  228,  227,  144,  226,  225,
+      224,  195,  223,  222,  221,  220,  219,  218,  217,  216,
+      215,  214,  213,  212,  211,  210,  207,  206,  205,  204,
+      203,  112,  202,  201,  200,  199,  198,  197,  196,  195,
+      194,  193,  192,  191,   73,  190,  189,  188,  187,  186,
+
+      185,  184,  183,  182,  181,  179,  178,  177,  176,  173,
+      172,  171,  170,  169,  168,  167,  162,  161,  160,  159,
+      158,  157,  156,  154,  153,  152,  151,  150,  149,  148,
+      147,  146,  143,  142,  141,  140,  138,  137,  136,  135,
+      134,  133,  132,  131,  130,  129,  128,  127,  126,  123,
+      122,  121,  120,  117,   73,  114,  113,  112,  111,  107,
+      106,  105,  101,  100,   99,   98,   96,   95,   94,   93,
+       92,   91,   90,   89,   88,   86,   87,   85,   84,   83,
+       41,   82,   81,   80,   78,   77,   70,   69,   58,   57,
+       43,   39,   38,  424,    3,  424,  424,  424,  424,  424,
+
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424
+    } ;
+
+static yyconst flex_int16_t yy_chk[539] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    9,    9,    9,    9,   10,   10,   10,
+       10,   15,   15,   17,   18,   18,   20,   18,   18,   19,
+       23,   15,   17,   23,   25,   24,   31,  125,   23,   31,
+      426,   20,   23,   19,   19,   46,   19,   26,  125,    9,
+       24,   26,   19,   29,   24,   26,   36,   36,   36,   36,
+       29,   25,   46,   29,   24,  124,   74,  124,   29,   29,
+
+       74,   74,   29,   30,   30,   30,   30,  423,   64,   30,
+       30,   30,   30,  422,   76,  115,  115,   30,   30,   30,
+       30,   30,   30,   59,  204,   82,   59,   64,   76,   68,
+       82,   59,   64,  102,   97,   59,   68,   97,  102,  116,
+       68,  133,   97,  174,  204,  139,   97,  421,  139,  420,
+      206,  133,  116,  139,  206,  174,  232,  139,  351,  355,
+      232,  392,  351,  419,  355,  392,  425,  425,  417,  416,
+      415,  412,  411,  410,  409,  408,  407,  406,  405,  404,
+      403,  402,  401,  399,  398,  394,  391,  390,  389,  388,
+      387,  386,  385,  384,  383,  382,  381,  380,  379,  378,
+
+      377,  375,  374,  373,  372,  371,  370,  369,  368,  367,
+      366,  365,  364,  363,  362,  360,  359,  358,  357,  356,
+      350,  349,  348,  347,  345,  344,  343,  342,  341,  340,
+      339,  337,  336,  335,  334,  333,  332,  331,  330,  329,
+      328,  327,  326,  325,  324,  322,  321,  319,  318,  316,
+      315,  314,  313,  312,  310,  309,  308,  306,  305,  304,
+      303,  302,  301,  300,  299,  298,  297,  296,  295,  294,
+      293,  292,  291,  290,  289,  287,  286,  285,  284,  283,
+      282,  281,  280,  279,  278,  277,  276,  275,  274,  273,
+      272,  271,  270,  269,  268,  267,  266,  265,  264,  263,
+
+      262,  261,  259,  258,  257,  256,  255,  254,  253,  252,
+      251,  250,  249,  248,  247,  246,  245,  244,  243,  242,
+      241,  240,  239,  238,  237,  236,  235,  234,  233,  231,
+      230,  229,  228,  227,  226,  225,  224,  223,  222,  221,
+      220,  218,  217,  216,  215,  214,  212,  210,  209,  208,
+      207,  205,  203,  202,  201,  200,  199,  198,  197,  196,
+      194,  193,  192,  191,  190,  189,  188,  187,  186,  185,
+      183,  182,  179,  178,  176,  175,  173,  172,  171,  170,
+      169,  168,  167,  166,  165,  164,  163,  162,  161,  160,
+      159,  158,  157,  156,  155,  154,  153,  151,  150,  149,
+
+      147,  146,  143,  142,  140,  138,  137,  135,  134,  132,
+      131,  130,  129,  128,  127,  126,  123,  122,  121,  120,
+      119,  118,  117,  114,  113,  111,  110,  109,  108,  107,
+      106,  105,  101,  100,   99,   98,   96,   95,   94,   93,
+       92,   91,   90,   89,   88,   87,   85,   84,   83,   81,
+       80,   78,   77,   75,   73,   72,   71,   70,   69,   67,
+       66,   65,   63,   62,   61,   60,   58,   57,   56,   55,
+       54,   52,   51,   50,   49,   48,   47,   45,   44,   43,
+       42,   40,   39,   38,   33,   32,   28,   27,   22,   21,
+       16,   14,   13,    3,  424,  424,  424,  424,  424,  424,
+
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int parse_events__flex_debug;
+int parse_events__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *parse_events_text;
+#line 1 "util/parse-events.l"
+#line 5 "util/parse-events.l"
+#include <errno.h>
+#include "../perf.h"
+#include "parse-events-bison.h"
+
+static int __value(char *str, int base, int token)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(str, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.num = num;
+	return token;
+}
+
+static int value(int base)
+{
+	return __value(parse_events_text, base, PE_VALUE);
+}
+
+static int raw(void)
+{
+	return __value(parse_events_text + 1, 16, PE_RAW);
+}
+
+static int str(int token)
+{
+	parse_events_lval.str = strdup(parse_events_text);
+	return token;
+}
+
+static int sym(int type, int config)
+{
+	parse_events_lval.num = (type << 16) + config;
+	return PE_VALUE_SYM;
+}
+
+#line 766 "<stdout>"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int parse_events_lex_destroy (void );
+
+int parse_events_get_debug (void );
+
+void parse_events_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE parse_events_get_extra (void );
+
+void parse_events_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *parse_events_get_in (void );
+
+void parse_events_set_in  (FILE * in_str  );
+
+FILE *parse_events_get_out (void );
+
+void parse_events_set_out  (FILE * out_str  );
+
+int parse_events_get_leng (void );
+
+char *parse_events_get_text (void );
+
+int parse_events_get_lineno (void );
+
+void parse_events_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int parse_events_wrap (void );
+#else
+extern int parse_events_wrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( parse_events_text, parse_events_leng, 1, parse_events_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		unsigned n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( parse_events_in )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( parse_events_in ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, parse_events_in))==0 && ferror(parse_events_in)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(parse_events_in); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int parse_events_lex (void);
+
+#define YY_DECL int parse_events_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after parse_events_text and parse_events_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 53 "util/parse-events.l"
+
+#line 950 "<stdout>"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! parse_events_in )
+			parse_events_in = stdin;
+
+		if ( ! parse_events_out )
+			parse_events_out = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			parse_events_ensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				parse_events__create_buffer(parse_events_in,YY_BUF_SIZE );
+		}
+
+		parse_events__load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of parse_events_text. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 425 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 495 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 54 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 55 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 56 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 57 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 58 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 59 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 60 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 61 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 62 "util/parse-events.l"
+{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 63 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 64 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 65 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 66 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 67 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 68 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 69 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 70 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 71 "util/parse-events.l"
+{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+	YY_BREAK
+case 19:
+#line 74 "util/parse-events.l"
+case 20:
+#line 75 "util/parse-events.l"
+case 21:
+#line 76 "util/parse-events.l"
+case 22:
+#line 77 "util/parse-events.l"
+case 23:
+#line 78 "util/parse-events.l"
+case 24:
+#line 79 "util/parse-events.l"
+case 25:
+YY_RULE_SETUP
+#line 79 "util/parse-events.l"
+{ return str(PE_NAME_CACHE_TYPE); }
+	YY_BREAK
+case 26:
+#line 82 "util/parse-events.l"
+case 27:
+#line 83 "util/parse-events.l"
+case 28:
+#line 84 "util/parse-events.l"
+case 29:
+#line 85 "util/parse-events.l"
+case 30:
+#line 86 "util/parse-events.l"
+case 31:
+YY_RULE_SETUP
+#line 86 "util/parse-events.l"
+{ return str(PE_NAME_CACHE_OP_RESULT); }
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 88 "util/parse-events.l"
+{ return PE_PREFIX_MEM; }
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 89 "util/parse-events.l"
+{ return raw(); }
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 90 "util/parse-events.l"
+{ return value(10); }
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 91 "util/parse-events.l"
+{ return value(16); }
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 93 "util/parse-events.l"
+{ return str(PE_MODIFIER_EVENT); }
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 94 "util/parse-events.l"
+{ return str(PE_MODIFIER_BP); }
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 95 "util/parse-events.l"
+{ return str(PE_NAME); }
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 96 "util/parse-events.l"
+{ return '/'; }
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 97 "util/parse-events.l"
+{ return '-'; }
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 98 "util/parse-events.l"
+{ return ','; }
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 99 "util/parse-events.l"
+{ return ':'; }
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 100 "util/parse-events.l"
+{ return '='; }
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 102 "util/parse-events.l"
+ECHO;
+	YY_BREAK
+#line 1220 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed parse_events_in at a new source and called
+			 * parse_events_lex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = parse_events_in;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( parse_events_wrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * parse_events_text, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of parse_events_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					parse_events_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			parse_events_restart(parse_events_in  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) parse_events_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 425 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    	register char *yy_cp = (yy_c_buf_p);
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 425 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 424);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up parse_events_text */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					parse_events_restart(parse_events_in );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( parse_events_wrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve parse_events_text */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void parse_events_restart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        parse_events_ensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            parse_events__create_buffer(parse_events_in,YY_BUF_SIZE );
+	}
+
+	parse_events__init_buffer(YY_CURRENT_BUFFER,input_file );
+	parse_events__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void parse_events__switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		parse_events_pop_buffer_state();
+	 *		parse_events_push_buffer_state(new_buffer);
+     */
+	parse_events_ensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	parse_events__load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (parse_events_wrap()) processing, but the only time this flag
+	 * is looked at is after parse_events_wrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void parse_events__load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	parse_events_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE parse_events__create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) parse_events_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) parse_events_alloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	parse_events__init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with parse_events__create_buffer()
+ * 
+ */
+    void parse_events__delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		parse_events_free((void *) b->yy_ch_buf  );
+
+	parse_events_free((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a parse_events_restart() or at EOF.
+ */
+    static void parse_events__init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	parse_events__flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then parse_events__init_buffer was _probably_
+     * called from parse_events_restart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void parse_events__flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		parse_events__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	parse_events_ensure_buffer_stack();
+
+	/* This block is copied from parse_events__switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from parse_events__switch_to_buffer. */
+	parse_events__load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void parse_events_pop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	parse_events__delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		parse_events__load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void parse_events_ensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)parse_events_alloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in parse_events_ensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)parse_events_realloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in parse_events_ensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE parse_events__scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) parse_events_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	parse_events__switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to parse_events_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       parse_events__scan_bytes() instead.
+ */
+YY_BUFFER_STATE parse_events__scan_string (yyconst char * yystr )
+{
+    
+	return parse_events__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to parse_events_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE parse_events__scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) parse_events_alloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in parse_events__scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = parse_events__scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in parse_events__scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up parse_events_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		parse_events_text[parse_events_leng] = (yy_hold_char); \
+		(yy_c_buf_p) = parse_events_text + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		parse_events_leng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int parse_events_get_lineno  (void)
+{
+        
+    return parse_events_lineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *parse_events_get_in  (void)
+{
+        return parse_events_in;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *parse_events_get_out  (void)
+{
+        return parse_events_out;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int parse_events_get_leng  (void)
+{
+        return parse_events_leng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *parse_events_get_text  (void)
+{
+        return parse_events_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void parse_events_set_lineno (int  line_number )
+{
+    
+    parse_events_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see parse_events__switch_to_buffer
+ */
+void parse_events_set_in (FILE *  in_str )
+{
+        parse_events_in = in_str ;
+}
+
+void parse_events_set_out (FILE *  out_str )
+{
+        parse_events_out = out_str ;
+}
+
+int parse_events_get_debug  (void)
+{
+        return parse_events__flex_debug;
+}
+
+void parse_events_set_debug (int  bdebug )
+{
+        parse_events__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from parse_events_lex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    parse_events_in = stdin;
+    parse_events_out = stdout;
+#else
+    parse_events_in = (FILE *) 0;
+    parse_events_out = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * parse_events_lex_init()
+     */
+    return 0;
+}
+
+/* parse_events_lex_destroy is for both reentrant and non-reentrant scanners. */
+int parse_events_lex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		parse_events__delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		parse_events_pop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	parse_events_free((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * parse_events_lex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *parse_events_alloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *parse_events_realloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void parse_events_free (void * ptr )
+{
+	free( (char *) ptr );	/* see parse_events_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 102 "util/parse-events.l"
+
+
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
+
diff --git a/tools/perf/util/parse-events-flex.h b/tools/perf/util/parse-events-flex.h
new file mode 100644
index 0000000..b927f9a
--- /dev/null
+++ b/tools/perf/util/parse-events-flex.h
@@ -0,0 +1,316 @@
+#ifndef parse_events_HEADER_H
+#define parse_events_HEADER_H 1
+#define parse_events_IN_HEADER 1
+
+#line 6 "util/parse-events-flex.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int parse_events_leng;
+
+extern FILE *parse_events_in, *parse_events_out;
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void parse_events_restart (FILE *input_file  );
+void parse_events__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE parse_events__create_buffer (FILE *file,int size  );
+void parse_events__delete_buffer (YY_BUFFER_STATE b  );
+void parse_events__flush_buffer (YY_BUFFER_STATE b  );
+void parse_events_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void parse_events_pop_buffer_state (void );
+
+YY_BUFFER_STATE parse_events__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE parse_events__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE parse_events__scan_bytes (yyconst char *bytes,int len  );
+
+void *parse_events_alloc (yy_size_t  );
+void *parse_events_realloc (void *,yy_size_t  );
+void parse_events_free (void *  );
+
+/* Begin user sect3 */
+
+extern int parse_events_lineno;
+
+extern char *parse_events_text;
+#define yytext_ptr parse_events_text
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int parse_events_lex_destroy (void );
+
+int parse_events_get_debug (void );
+
+void parse_events_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE parse_events_get_extra (void );
+
+void parse_events_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *parse_events_get_in (void );
+
+void parse_events_set_in  (FILE * in_str  );
+
+FILE *parse_events_get_out (void );
+
+void parse_events_set_out  (FILE * out_str  );
+
+int parse_events_get_leng (void );
+
+char *parse_events_get_text (void );
+
+int parse_events_get_lineno (void );
+
+void parse_events_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int parse_events_wrap (void );
+#else
+extern int parse_events_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int parse_events_lex (void);
+
+#define YY_DECL int parse_events_lex (void)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 102 "util/parse-events.l"
+
+
+#line 315 "util/parse-events-flex.h"
+#undef parse_events_IN_HEADER
+#endif /* parse_events_HEADER_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b029296..6e50b91 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,9 @@
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
+#include "parse-events-flex.h"
+
+#define MAX_NAME_LEN 100
 
 struct event_symbol {
 	u8		type;
@@ -19,11 +22,7 @@ struct event_symbol {
 	const char	*alias;
 };
 
-enum event_result {
-	EVT_FAILED,
-	EVT_HANDLED,
-	EVT_HANDLED_ALL
-};
+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
@@ -354,7 +353,24 @@ const char *__event_name(int type, u64 config)
 	return "unknown";
 }
 
-static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
+static int add_event(struct list_head *list, int *idx,
+		     struct perf_event_attr *attr, char *name)
+{
+	struct perf_evsel *evsel;
+
+	event_attr_init(attr);
+
+	evsel = perf_evsel__new(attr, (*idx)++);
+	if (!evsel)
+		return -ENOMEM;
+
+	list_add_tail(&evsel->node, list);
+
+	evsel->name = strdup(name);
+	return 0;
+}
+
+static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
 {
 	int i, j;
 	int n, longest = -1;
@@ -362,58 +378,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
 	for (i = 0; i < size; i++) {
 		for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
 			n = strlen(names[i][j]);
-			if (n > longest && !strncasecmp(*str, names[i][j], n))
+			if (n > longest && !strncasecmp(str, names[i][j], n))
 				longest = n;
 		}
-		if (longest > 0) {
-			*str += longest;
+		if (longest > 0)
 			return i;
-		}
 	}
 
 	return -1;
 }
 
-static enum event_result
-parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
+int parse_events_add_cache(struct list_head *list, int *idx,
+			   char *type, char *op_result1, char *op_result2)
 {
-	const char *s = *str;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	int cache_type = -1, cache_op = -1, cache_result = -1;
+	char *op_result[2] = { op_result1, op_result2 };
+	int i, n;
 
-	cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
 	/*
 	 * No fallback - if we cannot get a clear cache type
 	 * then bail out:
 	 */
+	cache_type = parse_aliases(type, hw_cache,
+				   PERF_COUNT_HW_CACHE_MAX);
 	if (cache_type == -1)
-		return EVT_FAILED;
+		return -EINVAL;
+
+	n = snprintf(name, MAX_NAME_LEN, "%s", type);
 
-	while ((cache_op == -1 || cache_result == -1) && *s == '-') {
-		++s;
+	for (i = 0; (i < 2) && (op_result[i]); i++) {
+		char *str = op_result[i];
+
+		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
 		if (cache_op == -1) {
-			cache_op = parse_aliases(&s, hw_cache_op,
-						PERF_COUNT_HW_CACHE_OP_MAX);
+			cache_op = parse_aliases(str, hw_cache_op,
+						 PERF_COUNT_HW_CACHE_OP_MAX);
 			if (cache_op >= 0) {
 				if (!is_cache_op_valid(cache_type, cache_op))
-					return EVT_FAILED;
+					return -EINVAL;
 				continue;
 			}
 		}
 
 		if (cache_result == -1) {
-			cache_result = parse_aliases(&s, hw_cache_result,
+			cache_result = parse_aliases(str, hw_cache_result,
 						PERF_COUNT_HW_CACHE_RESULT_MAX);
 			if (cache_result >= 0)
 				continue;
 		}
-
-		/*
-		 * Can't parse this as a cache op or result, so back up
-		 * to the '-'.
-		 */
-		--s;
-		break;
 	}
 
 	/*
@@ -428,20 +443,17 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
 	if (cache_result == -1)
 		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
 
-	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
-	attr->type = PERF_TYPE_HW_CACHE;
-
-	*str = s;
-	return EVT_HANDLED;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
+	attr.type = PERF_TYPE_HW_CACHE;
+	return add_event(list, idx, &attr, name);
 }
 
-static enum event_result
-parse_single_tracepoint_event(char *sys_name,
-			      const char *evt_name,
-			      unsigned int evt_length,
-			      struct perf_event_attr *attr,
-			      const char **strp)
+static int add_tracepoint(struct list_head *list, int *idx,
+			  char *sys_name, char *evt_name)
 {
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	char evt_path[MAXPATHLEN];
 	char id_buf[4];
 	u64 id;
@@ -452,130 +464,80 @@ parse_single_tracepoint_event(char *sys_name,
 
 	fd = open(evt_path, O_RDONLY);
 	if (fd < 0)
-		return EVT_FAILED;
+		return -1;
 
 	if (read(fd, id_buf, sizeof(id_buf)) < 0) {
 		close(fd);
-		return EVT_FAILED;
+		return -1;
 	}
 
 	close(fd);
 	id = atoll(id_buf);
-	attr->config = id;
-	attr->type = PERF_TYPE_TRACEPOINT;
-	*strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
 
-	attr->sample_type |= PERF_SAMPLE_RAW;
-	attr->sample_type |= PERF_SAMPLE_TIME;
-	attr->sample_type |= PERF_SAMPLE_CPU;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = id;
+	attr.type = PERF_TYPE_TRACEPOINT;
+	attr.sample_type |= PERF_SAMPLE_RAW;
+	attr.sample_type |= PERF_SAMPLE_TIME;
+	attr.sample_type |= PERF_SAMPLE_CPU;
+	attr.sample_period = 1;
 
-	attr->sample_period = 1;
-
-
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
+	return add_event(list, idx, &attr, name);
 }
 
-/* sys + ':' + event + ':' + flags*/
-#define MAX_EVOPT_LEN	(MAX_EVENT_LENGTH * 2 + 2 + 128)
-static enum event_result
-parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
-				const char *evt_exp, char *flags)
+static int add_tracepoint_multi(struct list_head *list, int *idx,
+				char *sys_name, char *evt_name)
 {
 	char evt_path[MAXPATHLEN];
 	struct dirent *evt_ent;
 	DIR *evt_dir;
+	int ret = 0;
 
 	snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
 	evt_dir = opendir(evt_path);
-
 	if (!evt_dir) {
 		perror("Can't open event dir");
-		return EVT_FAILED;
+		return -1;
 	}
 
-	while ((evt_ent = readdir(evt_dir))) {
-		char event_opt[MAX_EVOPT_LEN + 1];
-		int len;
-
+	while (!ret && (evt_ent = readdir(evt_dir))) {
 		if (!strcmp(evt_ent->d_name, ".")
 		    || !strcmp(evt_ent->d_name, "..")
 		    || !strcmp(evt_ent->d_name, "enable")
 		    || !strcmp(evt_ent->d_name, "filter"))
 			continue;
 
-		if (!strglobmatch(evt_ent->d_name, evt_exp))
+		if (!strglobmatch(evt_ent->d_name, evt_name))
 			continue;
 
-		len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
-			       evt_ent->d_name, flags ? ":" : "",
-			       flags ?: "");
-		if (len < 0)
-			return EVT_FAILED;
-
-		if (parse_events(evlist, event_opt, 0))
-			return EVT_FAILED;
+		ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
 	}
 
-	return EVT_HANDLED_ALL;
+	return ret;
 }
 
-static enum event_result
-parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
-		       struct perf_event_attr *attr)
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
+				char *sys, char *event)
 {
-	const char *evt_name;
-	char *flags = NULL, *comma_loc;
-	char sys_name[MAX_EVENT_LENGTH];
-	unsigned int sys_length, evt_length;
-
-	if (debugfs_valid_mountpoint(tracing_events_path))
-		return 0;
+	int ret;
 
-	evt_name = strchr(*strp, ':');
-	if (!evt_name)
-		return EVT_FAILED;
+	ret = debugfs_valid_mountpoint(tracing_events_path);
+	if (ret)
+		return ret;
 
-	sys_length = evt_name - *strp;
-	if (sys_length >= MAX_EVENT_LENGTH)
-		return 0;
-
-	strncpy(sys_name, *strp, sys_length);
-	sys_name[sys_length] = '\0';
-	evt_name = evt_name + 1;
-
-	comma_loc = strchr(evt_name, ',');
-	if (comma_loc) {
-		/* take the event name up to the comma */
-		evt_name = strndup(evt_name, comma_loc - evt_name);
-	}
-	flags = strchr(evt_name, ':');
-	if (flags) {
-		/* split it out: */
-		evt_name = strndup(evt_name, flags - evt_name);
-		flags++;
-	}
-
-	evt_length = strlen(evt_name);
-	if (evt_length >= MAX_EVENT_LENGTH)
-		return EVT_FAILED;
-	if (strpbrk(evt_name, "*?")) {
-		*strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
-		return parse_multiple_tracepoint_event(evlist, sys_name,
-						       evt_name, flags);
-	} else {
-		return parse_single_tracepoint_event(sys_name, evt_name,
-						     evt_length, attr, strp);
-	}
+	return strpbrk(event, "*?") ?
+	       add_tracepoint_multi(list, idx, sys, event) :
+	       add_tracepoint(list, idx, sys, event);
 }
 
-static enum event_result
-parse_breakpoint_type(const char *type, const char **strp,
-		      struct perf_event_attr *attr)
+static int
+parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
 	int i;
 
 	for (i = 0; i < 3; i++) {
-		if (!type[i])
+		if (!type || !type[i])
 			break;
 
 		switch (type[i]) {
@@ -589,164 +551,65 @@ parse_breakpoint_type(const char *type, const char **strp,
 			attr->bp_type |= HW_BREAKPOINT_X;
 			break;
 		default:
-			return EVT_FAILED;
+			return -EINVAL;
 		}
 	}
+
 	if (!attr->bp_type) /* Default */
 		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
 
-	*strp = type + i;
-
-	return EVT_HANDLED;
+	return 0;
 }
 
-static enum event_result
-parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
+				void *ptr, char *type)
 {
-	const char *target;
-	const char *type;
-	char *endaddr;
-	u64 addr;
-	enum event_result err;
-
-	target = strchr(*strp, ':');
-	if (!target)
-		return EVT_FAILED;
-
-	if (strncmp(*strp, "mem", target - *strp) != 0)
-		return EVT_FAILED;
-
-	target++;
-
-	addr = strtoull(target, &endaddr, 0);
-	if (target == endaddr)
-		return EVT_FAILED;
-
-	attr->bp_addr = addr;
-	*strp = endaddr;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 
-	type = strchr(target, ':');
+	memset(&attr, 0, sizeof(attr));
+	attr.bp_addr = (u64) ptr;
 
-	/* If no type is defined, just rw as default */
-	if (!type) {
-		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
-	} else {
-		err = parse_breakpoint_type(++type, strp, attr);
-		if (err == EVT_FAILED)
-			return EVT_FAILED;
-	}
+	if (parse_breakpoint_type(type, &attr))
+		return -EINVAL;
 
 	/*
 	 * We should find a nice way to override the access length
 	 * Provide some defaults for now
 	 */
-	if (attr->bp_type == HW_BREAKPOINT_X)
-		attr->bp_len = sizeof(long);
+	if (attr.bp_type == HW_BREAKPOINT_X)
+		attr.bp_len = sizeof(long);
 	else
-		attr->bp_len = HW_BREAKPOINT_LEN_4;
-
-	attr->type = PERF_TYPE_BREAKPOINT;
-
-	return EVT_HANDLED;
-}
-
-static int check_events(const char *str, unsigned int i)
-{
-	int n;
-
-	n = strlen(event_symbols[i].symbol);
-	if (!strncasecmp(str, event_symbols[i].symbol, n))
-		return n;
+		attr.bp_len = HW_BREAKPOINT_LEN_4;
 
-	n = strlen(event_symbols[i].alias);
-	if (n) {
-		if (!strncasecmp(str, event_symbols[i].alias, n))
-			return n;
-	}
+	attr.type = PERF_TYPE_BREAKPOINT;
 
-	return 0;
+	snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
+	return add_event(list, idx, &attr, name);
 }
 
-static enum event_result
-parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
+int
+parse_events_add_numeric(struct list_head *list, int *idx,
+			 unsigned long type, unsigned long config)
 {
-	const char *str = *strp;
-	unsigned int i;
-	int n;
-
-	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-		n = check_events(str, i);
-		if (n > 0) {
-			attr->type = event_symbols[i].type;
-			attr->config = event_symbols[i].config;
-			*strp = str + n;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
-}
+	struct perf_event_attr attr;
 
-static enum event_result
-parse_raw_event(const char **strp, struct perf_event_attr *attr)
-{
-	const char *str = *strp;
-	u64 config;
-	int n;
-
-	if (*str != 'r')
-		return EVT_FAILED;
-	n = hex2u64(str + 1, &config);
-	if (n > 0) {
-		const char *end = str + n + 1;
-		if (*end != '\0' && *end != ',' && *end != ':')
-			return EVT_FAILED;
-
-		*strp = end;
-		attr->type = PERF_TYPE_RAW;
-		attr->config = config;
-		return EVT_HANDLED;
-	}
-	return EVT_FAILED;
+	memset(&attr, 0, sizeof(attr));
+	attr.type = type;
+	attr.config = config;
+	return add_event(list, idx, &attr,
+			 (char *) __event_name(type, config));
 }
 
-static enum event_result
-parse_numeric_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_modifier(struct list_head *list, char *str)
 {
-	const char *str = *strp;
-	char *endp;
-	unsigned long type;
-	u64 config;
-
-	type = strtoul(str, &endp, 0);
-	if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
-		str = endp + 1;
-		config = strtoul(str, &endp, 0);
-		if (endp > str) {
-			attr->type = type;
-			attr->config = config;
-			*strp = endp;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
-}
-
-static int
-parse_event_modifier(const char **strp, struct perf_event_attr *attr)
-{
-	const char *str = *strp;
+	struct perf_evsel *evsel;
 	int exclude = 0, exclude_GH = 0;
 	int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
 
-	if (!*str)
+	if (str == NULL)
 		return 0;
 
-	if (*str == ',')
-		return 0;
-
-	if (*str++ != ':')
-		return -1;
-
 	while (*str) {
 		if (*str == 'u') {
 			if (!exclude)
@@ -775,111 +638,60 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
 
 		++str;
 	}
-	if (str < *strp + 2)
-		return -1;
 
-	*strp = str;
+	/*
+	 * precise ip:
+	 *
+	 *  0 - SAMPLE_IP can have arbitrary skid
+	 *  1 - SAMPLE_IP must have constant skid
+	 *  2 - SAMPLE_IP requested to have 0 skid
+	 *  3 - SAMPLE_IP must have 0 skid
+	 *
+	 *  See also PERF_RECORD_MISC_EXACT_IP
+	 */
+	if (precise > 3)
+		return -EINVAL;
 
-	attr->exclude_user   = eu;
-	attr->exclude_kernel = ek;
-	attr->exclude_hv     = eh;
-	attr->precise_ip     = precise;
-	attr->exclude_host   = eH;
-	attr->exclude_guest  = eG;
+	list_for_each_entry(evsel, list, node) {
+		evsel->attr.exclude_user   = eu;
+		evsel->attr.exclude_kernel = ek;
+		evsel->attr.exclude_hv     = eh;
+		evsel->attr.precise_ip     = precise;
+		evsel->attr.exclude_host   = eH;
+		evsel->attr.exclude_guest  = eG;
+	}
 
 	return 0;
 }
 
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static enum event_result
-parse_event_symbols(struct perf_evlist *evlist, const char **str,
-		    struct perf_event_attr *attr)
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
-	enum event_result ret;
-
-	ret = parse_tracepoint_event(evlist, str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	struct perf_evsel *evsel, *h;
+	LIST_HEAD(list);
+	YY_BUFFER_STATE buffer;
+	int ret, idx = evlist->nr_entries;
 
-	ret = parse_raw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	buffer = parse_events__scan_string(str);
 
-	ret = parse_numeric_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	ret = parse_events_parse(&list, &idx);
 
-	ret = parse_symbolic_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	parse_events__flush_buffer(buffer);
+	parse_events__delete_buffer(buffer);
 
-	ret = parse_generic_hw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	if (!ret) {
+		int entries = idx - evlist->nr_entries;
+		perf_evlist__splice_list_tail(evlist, &list, entries);
+		return 0;
+	}
 
-	ret = parse_breakpoint_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	list_for_each_entry_safe(evsel, h, &list, node)
+		perf_evsel__delete(evsel);
 
-	fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
+	fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
 	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
-	return EVT_FAILED;
-
-modifier:
-	if (parse_event_modifier(str, attr) < 0) {
-		fprintf(stderr, "invalid event modifier: '%s'\n", *str);
-		fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
-
-		return EVT_FAILED;
-	}
-
 	return ret;
 }
 
-int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
-{
-	struct perf_event_attr attr;
-	enum event_result ret;
-	const char *ostr;
-
-	for (;;) {
-		ostr = str;
-		memset(&attr, 0, sizeof(attr));
-		event_attr_init(&attr);
-		ret = parse_event_symbols(evlist, &str, &attr);
-		if (ret == EVT_FAILED)
-			return -1;
-
-		if (!(*str == 0 || *str == ',' || isspace(*str)))
-			return -1;
-
-		if (ret != EVT_HANDLED_ALL) {
-			struct perf_evsel *evsel;
-			evsel = perf_evsel__new(&attr, evlist->nr_entries);
-			if (evsel == NULL)
-				return -1;
-			perf_evlist__add(evlist, evsel);
-
-			evsel->name = calloc(str - ostr + 1, 1);
-			if (!evsel->name)
-				return -1;
-			strncpy(evsel->name, ostr, str - ostr);
-		}
-
-		if (*str == 0)
-			break;
-		if (*str == ',')
-			++str;
-		while (isspace(*str))
-			++str;
-	}
-
-	return 0;
-}
-
 int parse_events_option(const struct option *opt, const char *str,
 			int unset __used)
 {
@@ -1052,8 +864,6 @@ int print_hwcache_events(const char *event_glob)
 	return printed;
 }
 
-#define MAX_NAME_LEN 100
-
 /*
  * Print the help text for the event symbols:
  */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7e0cbe7..84d3771 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,21 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
 
+int parse_events_modifier(struct list_head *list __used, char *str __used);
+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,
+			     unsigned long type, unsigned long config);
+int parse_events_add_cache(struct list_head *list, int *idx,
+			   char *type, char *op_result1, char *op_result2);
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
+				void *ptr, char *type);
+void parse_events_error(struct list_head *list, int *idx,
+			char const *msg);
+
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
 void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
new file mode 100644
index 0000000..44dbc35
--- /dev/null
+++ b/tools/perf/util/parse-events.l
@@ -0,0 +1,107 @@
+
+%option prefix="parse_events_"
+
+%{
+#include <errno.h>
+#include "../perf.h"
+#include "parse-events-bison.h"
+
+static int __value(char *str, int base, int token)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(str, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.num = num;
+	return token;
+}
+
+static int value(int base)
+{
+	return __value(parse_events_text, base, PE_VALUE);
+}
+
+static int raw(void)
+{
+	return __value(parse_events_text + 1, 16, PE_RAW);
+}
+
+static int str(int token)
+{
+	parse_events_lval.str = strdup(parse_events_text);
+	return token;
+}
+
+static int sym(int type, int config)
+{
+	parse_events_lval.num = (type << 16) + config;
+	return PE_VALUE_SYM;
+}
+
+%}
+
+num_dec		[0-9]+
+num_hex		0x[a-fA-F0-9]+
+num_raw_hex	[a-fA-F0-9]+
+name		[a-zA-Z_*?][a-zA-Z0-9_*?]*
+modifier_event	[ukhp]{1,5}
+modifier_bp	[rwx]
+
+%%
+cpu-cycles|cycles				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches			{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+cpu-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations			{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+
+L1-dcache|l1-d|l1d|L1-data		|
+L1-icache|l1-i|l1i|L1-instruction	|
+LLC|L2					|
+dTLB|d-tlb|Data-TLB			|
+iTLB|i-tlb|Instruction-TLB		|
+branch|branches|bpu|btb|bpc		|
+node					{ return str(PE_NAME_CACHE_TYPE); }
+
+load|loads|read				|
+store|stores|write			|
+prefetch|prefetches			|
+speculative-read|speculative-load	|
+refs|Reference|ops|access		|
+misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
+
+mem:			{ return PE_PREFIX_MEM; }
+r{num_raw_hex}		{ return raw(); }
+{num_dec}		{ return value(10); }
+{num_hex}		{ return value(16); }
+
+{modifier_event}	{ return str(PE_MODIFIER_EVENT); }
+{modifier_bp}		{ return str(PE_MODIFIER_BP); }
+{name}			{ return str(PE_NAME); }
+"/"			{ return '/'; }
+-			{ return '-'; }
+,			{ return ','; }
+:			{ return ':'; }
+=			{ return '='; }
+
+%%
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
new file mode 100644
index 0000000..4b4459e
--- /dev/null
+++ b/tools/perf/util/parse-events.y
@@ -0,0 +1,127 @@
+
+%name-prefix "parse_events_"
+%parse-param {struct list_head *list}
+%parse-param {int *idx}
+
+%{
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+%}
+
+%token PE_VALUE PE_VALUE_SYM PE_RAW
+%token PE_NAME
+%token PE_MODIFIER_EVENT PE_MODIFIER_BP
+%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
+%token PE_PREFIX_MEM PE_PREFIX_RAW
+%token PE_ERROR
+%type <num> PE_VALUE
+%type <num> PE_VALUE_SYM
+%type <num> PE_RAW
+%type <str> PE_NAME
+%type <str> PE_NAME_CACHE_TYPE
+%type <str> PE_NAME_CACHE_OP_RESULT
+%type <str> PE_MODIFIER_EVENT
+%type <str> PE_MODIFIER_BP
+
+%union
+{
+	char *str;
+	unsigned long num;
+}
+%%
+
+events:
+events ',' event | event
+
+event:
+event_def PE_MODIFIER_EVENT
+{
+	ABORT_ON(parse_events_modifier(list, $2));
+}
+|
+event_def
+
+event_def: event_legacy_symbol sep_dc |
+	   event_legacy_cache sep_dc |
+	   event_legacy_mem |
+	   event_legacy_tracepoint sep_dc |
+	   event_legacy_numeric sep_dc |
+	   event_legacy_raw sep_dc
+
+event_legacy_symbol:
+PE_VALUE_SYM
+{
+	int type = $1 >> 16;
+	int config = $1 & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+}
+
+event_legacy_cache:
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
+{
+	ABORT_ON(parse_events_add_cache(list, idx, $1, $3, $5));
+}
+|
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
+{
+	ABORT_ON(parse_events_add_cache(list, idx, $1, $3, NULL));
+}
+|
+PE_NAME_CACHE_TYPE
+{
+	ABORT_ON(parse_events_add_cache(list, idx, $1, NULL, NULL));
+}
+
+event_legacy_mem:
+PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
+{
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) $2, $4));
+}
+|
+PE_PREFIX_MEM PE_VALUE sep_dc
+{
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) $2, NULL));
+}
+
+event_legacy_tracepoint:
+PE_NAME ':' PE_NAME
+{
+	ABORT_ON(parse_events_add_tracepoint(list, idx, $1, $3));
+}
+
+event_legacy_numeric:
+PE_VALUE ':' PE_VALUE
+{
+	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3));
+}
+
+event_legacy_raw:
+PE_RAW
+{
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1));
+}
+
+sep_dc: ':' |
+
+%%
+
+void parse_events_error(struct list_head *list __used, int *idx __used,
+			char const *msg __used)
+{
+}
-- 
1.7.4.4


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

* [PATCH 7/9] perf, tool: Add config options support for event parsing
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (5 preceding siblings ...)
  2012-01-27 14:34                         ` [PATCH 6/9] perf, tool: Add parser generator for events parsing Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition Jiri Olsa
                                           ` (3 subsequent siblings)
  10 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding a new rule to the event grammar to be able to specify
values of additional attributes of symbolic event.

The new syntax for event symbolic definition is:

event_legacy_symbol:  PE_NAME_SYM '/' event_config '/' |
                      PE_NAME_SYM sep_slash_dc

event_config:         event_config ',' event_term | event_term

event_term:           PE_NAME '=' PE_NAME |
                      PE_NAME '=' PE_VALUE

sep_slash_dc: '/' | ':' |

At the moment the code is recognizing only 'period' config
option, which modifies value sample_period event attribute.

Use is now allowed to specify events like:
  cycles/period=100000/

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c            |   18 +++
 tools/perf/util/parse-events-bison.c |  245 +++++++++++++++++++++++-----------
 tools/perf/util/parse-events-bison.h |    6 +-
 tools/perf/util/parse-events.c       |   75 ++++++++++-
 tools/perf/util/parse-events.h       |   22 +++-
 tools/perf/util/parse-events.y       |   66 +++++++++-
 6 files changed, 340 insertions(+), 92 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index adf959f..e46bf21 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -677,6 +677,20 @@ static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
 	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);
+	return 0;
+}
+
 static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -884,6 +898,10 @@ static struct test__event_st {
 		.check = test__checkevent_symbolic_name,
 	},
 	{
+		.name  = "cycles/period=100000/",
+		.check = test__checkevent_symbolic_name_config,
+	},
+	{
 		.name  = "faults",
 		.check = test__checkevent_symbolic_alias,
 	},
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
index 20fca26..32adc40 100644
--- a/tools/perf/util/parse-events-bison.c
+++ b/tools/perf/util/parse-events-bison.c
@@ -145,15 +145,17 @@ typedef union YYSTYPE
 {
 
 /* Line 214 of yacc.c  */
-#line 42 "util/parse-events.y"
+#line 44 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
+	struct list_head *head;
+	struct parse_events__term *term;
 
 
 
 /* Line 214 of yacc.c  */
-#line 157 "util/parse-events-bison.c"
+#line 159 "util/parse-events-bison.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -165,7 +167,7 @@ typedef union YYSTYPE
 
 
 /* Line 264 of yacc.c  */
-#line 169 "util/parse-events-bison.c"
+#line 171 "util/parse-events-bison.c"
 
 #ifdef short
 # undef short
@@ -378,18 +380,18 @@ union yyalloc
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  20
+#define YYFINAL  23
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   27
+#define YYLAST   35
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  17
+#define YYNTOKENS  19
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  11
+#define YYNNTS  14
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  22
+#define YYNRULES  30
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  39
+#define YYNSTATES  50
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -405,9 +407,9 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    14,    15,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    16,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    14,    16,     2,    15,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    17,     2,
+       2,    18,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -435,29 +437,34 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint8 yyprhs[] =
 {
-       0,     0,     3,     7,     9,    12,    14,    17,    20,    22,
-      25,    28,    31,    33,    39,    43,    45,    51,    55,    59,
-      63,    65,    67
+       0,     0,     3,     7,     9,    12,    14,    16,    19,    21,
+      24,    27,    30,    35,    38,    44,    48,    50,    56,    60,
+      64,    68,    70,    74,    76,    80,    84,    86,    87,    89,
+      91
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      18,     0,    -1,    18,    14,    19,    -1,    19,    -1,    20,
-       7,    -1,    20,    -1,    21,    27,    -1,    22,    27,    -1,
-      23,    -1,    24,    27,    -1,    25,    27,    -1,    26,    27,
-      -1,     4,    -1,     9,    15,    10,    15,    10,    -1,     9,
-      15,    10,    -1,     9,    -1,    11,     3,    16,     8,    27,
-      -1,    11,     3,    27,    -1,     6,    16,     6,    -1,     3,
-      16,     3,    -1,     5,    -1,    16,    -1,    -1
+      20,     0,    -1,    20,    14,    21,    -1,    21,    -1,    22,
+       7,    -1,    22,    -1,    23,    -1,    24,    31,    -1,    25,
+      -1,    26,    31,    -1,    27,    31,    -1,    28,    31,    -1,
+       4,    15,    29,    15,    -1,     4,    32,    -1,     9,    16,
+      10,    16,    10,    -1,     9,    16,    10,    -1,     9,    -1,
+      11,     3,    17,     8,    31,    -1,    11,     3,    31,    -1,
+       6,    17,     6,    -1,     3,    17,     3,    -1,     5,    -1,
+      29,    14,    30,    -1,    30,    -1,     6,    18,     6,    -1,
+       6,    18,     3,    -1,    17,    -1,    -1,    15,    -1,    17,
+      -1,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    49,    49,    49,    52,    57,    59,    60,    61,    62,
-      63,    64,    67,    76,    81,    86,    92,    97,   103,   109,
-     115,   120,   120
+       0,    53,    53,    53,    56,    61,    63,    64,    65,    66,
+      67,    68,    71,    80,    89,    94,    99,   105,   110,   116,
+     122,   128,   134,   144,   156,   165,   174,   174,   176,   176,
+     176
 };
 #endif
 
@@ -469,10 +476,11 @@ static const char *const yytname[] =
   "$end", "error", "$undefined", "PE_VALUE", "PE_VALUE_SYM", "PE_RAW",
   "PE_NAME", "PE_MODIFIER_EVENT", "PE_MODIFIER_BP", "PE_NAME_CACHE_TYPE",
   "PE_NAME_CACHE_OP_RESULT", "PE_PREFIX_MEM", "PE_PREFIX_RAW", "PE_ERROR",
-  "','", "'-'", "':'", "$accept", "events", "event", "event_def",
-  "event_legacy_symbol", "event_legacy_cache", "event_legacy_mem",
-  "event_legacy_tracepoint", "event_legacy_numeric", "event_legacy_raw",
-  "sep_dc", 0
+  "','", "'/'", "'-'", "':'", "'='", "$accept", "events", "event",
+  "event_def", "event_legacy_symbol", "event_legacy_cache",
+  "event_legacy_mem", "event_legacy_tracepoint", "event_legacy_numeric",
+  "event_legacy_raw", "event_config", "event_term", "sep_dc",
+  "sep_slash_dc", 0
 };
 #endif
 
@@ -482,24 +490,26 @@ static const char *const yytname[] =
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,    44,    45,    58
+     265,   266,   267,   268,    44,    47,    45,    58,    61
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    17,    18,    18,    19,    19,    20,    20,    20,    20,
-      20,    20,    21,    22,    22,    22,    23,    23,    24,    25,
-      26,    27,    27
+       0,    19,    20,    20,    21,    21,    22,    22,    22,    22,
+      22,    22,    23,    23,    24,    24,    24,    25,    25,    26,
+      27,    28,    29,    29,    30,    30,    31,    31,    32,    32,
+      32
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     3,     1,     2,     1,     2,     2,     1,     2,
-       2,     2,     1,     5,     3,     1,     5,     3,     3,     3,
-       1,     1,     0
+       0,     2,     3,     1,     2,     1,     1,     2,     1,     2,
+       2,     2,     4,     2,     5,     3,     1,     5,     3,     3,
+       3,     1,     3,     1,     3,     3,     1,     0,     1,     1,
+       0
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -507,35 +517,37 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,    12,    20,     0,    15,     0,     0,     3,     5,
-      22,    22,     8,    22,    22,    22,     0,     0,     0,    22,
-       1,     0,     4,    21,     6,     7,     9,    10,    11,    19,
-      18,    14,    21,    17,     2,     0,    22,    13,    16
+       0,     0,    30,    21,     0,    16,     0,     0,     3,     5,
+       6,    27,     8,    27,    27,    27,     0,    28,    29,    13,
+       0,     0,    27,     1,     0,     4,    26,     7,     9,    10,
+      11,    20,     0,     0,    23,    19,    15,    26,    18,     2,
+       0,     0,    12,     0,    27,    25,    24,    22,    14,    17
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
       -1,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      24
+      33,    34,    27,    19
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -12
+#define YYPACT_NINF -14
 static const yytype_int8 yypact[] =
 {
-       7,   -10,   -12,   -12,    -9,    -6,     2,     1,   -12,    10,
-      -2,    -2,   -12,    -2,    -2,    -2,    16,    14,    11,     6,
-     -12,     7,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
-     -12,     8,    18,   -12,   -12,    17,    -2,   -12,   -12
+       1,    -3,    -2,   -14,    -1,     6,    17,     3,   -14,    14,
+     -14,     7,   -14,     7,     7,     7,    20,    19,   -14,   -14,
+      21,    16,    11,   -14,     1,   -14,   -14,   -14,   -14,   -14,
+     -14,   -14,    12,     4,   -14,   -14,    13,    24,   -14,   -14,
+       5,    19,   -14,    23,     7,   -14,   -14,   -14,   -14,   -14
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -12,   -12,     3,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
-     -11
+     -14,   -14,    10,   -14,   -14,   -14,   -14,   -14,   -14,   -14,
+     -14,    -6,   -13,   -14
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -545,26 +557,29 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      25,    20,    26,    27,    28,    19,    16,    17,    33,    18,
-       1,     2,     3,     4,    23,    21,     5,    22,     6,    29,
-      30,    31,    32,    35,    34,    38,    36,    37
+      28,    29,    30,    23,     1,     2,     3,     4,    45,    38,
+       5,    46,     6,    17,    16,    18,    20,    24,    41,    42,
+      22,    25,    21,    31,    26,    32,    36,    35,    37,    43,
+      40,    49,    44,    48,    39,    47
 };
 
 static const yytype_uint8 yycheck[] =
 {
-      11,     0,    13,    14,    15,     3,    16,    16,    19,    15,
-       3,     4,     5,     6,    16,    14,     9,     7,    11,     3,
-       6,    10,    16,    15,    21,    36,     8,    10
+      13,    14,    15,     0,     3,     4,     5,     6,     3,    22,
+       9,     6,    11,    15,    17,    17,    17,    14,    14,    15,
+       3,     7,    16,     3,    17,     6,    10,     6,    17,    16,
+      18,    44,     8,    10,    24,    41
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,     4,     5,     6,     9,    11,    18,    19,    20,
-      21,    22,    23,    24,    25,    26,    16,    16,    15,     3,
-       0,    14,     7,    16,    27,    27,    27,    27,    27,     3,
-       6,    10,    16,    27,    19,    15,     8,    10,    27
+       0,     3,     4,     5,     6,     9,    11,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    17,    15,    17,    32,
+      17,    16,     3,     0,    14,     7,    17,    31,    31,    31,
+      31,     3,     6,    29,    30,     6,    10,    17,    31,    21,
+      18,    14,    15,    16,     8,     3,     6,    30,    10,    31
 };
 
 #define yyerrok		(yyerrstatus = 0)
@@ -1400,7 +1415,7 @@ yyreduce:
         case 4:
 
 /* Line 1464 of yacc.c  */
-#line 53 "util/parse-events.y"
+#line 57 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_modifier(list, (yyvsp[(2) - (2)].str)));
 ;}
@@ -1409,91 +1424,159 @@ yyreduce:
   case 12:
 
 /* Line 1464 of yacc.c  */
-#line 68 "util/parse-events.y"
+#line 72 "util/parse-events.y"
     {
-	int type = (yyvsp[(1) - (1)].num) >> 16;
-	int config = (yyvsp[(1) - (1)].num) & 255;
+	int type = (yyvsp[(1) - (4)].num) >> 16;
+	int config = (yyvsp[(1) - (4)].num) & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, (yyvsp[(3) - (4)].head)));
+	parse_events__free_terms((yyvsp[(3) - (4)].head));
 ;}
     break;
 
   case 13:
 
 /* Line 1464 of yacc.c  */
-#line 77 "util/parse-events.y"
+#line 81 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
+	int type = (yyvsp[(1) - (2)].num) >> 16;
+	int config = (yyvsp[(1) - (2)].num) & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, NULL));
 ;}
     break;
 
   case 14:
 
 /* Line 1464 of yacc.c  */
-#line 82 "util/parse-events.y"
+#line 90 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
 ;}
     break;
 
   case 15:
 
 /* Line 1464 of yacc.c  */
-#line 87 "util/parse-events.y"
+#line 95 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
 ;}
     break;
 
   case 16:
 
 /* Line 1464 of yacc.c  */
-#line 93 "util/parse-events.y"
+#line 100 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
+	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
 ;}
     break;
 
   case 17:
 
 /* Line 1464 of yacc.c  */
-#line 98 "util/parse-events.y"
+#line 106 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
 ;}
     break;
 
   case 18:
 
 /* Line 1464 of yacc.c  */
-#line 104 "util/parse-events.y"
+#line 111 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
+	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
 ;}
     break;
 
   case 19:
 
 /* Line 1464 of yacc.c  */
-#line 110 "util/parse-events.y"
+#line 117 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num)));
+	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
 ;}
     break;
 
   case 20:
 
 /* Line 1464 of yacc.c  */
-#line 116 "util/parse-events.y"
+#line 123 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
+;}
+    break;
+
+  case 21:
+
+/* Line 1464 of yacc.c  */
+#line 129 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
+;}
+    break;
+
+  case 22:
+
+/* Line 1464 of yacc.c  */
+#line 135 "util/parse-events.y"
+    {
+	struct list_head *head = (yyvsp[(1) - (3)].head);
+	struct parse_events__term *term = (yyvsp[(3) - (3)].term);
+
+	ABORT_ON(!head);
+	list_add_tail(&term->list, head);
+	(yyval.head) = (yyvsp[(1) - (3)].head);
+;}
+    break;
+
+  case 23:
+
+/* Line 1464 of yacc.c  */
+#line 145 "util/parse-events.y"
+    {
+	struct list_head *head = malloc(sizeof(*head));
+	struct parse_events__term *term = (yyvsp[(1) - (1)].term);
+
+	ABORT_ON(!head);
+	INIT_LIST_HEAD(head);
+	list_add_tail(&term->list, head);
+	(yyval.head) = head;
+;}
+    break;
+
+  case 24:
+
+/* Line 1464 of yacc.c  */
+#line 157 "util/parse-events.y"
+    {
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
+		 (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), 0));
+	(yyval.term) = term;
+;}
+    break;
+
+  case 25:
+
+/* Line 1464 of yacc.c  */
+#line 166 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num)));
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
+		 (yyvsp[(1) - (3)].str), NULL, (yyvsp[(3) - (3)].num)));
+	(yyval.term) = term;
 ;}
     break;
 
 
 
 /* Line 1464 of yacc.c  */
-#line 1497 "util/parse-events-bison.c"
+#line 1580 "util/parse-events-bison.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1705,7 +1788,7 @@ yyreturn:
 
 
 /* Line 1684 of yacc.c  */
-#line 122 "util/parse-events.y"
+#line 178 "util/parse-events.y"
 
 
 void parse_events_error(struct list_head *list __used, int *idx __used,
diff --git a/tools/perf/util/parse-events-bison.h b/tools/perf/util/parse-events-bison.h
index 097a632..b73c4bd 100644
--- a/tools/perf/util/parse-events-bison.h
+++ b/tools/perf/util/parse-events-bison.h
@@ -59,15 +59,17 @@ typedef union YYSTYPE
 {
 
 /* Line 1685 of yacc.c  */
-#line 42 "util/parse-events.y"
+#line 44 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
+	struct list_head *head;
+	struct parse_events__term *term;
 
 
 
 /* Line 1685 of yacc.c  */
-#line 71 "util/parse-events-bison.h"
+#line 73 "util/parse-events-bison.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6e50b91..7423049 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -588,15 +588,46 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
 	return add_event(list, idx, &attr, name);
 }
 
-int
-parse_events_add_numeric(struct list_head *list, int *idx,
-			 unsigned long type, unsigned long config)
+static int config_term(struct perf_event_attr *attr,
+		       struct parse_events__term *term)
+{
+	/* Only period supported so far. */
+	if (strcmp(term->config, "period"))
+		return -EINVAL;
+
+	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+		return -EINVAL;
+
+	attr->sample_period = term->val.num;
+	return 0;
+}
+
+static int config_attr(struct perf_event_attr *attr,
+		       struct list_head *head)
+{
+	struct parse_events__term *term;
+
+	list_for_each_entry(term, head, list)
+		if (config_term(attr, term))
+			return -EINVAL;
+
+	return 0;
+}
+
+int parse_events_add_numeric(struct list_head *list, int *idx,
+			     unsigned long type, unsigned long config,
+			     struct list_head *head_config)
 {
 	struct perf_event_attr attr;
 
 	memset(&attr, 0, sizeof(attr));
 	attr.type = type;
 	attr.config = config;
+
+	if (head_config &&
+	    config_attr(&attr, head_config))
+		return -EINVAL;
+
 	return add_event(list, idx, &attr,
 			 (char *) __event_name(type, config));
 }
@@ -923,3 +954,41 @@ void print_events(const char *event_glob)
 
 	print_tracepoint_events(NULL, NULL);
 }
+
+int parse_events__new_term(struct parse_events__term **_term, int type,
+			   char *config, char *str, long num)
+{
+	struct parse_events__term *term;
+
+	term = zalloc(sizeof(*term));
+	if (!term)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&term->list);
+	term->type = type;
+	term->config = config;
+
+	switch (type) {
+	case PARSE_EVENTS__TERM_TYPE_NUM:
+		term->val.num = num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_STR:
+		term->val.str = str;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_term = term;
+	return 0;
+}
+
+void parse_events__free_terms(struct list_head *terms)
+{
+	struct parse_events__term *term, *h;
+
+	list_for_each_entry_safe(term, h, terms, list)
+		free(term);
+
+	free(terms);
+}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 84d3771..2737f1e 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,25 @@ 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,
+};
+
+struct parse_events__term {
+	char *config;
+	union {
+		char *str;
+		long  num;
+	} val;
+	int type;
+
+	struct list_head list;
+};
+
+int parse_events__new_term(struct parse_events__term **term, int type,
+			   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,
 				char *sys, char *event);
@@ -40,7 +59,8 @@ 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,
-			     unsigned long type, unsigned long config);
+			     unsigned long type, unsigned long config,
+			     struct list_head *head_config);
 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,
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 4b4459e..0be12dc 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -37,11 +37,15 @@ do { \
 %type <str> PE_NAME_CACHE_OP_RESULT
 %type <str> PE_MODIFIER_EVENT
 %type <str> PE_MODIFIER_BP
+%type <head> event_config
+%type <term> event_term
 
 %union
 {
 	char *str;
 	unsigned long num;
+	struct list_head *head;
+	struct parse_events__term *term;
 }
 %%
 
@@ -56,7 +60,7 @@ event_def PE_MODIFIER_EVENT
 |
 event_def
 
-event_def: event_legacy_symbol sep_dc |
+event_def: event_legacy_symbol |
 	   event_legacy_cache sep_dc |
 	   event_legacy_mem |
 	   event_legacy_tracepoint sep_dc |
@@ -64,12 +68,21 @@ event_def: event_legacy_symbol sep_dc |
 	   event_legacy_raw sep_dc
 
 event_legacy_symbol:
-PE_VALUE_SYM
+PE_VALUE_SYM '/' event_config '/'
 {
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config));
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, $3));
+	parse_events__free_terms($3);
+}
+|
+PE_VALUE_SYM sep_slash_dc
+{
+	int type = $1 >> 16;
+	int config = $1 & 255;
+
+	ABORT_ON(parse_events_add_numeric(list, idx, type, config, NULL));
 }
 
 event_legacy_cache:
@@ -108,17 +121,60 @@ PE_NAME ':' PE_NAME
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3));
+	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3, NULL));
 }
 
 event_legacy_raw:
 PE_RAW
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1));
+	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1, NULL));
+}
+
+event_config:
+event_config ',' event_term
+{
+	struct list_head *head = $1;
+	struct parse_events__term *term = $3;
+
+	ABORT_ON(!head);
+	list_add_tail(&term->list, head);
+	$$ = $1;
+}
+|
+event_term
+{
+	struct list_head *head = malloc(sizeof(*head));
+	struct parse_events__term *term = $1;
+
+	ABORT_ON(!head);
+	INIT_LIST_HEAD(head);
+	list_add_tail(&term->list, head);
+	$$ = head;
+}
+
+event_term:
+PE_NAME '=' PE_NAME
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
+		 $1, $3, 0));
+	$$ = term;
+}
+|
+PE_NAME '=' PE_VALUE
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
+		 $1, NULL, $3));
+	$$ = term;
 }
 
 sep_dc: ':' |
 
+sep_slash_dc: '/' | ':' |
+
 %%
 
 void parse_events_error(struct list_head *list __used, int *idx __used,
-- 
1.7.4.4


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

* [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (6 preceding siblings ...)
  2012-01-27 14:34                         ` [PATCH 7/9] perf, tool: Add config options support for event parsing Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-01-27 14:34                         ` [PATCH 9/9] perf, tool: Add support to specify pmu style event Jiri Olsa
                                           ` (2 subsequent siblings)
  10 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Adding pmu object which provides interface to pmu's sysfs
event format definition located at:
  ${sysfs_mount}/bus/event_source/devices/${pmu}/format

Following interface is exported:
  struct perf_pmu* perf_pmu__find(char *name);
  - this function returns pmu object, which is then
    passed as a handle to other interface functions

  int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                       struct list_head *head_terms);
  - this function configures perf_event_attr struct based
    on pmu's format definitions and config terms data,
    containined in head_terms list.

Parser generator is used to retrive the pmu's format definition.
The generated parser is part of the patch. Added makefile rule
'pmu-parser' to generate the parser code out of the bison/flex
sources.

Added builtin test 'Test perf pmu format parsing', which could
be run like:
	perf test pmu

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile         |   12 +
 tools/perf/builtin-test.c   |   10 +
 tools/perf/util/pmu-bison.c | 1663 +++++++++++++++++++++++++++++++++++++++
 tools/perf/util/pmu-bison.h |   73 ++
 tools/perf/util/pmu-flex.c  | 1821 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/pmu-flex.h  |  316 ++++++++
 tools/perf/util/pmu.c       |  462 +++++++++++
 tools/perf/util/pmu.h       |   41 +
 tools/perf/util/pmu.l       |   43 +
 tools/perf/util/pmu.y       |   93 +++
 10 files changed, 4534 insertions(+), 0 deletions(-)
 create mode 100644 tools/perf/util/pmu-bison.c
 create mode 100644 tools/perf/util/pmu-bison.h
 create mode 100644 tools/perf/util/pmu-flex.c
 create mode 100644 tools/perf/util/pmu-flex.h
 create mode 100644 tools/perf/util/pmu.c
 create mode 100644 tools/perf/util/pmu.h
 create mode 100644 tools/perf/util/pmu.l
 create mode 100644 tools/perf/util/pmu.y

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index ee48082..0b9a40e 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -259,6 +259,7 @@ LIB_H += util/build-id.h
 LIB_H += util/debug.h
 LIB_H += util/debugfs.h
 LIB_H += util/sysfs.h
+LIB_H += util/pmu.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
 LIB_H += util/evlist.h
@@ -306,6 +307,7 @@ LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
 LIB_OBJS += $(OUTPUT)util/sysfs.o
+LIB_OBJS += $(OUTPUT)util/pmu.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
 LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -344,6 +346,8 @@ LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
 LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
 LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
+LIB_OBJS += $(OUTPUT)util/pmu-flex.o
+LIB_OBJS += $(OUTPUT)util/pmu-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -752,6 +756,9 @@ $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/parse-events-flex.o: util/parse-events-flex.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
 
+$(OUTPUT)util/pmu-flex.o: util/pmu-flex.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
@@ -789,6 +796,7 @@ help:
 	@echo '  info		- make GNU info documentation (access with info <foo>)'
 	@echo '  pdf		- make pdf documentation'
 	@echo '  event-parser	- make event parser code'
+	@echo '  pmu-parser	- make pmu format parser code'
 	@echo '  TAGS		- use etags to make tag information for source browsing'
 	@echo '  tags		- use ctags to make tag information for source browsing'
 	@echo '  cscope	- use cscope to make interactive browsing database'
@@ -843,6 +851,10 @@ event-parser:
 	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o util/parse-events-bison.c
 	$(QUIET_FLEX)$(FLEX) --header-file=util/parse-events-flex.h -t util/parse-events.l > util/parse-events-flex.c
 
+pmu-parser:
+	$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o util/pmu-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=util/pmu-flex.h -t util/pmu.l > util/pmu-flex.c
+
 ### Detect prefix changes
 TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
              $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index e46bf21..1969d3f 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -13,6 +13,7 @@
 #include "util/parse-events.h"
 #include "util/symbol.h"
 #include "util/thread_map.h"
+#include "util/pmu.h"
 #include "../../include/linux/hw_breakpoint.h"
 
 #include <sys/mman.h>
@@ -1483,6 +1484,11 @@ static int test__rdpmc(void)
 
 #endif
 
+static int test__perf_pmu(void)
+{
+	return perf_pmu__test();
+}
+
 static struct test {
 	const char *desc;
 	int (*func)(void);
@@ -1518,6 +1524,10 @@ static struct test {
 		.func = test__PERF_RECORD,
 	},
 	{
+		.desc = "Test perf pmu format parsing",
+		.func = test__perf_pmu,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/util/pmu-bison.c b/tools/perf/util/pmu-bison.c
new file mode 100644
index 0000000..343521e
--- /dev/null
+++ b/tools/perf/util/pmu-bison.c
@@ -0,0 +1,1663 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.4.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse         perf_pmu_parse
+#define yylex           perf_pmu_lex
+#define yyerror         perf_pmu_error
+#define yylval          perf_pmu_lval
+#define yychar          perf_pmu_char
+#define yydebug         perf_pmu_debug
+#define yynerrs         perf_pmu_nerrs
+
+
+/* Copy the first part of user declarations.  */
+
+/* Line 189 of yacc.c  */
+#line 6 "util/pmu.y"
+
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/bitmap.h>
+#include <string.h>
+#include "pmu.h"
+
+extern int perf_pmu_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+        if (val) \
+                YYABORT; \
+} while (0)
+
+
+
+/* Line 189 of yacc.c  */
+#line 99 "util/pmu-bison.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PP_CONFIG = 258,
+     PP_CONFIG1 = 259,
+     PP_CONFIG2 = 260,
+     PP_VALUE = 261,
+     PP_ERROR = 262
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c  */
+#line 31 "util/pmu.y"
+
+	unsigned long num;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+
+
+
+/* Line 214 of yacc.c  */
+#line 149 "util/pmu-bison.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 264 of yacc.c  */
+#line 161 "util/pmu-bison.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  9
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   17
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  11
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  5
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  10
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  20
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   262
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     9,    10,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     8,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     6,     8,    12,    16,    20,    24,    26,
+      30
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      12,     0,    -1,    12,    13,    -1,    13,    -1,     3,     8,
+      14,    -1,     4,     8,    14,    -1,     5,     8,    14,    -1,
+      14,     9,    15,    -1,    15,    -1,     6,    10,     6,    -1,
+       6,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,    39,    39,    41,    44,    51,    58,    66,    71,    77,
+      82
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "PP_CONFIG", "PP_CONFIG1", "PP_CONFIG2",
+  "PP_VALUE", "PP_ERROR", "':'", "','", "'-'", "$accept", "format",
+  "format_term", "bits", "bit_term", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,    58,    44,
+      45
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    11,    12,    12,    13,    13,    13,    14,    14,    15,
+      15
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     2,     1,     3,     3,     3,     3,     1,     3,
+       1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,     0,     0,     0,     0,     3,     0,     0,     0,     1,
+       2,    10,     4,     8,     5,     6,     0,     0,     9,     7
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     4,     5,    12,    13
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -7
+static const yytype_int8 yypact[] =
+{
+       3,     1,     2,     4,     0,    -7,     5,     5,     5,    -7,
+      -7,     6,     8,    -7,     8,     8,     7,     5,    -7,    -7
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+      -7,    -7,    10,    -6,    -2
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+       9,    14,    15,     1,     2,     3,     1,     2,     3,     6,
+       7,    11,     8,    18,    10,    19,    16,    17
+};
+
+static const yytype_uint8 yycheck[] =
+{
+       0,     7,     8,     3,     4,     5,     3,     4,     5,     8,
+       8,     6,     8,     6,     4,    17,    10,     9
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,     4,     5,    12,    13,     8,     8,     8,     0,
+      13,     6,    14,    15,    14,    14,    10,     9,     6,    15
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  However,
+   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
+   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+   discussed.  */
+
+#define YYFAIL		goto yyerrlab
+#if defined YYFAIL
+  /* This is here to suppress warnings from the GCC cpp's
+     -Wunused-macros.  Normally we don't worry about that warning, but
+     some users do, and we want to make it easy for users to remove
+     YYFAIL uses, which will produce warnings from Bison 2.5.  */
+#endif
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (format, name, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, format, name); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *format, char *name)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, format, name)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *format;
+    char *name;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (format);
+  YYUSE (name);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *format, char *name)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, format, name)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    struct list_head *format;
+    char *name;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, format, name);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, struct list_head *format, char *name)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, format, name)
+    YYSTYPE *yyvsp;
+    int yyrule;
+    struct list_head *format;
+    char *name;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       , format, name);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule, format, name); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct list_head *format, char *name)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, format, name)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    struct list_head *format;
+    char *name;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (format);
+  YYUSE (name);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (struct list_head *format, char *name);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (struct list_head *format, char *name)
+#else
+int
+yyparse (format, name)
+    struct list_head *format;
+    char *name;
+#endif
+#endif
+{
+
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+
+/* Line 1464 of yacc.c  */
+#line 45 "util/pmu.y"
+    {
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG,
+				      (yyvsp[(3) - (3)].bits)));
+;}
+    break;
+
+  case 5:
+
+/* Line 1464 of yacc.c  */
+#line 52 "util/pmu.y"
+    {
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG1,
+				      (yyvsp[(3) - (3)].bits)));
+;}
+    break;
+
+  case 6:
+
+/* Line 1464 of yacc.c  */
+#line 59 "util/pmu.y"
+    {
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG2,
+				      (yyvsp[(3) - (3)].bits)));
+;}
+    break;
+
+  case 7:
+
+/* Line 1464 of yacc.c  */
+#line 67 "util/pmu.y"
+    {
+	bitmap_or((yyval.bits), (yyvsp[(1) - (3)].bits), (yyvsp[(3) - (3)].bits), 64);
+;}
+    break;
+
+  case 8:
+
+/* Line 1464 of yacc.c  */
+#line 72 "util/pmu.y"
+    {
+	memcpy((yyval.bits), (yyvsp[(1) - (1)].bits), sizeof((yyvsp[(1) - (1)].bits)));
+;}
+    break;
+
+  case 9:
+
+/* Line 1464 of yacc.c  */
+#line 78 "util/pmu.y"
+    {
+	perf_pmu__set_format((yyval.bits), (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num));
+;}
+    break;
+
+  case 10:
+
+/* Line 1464 of yacc.c  */
+#line 83 "util/pmu.y"
+    {
+	perf_pmu__set_format((yyval.bits), (yyvsp[(1) - (1)].num), 0);
+;}
+    break;
+
+
+
+/* Line 1464 of yacc.c  */
+#line 1444 "util/pmu-bison.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (format, name, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (format, name, yymsg);
+	  }
+	else
+	  {
+	    yyerror (format, name, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, format, name);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, format, name);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (format, name, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, format, name);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, format, name);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+/* Line 1684 of yacc.c  */
+#line 87 "util/pmu.y"
+
+
+void perf_pmu_error(struct list_head *list __used,
+		    char *name __used,
+		    char const *msg __used)
+{
+}
+
diff --git a/tools/perf/util/pmu-bison.h b/tools/perf/util/pmu-bison.h
new file mode 100644
index 0000000..54f4a0d
--- /dev/null
+++ b/tools/perf/util/pmu-bison.h
@@ -0,0 +1,73 @@
+/* A Bison parser, made by GNU Bison 2.4.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2009, 2010 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     PP_CONFIG = 258,
+     PP_CONFIG1 = 259,
+     PP_CONFIG2 = 260,
+     PP_VALUE = 261,
+     PP_ERROR = 262
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1685 of yacc.c  */
+#line 31 "util/pmu.y"
+
+	unsigned long num;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+
+
+
+/* Line 1685 of yacc.c  */
+#line 65 "util/pmu-bison.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE perf_pmu_lval;
+
+
diff --git a/tools/perf/util/pmu-flex.c b/tools/perf/util/pmu-flex.c
new file mode 100644
index 0000000..5a8c159
--- /dev/null
+++ b/tools/perf/util/pmu-flex.c
@@ -0,0 +1,1821 @@
+
+#line 3 "<stdout>"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer perf_pmu__create_buffer
+#define yy_delete_buffer perf_pmu__delete_buffer
+#define yy_flex_debug perf_pmu__flex_debug
+#define yy_init_buffer perf_pmu__init_buffer
+#define yy_flush_buffer perf_pmu__flush_buffer
+#define yy_load_buffer_state perf_pmu__load_buffer_state
+#define yy_switch_to_buffer perf_pmu__switch_to_buffer
+#define yyin perf_pmu_in
+#define yyleng perf_pmu_leng
+#define yylex perf_pmu_lex
+#define yylineno perf_pmu_lineno
+#define yyout perf_pmu_out
+#define yyrestart perf_pmu_restart
+#define yytext perf_pmu_text
+#define yywrap perf_pmu_wrap
+#define yyalloc perf_pmu_alloc
+#define yyrealloc perf_pmu_realloc
+#define yyfree perf_pmu_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE perf_pmu_restart(perf_pmu_in  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int perf_pmu_leng;
+
+extern FILE *perf_pmu_in, *perf_pmu_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up perf_pmu_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up perf_pmu_text again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via perf_pmu_restart()), so that the user can continue scanning by
+	 * just pointing perf_pmu_in at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when perf_pmu_text is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int perf_pmu_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow perf_pmu_wrap()'s to do buffer switches
+ * instead of setting up a fresh perf_pmu_in.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void perf_pmu_restart (FILE *input_file  );
+void perf_pmu__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE perf_pmu__create_buffer (FILE *file,int size  );
+void perf_pmu__delete_buffer (YY_BUFFER_STATE b  );
+void perf_pmu__flush_buffer (YY_BUFFER_STATE b  );
+void perf_pmu_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void perf_pmu_pop_buffer_state (void );
+
+static void perf_pmu_ensure_buffer_stack (void );
+static void perf_pmu__load_buffer_state (void );
+static void perf_pmu__init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER perf_pmu__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE perf_pmu__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE perf_pmu__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE perf_pmu__scan_bytes (yyconst char *bytes,int len  );
+
+void *perf_pmu_alloc (yy_size_t  );
+void *perf_pmu_realloc (void *,yy_size_t  );
+void perf_pmu_free (void *  );
+
+#define yy_new_buffer perf_pmu__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        perf_pmu_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        perf_pmu_ensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *perf_pmu_in = (FILE *) 0, *perf_pmu_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int perf_pmu_lineno;
+
+int perf_pmu_lineno = 1;
+
+extern char *perf_pmu_text;
+#define yytext_ptr perf_pmu_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up perf_pmu_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	perf_pmu_leng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 10
+#define YY_END_OF_BUFFER 11
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[20] =
+    {   0,
+        0,    0,   11,    8,    9,    7,    5,    1,    6,    8,
+        1,    0,    0,    0,    0,    2,    3,    4,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    2,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    3,    4,    1,    1,    5,    6,    7,
+        5,    5,    5,    5,    5,    5,    5,    8,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    9,    1,
+
+        1,   10,   11,    1,   12,    1,    1,    1,    1,   13,
+       14,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[15] =
+    {   0,
+        1,    1,    1,    1,    2,    2,    2,    1,    1,    1,
+        1,    1,    1,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[21] =
+    {   0,
+        0,    0,   23,   24,   24,   24,   24,    0,   24,    8,
+        0,    8,   10,    7,    7,    9,   24,   24,   24,   15
+    } ;
+
+static yyconst flex_int16_t yy_def[21] =
+    {   0,
+       19,    1,   19,   19,   19,   19,   19,   20,   19,   19,
+       20,   19,   19,   19,   19,   19,   19,   19,    0,   19
+    } ;
+
+static yyconst flex_int16_t yy_nxt[39] =
+    {   0,
+        4,    5,    6,    7,    8,    8,    8,    9,   10,    4,
+        4,    4,    4,    4,   17,   18,   11,   16,   15,   14,
+       13,   12,   19,    3,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19
+    } ;
+
+static yyconst flex_int16_t yy_chk[39] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,   16,   16,   20,   15,   14,   13,
+       12,   10,    3,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int perf_pmu__flex_debug;
+int perf_pmu__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *perf_pmu_text;
+#line 1 "util/pmu.l"
+#line 4 "util/pmu.l"
+#include <stdlib.h>
+#include <linux/bitops.h>
+#include "pmu.h"
+#include "pmu-bison.h"
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(perf_pmu_text, NULL, base);
+	if (errno)
+		return PP_ERROR;
+
+	perf_pmu_lval.num = num;
+	return PP_VALUE;
+}
+
+#line 497 "<stdout>"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int perf_pmu_lex_destroy (void );
+
+int perf_pmu_get_debug (void );
+
+void perf_pmu_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE perf_pmu_get_extra (void );
+
+void perf_pmu_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *perf_pmu_get_in (void );
+
+void perf_pmu_set_in  (FILE * in_str  );
+
+FILE *perf_pmu_get_out (void );
+
+void perf_pmu_set_out  (FILE * out_str  );
+
+int perf_pmu_get_leng (void );
+
+char *perf_pmu_get_text (void );
+
+int perf_pmu_get_lineno (void );
+
+void perf_pmu_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int perf_pmu_wrap (void );
+#else
+extern int perf_pmu_wrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( perf_pmu_text, perf_pmu_leng, 1, perf_pmu_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		unsigned n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( perf_pmu_in )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( perf_pmu_in ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, perf_pmu_in))==0 && ferror(perf_pmu_in)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(perf_pmu_in); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int perf_pmu_lex (void);
+
+#define YY_DECL int perf_pmu_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after perf_pmu_text and perf_pmu_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 26 "util/pmu.l"
+
+
+#line 682 "<stdout>"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! perf_pmu_in )
+			perf_pmu_in = stdin;
+
+		if ( ! perf_pmu_out )
+			perf_pmu_out = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			perf_pmu_ensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE );
+		}
+
+		perf_pmu__load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of perf_pmu_text. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 20 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 24 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 28 "util/pmu.l"
+{ return value(10); }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 29 "util/pmu.l"
+{ return PP_CONFIG; }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 30 "util/pmu.l"
+{ return PP_CONFIG1; }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 31 "util/pmu.l"
+{ return PP_CONFIG2; }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 32 "util/pmu.l"
+{ return '-'; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 33 "util/pmu.l"
+{ return ':'; }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 34 "util/pmu.l"
+{ return ','; }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 35 "util/pmu.l"
+{ ; }
+	YY_BREAK
+case 9:
+/* rule 9 can match eol */
+YY_RULE_SETUP
+#line 36 "util/pmu.l"
+{ ; }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 38 "util/pmu.l"
+ECHO;
+	YY_BREAK
+#line 816 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed perf_pmu_in at a new source and called
+			 * perf_pmu_lex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = perf_pmu_in;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( perf_pmu_wrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * perf_pmu_text, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of perf_pmu_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					perf_pmu_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			perf_pmu_restart(perf_pmu_in  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) perf_pmu_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 20 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    	register char *yy_cp = (yy_c_buf_p);
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 20 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 19);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up perf_pmu_text */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					perf_pmu_restart(perf_pmu_in );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( perf_pmu_wrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve perf_pmu_text */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void perf_pmu_restart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        perf_pmu_ensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            perf_pmu__create_buffer(perf_pmu_in,YY_BUF_SIZE );
+	}
+
+	perf_pmu__init_buffer(YY_CURRENT_BUFFER,input_file );
+	perf_pmu__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void perf_pmu__switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		perf_pmu_pop_buffer_state();
+	 *		perf_pmu_push_buffer_state(new_buffer);
+     */
+	perf_pmu_ensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	perf_pmu__load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (perf_pmu_wrap()) processing, but the only time this flag
+	 * is looked at is after perf_pmu_wrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void perf_pmu__load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	perf_pmu_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE perf_pmu__create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) perf_pmu_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) perf_pmu_alloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	perf_pmu__init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with perf_pmu__create_buffer()
+ * 
+ */
+    void perf_pmu__delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		perf_pmu_free((void *) b->yy_ch_buf  );
+
+	perf_pmu_free((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a perf_pmu_restart() or at EOF.
+ */
+    static void perf_pmu__init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	perf_pmu__flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then perf_pmu__init_buffer was _probably_
+     * called from perf_pmu_restart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void perf_pmu__flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		perf_pmu__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void perf_pmu_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	perf_pmu_ensure_buffer_stack();
+
+	/* This block is copied from perf_pmu__switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from perf_pmu__switch_to_buffer. */
+	perf_pmu__load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void perf_pmu_pop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	perf_pmu__delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		perf_pmu__load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void perf_pmu_ensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)perf_pmu_alloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in perf_pmu_ensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)perf_pmu_realloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in perf_pmu_ensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE perf_pmu__scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) perf_pmu_alloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	perf_pmu__switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to perf_pmu_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       perf_pmu__scan_bytes() instead.
+ */
+YY_BUFFER_STATE perf_pmu__scan_string (yyconst char * yystr )
+{
+    
+	return perf_pmu__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to perf_pmu_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE perf_pmu__scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) perf_pmu_alloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in perf_pmu__scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = perf_pmu__scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in perf_pmu__scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up perf_pmu_text. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		perf_pmu_text[perf_pmu_leng] = (yy_hold_char); \
+		(yy_c_buf_p) = perf_pmu_text + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		perf_pmu_leng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int perf_pmu_get_lineno  (void)
+{
+        
+    return perf_pmu_lineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *perf_pmu_get_in  (void)
+{
+        return perf_pmu_in;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *perf_pmu_get_out  (void)
+{
+        return perf_pmu_out;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int perf_pmu_get_leng  (void)
+{
+        return perf_pmu_leng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *perf_pmu_get_text  (void)
+{
+        return perf_pmu_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void perf_pmu_set_lineno (int  line_number )
+{
+    
+    perf_pmu_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see perf_pmu__switch_to_buffer
+ */
+void perf_pmu_set_in (FILE *  in_str )
+{
+        perf_pmu_in = in_str ;
+}
+
+void perf_pmu_set_out (FILE *  out_str )
+{
+        perf_pmu_out = out_str ;
+}
+
+int perf_pmu_get_debug  (void)
+{
+        return perf_pmu__flex_debug;
+}
+
+void perf_pmu_set_debug (int  bdebug )
+{
+        perf_pmu__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from perf_pmu_lex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    perf_pmu_in = stdin;
+    perf_pmu_out = stdout;
+#else
+    perf_pmu_in = (FILE *) 0;
+    perf_pmu_out = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * perf_pmu_lex_init()
+     */
+    return 0;
+}
+
+/* perf_pmu_lex_destroy is for both reentrant and non-reentrant scanners. */
+int perf_pmu_lex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		perf_pmu__delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		perf_pmu_pop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	perf_pmu_free((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * perf_pmu_lex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *perf_pmu_alloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *perf_pmu_realloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void perf_pmu_free (void * ptr )
+{
+	free( (char *) ptr );	/* see perf_pmu_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 38 "util/pmu.l"
+
+
+
+int perf_pmu_wrap(void)
+{
+	return 1;
+}
+
diff --git a/tools/perf/util/pmu-flex.h b/tools/perf/util/pmu-flex.h
new file mode 100644
index 0000000..0a29c8a
--- /dev/null
+++ b/tools/perf/util/pmu-flex.h
@@ -0,0 +1,316 @@
+#ifndef perf_pmu_HEADER_H
+#define perf_pmu_HEADER_H 1
+#define perf_pmu_IN_HEADER 1
+
+#line 6 "util/pmu-flex.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int perf_pmu_leng;
+
+extern FILE *perf_pmu_in, *perf_pmu_out;
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void perf_pmu_restart (FILE *input_file  );
+void perf_pmu__switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE perf_pmu__create_buffer (FILE *file,int size  );
+void perf_pmu__delete_buffer (YY_BUFFER_STATE b  );
+void perf_pmu__flush_buffer (YY_BUFFER_STATE b  );
+void perf_pmu_push_buffer_state (YY_BUFFER_STATE new_buffer  );
+void perf_pmu_pop_buffer_state (void );
+
+YY_BUFFER_STATE perf_pmu__scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE perf_pmu__scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE perf_pmu__scan_bytes (yyconst char *bytes,int len  );
+
+void *perf_pmu_alloc (yy_size_t  );
+void *perf_pmu_realloc (void *,yy_size_t  );
+void perf_pmu_free (void *  );
+
+/* Begin user sect3 */
+
+extern int perf_pmu_lineno;
+
+extern char *perf_pmu_text;
+#define yytext_ptr perf_pmu_text
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int perf_pmu_lex_destroy (void );
+
+int perf_pmu_get_debug (void );
+
+void perf_pmu_set_debug (int debug_flag  );
+
+YY_EXTRA_TYPE perf_pmu_get_extra (void );
+
+void perf_pmu_set_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *perf_pmu_get_in (void );
+
+void perf_pmu_set_in  (FILE * in_str  );
+
+FILE *perf_pmu_get_out (void );
+
+void perf_pmu_set_out  (FILE * out_str  );
+
+int perf_pmu_get_leng (void );
+
+char *perf_pmu_get_text (void );
+
+int perf_pmu_get_lineno (void );
+
+void perf_pmu_set_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int perf_pmu_wrap (void );
+#else
+extern int perf_pmu_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int perf_pmu_lex (void);
+
+#define YY_DECL int perf_pmu_lex (void)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 38 "util/pmu.l"
+
+
+#line 315 "util/pmu-flex.h"
+#undef perf_pmu_IN_HEADER
+#endif /* perf_pmu_HEADER_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
new file mode 100644
index 0000000..514c82d
--- /dev/null
+++ b/tools/perf/util/pmu.c
@@ -0,0 +1,462 @@
+
+#include <linux/list.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+#include "sysfs.h"
+#include "util.h"
+#include "pmu.h"
+#include "parse-events.h"
+
+int perf_pmu_parse(struct list_head *list, char *name);
+extern FILE *perf_pmu_in;
+
+static LIST_HEAD(pmus);
+
+/*
+ * Parse & process all the sysfs attributes located under
+ * the directory specified in 'dir' parameter.
+ */
+static int pmu_format_parse(char *dir, struct list_head *head)
+{
+	struct dirent *evt_ent;
+	DIR *format_dir;
+	int ret = 0;
+
+	format_dir = opendir(dir);
+	if (!format_dir)
+		return -EINVAL;
+
+	while (!ret && (evt_ent = readdir(format_dir))) {
+		char path[PATH_MAX];
+		char *name = evt_ent->d_name;
+		FILE *file;
+
+		if (!strcmp(name, ".") || !strcmp(name, ".."))
+			continue;
+
+		snprintf(path, PATH_MAX, "%s/%s", dir, name);
+
+		ret = -EINVAL;
+		file = fopen(path, "r");
+		if (!file)
+			break;
+
+		perf_pmu_in = file;
+		ret = perf_pmu_parse(head, name);
+		fclose(file);
+	}
+
+	closedir(format_dir);
+	return ret;
+}
+
+/*
+ * Reading/parsing the default pmu format definition, which should be
+ * located at:
+ * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
+ */
+static int pmu_format(char *name, struct list_head *format)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return -1;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/format", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	if (pmu_format_parse(path, format))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Reading/parsing the default pmu type value, which should be
+ * located at:
+ * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
+ */
+static int pmu_type(char *name, __u32 *type)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+	FILE *file;
+	int ret = 0;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return -1;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/type", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	file = fopen(path, "r");
+	if (!file)
+		return -EINVAL;
+
+	if (1 != fscanf(file, "%u", type))
+		ret = -1;
+
+	fclose(file);
+	return ret;
+}
+
+static struct perf_pmu *pmu_lookup(char *name)
+{
+	struct perf_pmu *pmu;
+	LIST_HEAD(format);
+	__u32 type;
+
+	/*
+	 * The pmu data we store & need consists of the pmu
+	 * type value and format definitions. Load both right
+	 * now.
+	 */
+	if (pmu_format(name, &format))
+		return NULL;
+
+	if (pmu_type(name, &type))
+		return NULL;
+
+	pmu = zalloc(sizeof(*pmu));
+	if (!pmu)
+		return NULL;
+
+	INIT_LIST_HEAD(&pmu->format);
+	list_splice(&format, &pmu->format);
+	pmu->name = strdup(name);
+	pmu->type = type;
+	return pmu;
+}
+
+static struct perf_pmu *pmu_find(char *name)
+{
+	struct perf_pmu *pmu;
+
+	list_for_each_entry(pmu, &pmus, list)
+		if (!strcmp(pmu->name, name))
+			return pmu;
+
+	return NULL;
+}
+
+struct perf_pmu *perf_pmu__find(char *name)
+{
+	struct perf_pmu *pmu;
+
+	/*
+	 * Once PMU is loaded it stays in the list,
+	 * so we keep us from multiple reading/parsing
+	 * the pmu format definitions.
+	 */
+	pmu = pmu_find(name);
+	if (pmu)
+		return pmu;
+
+	return pmu_lookup(name);
+}
+
+static struct perf_pmu__format*
+pmu_find_format(struct list_head *formats, char *name)
+{
+	struct perf_pmu__format *format;
+
+	list_for_each_entry(format, formats, list)
+		if (!strcmp(format->name, name))
+			return format;
+
+	return NULL;
+}
+
+/*
+ * Returns value based on the format definition (format parameter)
+ * and unformated value (value parameter).
+ *
+ * TODO maybe optimize a little ;)
+ */
+static __u64 pmu_format_value(unsigned long *format, __u64 value)
+{
+	unsigned long fbit, vbit;
+	__u64 v = 0;
+
+	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
+
+		if (!test_bit(fbit, format))
+			continue;
+
+		if (!(value & (1llu << vbit++)))
+			continue;
+
+		v |= (1llu << fbit);
+	}
+
+	return v;
+}
+
+/*
+ * Setup one of config[12] attr members based on the
+ * user input data - temr parameter.
+ */
+static int pmu_config_term(struct list_head *formats,
+			   struct perf_event_attr *attr,
+			   struct parse_events__term *term)
+{
+	struct perf_pmu__format *format;
+	__u64 *vp;
+
+	/* Support only for numnerial terms. */
+	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+		return -EINVAL;
+
+	format = pmu_find_format(formats, term->config);
+	if (!format)
+		return -EINVAL;
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		vp = &attr->config;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		vp = &attr->config1;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		vp = &attr->config2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*vp |= pmu_format_value(format->bits, term->val.num);
+	return 0;
+}
+
+static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
+		      struct list_head *head_terms)
+{
+	struct parse_events__term *term, *h;
+
+	list_for_each_entry_safe(term, h, head_terms, list)
+		if (pmu_config_term(formats, attr, term))
+			return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Configures event's 'attr' parameter based on the:
+ * 1) users input - specified in terms parameter
+ * 2) pmu format definitions - specified by pmu parameter
+ */
+int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
+		     struct list_head *head_terms)
+{
+	attr->type = pmu->type;
+	return pmu_config(&pmu->format, attr, head_terms);
+}
+
+int perf_pmu__new_format(struct list_head *list, char *name,
+			 int config, unsigned long *bits)
+{
+	struct perf_pmu__format *format;
+
+	format = zalloc(sizeof(*format));
+	if (!format)
+		return -ENOMEM;
+
+	format->name = strdup(name);
+	format->value = config;
+	memcpy(format->bits, bits, sizeof(format->bits));
+
+	list_add_tail(&format->list, list);
+	return 0;
+}
+
+void perf_pmu__set_format(unsigned long *bits, long from, long to)
+{
+	long b;
+
+	if (!to)
+		to = from;
+
+	memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
+	for (b = from; b <= to; b++)
+		set_bit(b, bits);
+}
+
+/* Simulated format definitions. */
+static struct test_format {
+	const char *name;
+	const char *value;
+} test_formats[] = {
+	{ "krava01", "config:0-1,62-63\n", },
+	{ "krava02", "config:10-17\n", },
+	{ "krava03", "config:5\n", },
+	{ "krava11", "config1:0,2,4,6,8,20-28\n", },
+	{ "krava12", "config1:63\n", },
+	{ "krava13", "config1:45-47\n", },
+	{ "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
+	{ "krava22", "config2:8,18,48,58\n", },
+	{ "krava23", "config2:28-29,38\n", },
+};
+
+#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(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 *) "krava02",
+		.val.num = 170,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava03",
+		.val.num = 1,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava11",
+		.val.num = 27,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava12",
+		.val.num = 1,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava13",
+		.val.num = 2,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava21",
+		.val.num = 119,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava22",
+		.val.num = 11,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava23",
+		.val.num = 2,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+};
+#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
+
+/*
+ * Prepare format directory data, exported by kernel
+ * at /sys/bus/event_source/devices/<dev>/format.
+ */
+static char *test_format_dir_get(void)
+{
+	static char dir[PATH_MAX];
+	unsigned int i;
+
+	snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
+	if (!mkdtemp(dir))
+		return NULL;
+
+	for (i = 0; i < TEST_FORMATS_CNT; i++) {
+		static char name[PATH_MAX];
+		struct test_format *format = &test_formats[i];
+		FILE *file;
+
+		snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
+
+		file = fopen(name, "w");
+		if (!file)
+			return NULL;
+
+		if (1 != fwrite(format->value, strlen(format->value), 1, file))
+			break;
+
+		fclose(file);
+	}
+
+	return dir;
+}
+
+/* Cleanup format directory. */
+static int test_format_dir_put(char *dir)
+{
+	char buf[PATH_MAX];
+	snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
+	if (system(buf))
+		return -1;
+
+	snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
+	return system(buf);
+}
+
+static struct list_head *test_terms_list(void)
+{
+	static LIST_HEAD(terms);
+	unsigned int i;
+
+	for (i = 0; i < TERMS_CNT; i++)
+		list_add_tail(&test_terms[i].list, &terms);
+
+	return &terms;
+}
+
+#undef TERMS_CNT
+
+int perf_pmu__test(void)
+{
+	char *format = test_format_dir_get();
+	LIST_HEAD(formats);
+	struct list_head *terms = test_terms_list();
+	int ret;
+
+	if (!format)
+		return -EINVAL;
+
+	do {
+		struct perf_event_attr attr;
+
+		memset(&attr, 0, sizeof(attr));
+
+		ret = pmu_format_parse(format, &formats);
+		if (ret)
+			break;
+
+		ret = pmu_config(&formats, &attr, terms);
+		if (ret)
+			break;
+
+		ret = -EINVAL;
+
+		if (attr.config  != 0xc00000000002a823)
+			break;
+		if (attr.config1 != 0x8000400000000145)
+			break;
+		if (attr.config2 != 0x0400000020041d07)
+			break;
+
+		ret = 0;
+	} while (0);
+
+	test_format_dir_put(format);
+	return ret;
+}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
new file mode 100644
index 0000000..1ffdfb9
--- /dev/null
+++ b/tools/perf/util/pmu.h
@@ -0,0 +1,41 @@
+#ifndef __PMU_H
+#define __PMU_H
+
+#include <linux/bitops.h>
+#include <linux/perf_event.h>
+
+enum {
+	PERF_PMU_FORMAT_VALUE_CONFIG,
+	PERF_PMU_FORMAT_VALUE_CONFIG1,
+	PERF_PMU_FORMAT_VALUE_CONFIG2,
+};
+
+#define PERF_PMU_FORMAT_BITS 64
+
+struct perf_pmu__format {
+	char *name;
+	int value;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+	struct list_head list;
+};
+
+struct perf_pmu {
+	char *name;
+	__u32 type;
+	struct list_head format;
+	struct list_head list;
+};
+
+struct perf_pmu *perf_pmu__find(char *name);
+int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
+		     struct list_head *head_terms);
+
+int perf_pmu_wrap(void);
+void perf_pmu_error(struct list_head *list, char *name, char const *msg);
+
+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);
+
+int perf_pmu__test(void);
+#endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.l b/tools/perf/util/pmu.l
new file mode 100644
index 0000000..a15d9fb
--- /dev/null
+++ b/tools/perf/util/pmu.l
@@ -0,0 +1,43 @@
+%option prefix="perf_pmu_"
+
+%{
+#include <stdlib.h>
+#include <linux/bitops.h>
+#include "pmu.h"
+#include "pmu-bison.h"
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(perf_pmu_text, NULL, base);
+	if (errno)
+		return PP_ERROR;
+
+	perf_pmu_lval.num = num;
+	return PP_VALUE;
+}
+
+%}
+
+num_dec         [0-9]+
+
+%%
+
+{num_dec}	{ return value(10); }
+config		{ return PP_CONFIG; }
+config1		{ return PP_CONFIG1; }
+config2		{ return PP_CONFIG2; }
+-		{ return '-'; }
+:		{ return ':'; }
+,		{ return ','; }
+.		{ ; }
+\n		{ ; }
+
+%%
+
+int perf_pmu_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
new file mode 100644
index 0000000..20ea77e
--- /dev/null
+++ b/tools/perf/util/pmu.y
@@ -0,0 +1,93 @@
+
+%name-prefix "perf_pmu_"
+%parse-param {struct list_head *format}
+%parse-param {char *name}
+
+%{
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/bitmap.h>
+#include <string.h>
+#include "pmu.h"
+
+extern int perf_pmu_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+        if (val) \
+                YYABORT; \
+} while (0)
+
+%}
+
+%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
+%token PP_VALUE PP_ERROR
+%type <num> PP_VALUE
+%type <bits> bit_term
+%type <bits> bits
+
+%union
+{
+	unsigned long num;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+}
+
+%%
+
+format:
+format format_term
+|
+format_term
+
+format_term:
+PP_CONFIG ':' bits
+{
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG,
+				      $3));
+}
+|
+PP_CONFIG1 ':' bits
+{
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG1,
+				      $3));
+}
+|
+PP_CONFIG2 ':' bits
+{
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG2,
+				      $3));
+}
+
+bits:
+bits ',' bit_term
+{
+	bitmap_or($$, $1, $3, 64);
+}
+|
+bit_term
+{
+	memcpy($$, $1, sizeof($1));
+}
+
+bit_term:
+PP_VALUE '-' PP_VALUE
+{
+	perf_pmu__set_format($$, $1, $3);
+}
+|
+PP_VALUE
+{
+	perf_pmu__set_format($$, $1, 0);
+}
+
+%%
+
+void perf_pmu_error(struct list_head *list __used,
+		    char *name __used,
+		    char const *msg __used)
+{
+}
-- 
1.7.4.4


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

* [PATCH 9/9] perf, tool: Add support to specify pmu style event
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (7 preceding siblings ...)
  2012-01-27 14:34                         ` [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition Jiri Olsa
@ 2012-01-27 14:34                         ` Jiri Olsa
  2012-02-13 13:13                         ` [PATCHv4 0/9] perf tool: parser generator for events parsing Jiri Olsa
  2012-02-14 16:28                         ` Peter Zijlstra
  10 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-01-27 14:34 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel, Jiri Olsa

Added new event rule to the event definition grammar:

event_def: event_pmu |
           ...
event_pmu: PE_NAME '/' event_config '/'

Using this rule, event could be now specified like:
  cpu/config=1,config1=2,config2=3/u

where pmu name 'cpu' is looked up via following path:
  ${sysfs_mount}/bus/event_source/devices/${pmu}

and config options are bound to the pmu's format definiton:
  ${sysfs_mount}/bus/event_source/devices/${pmu}/format

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c            |   18 ++++
 tools/perf/util/parse-events-bison.c |  187 ++++++++++++++++++----------------
 tools/perf/util/parse-events.c       |   19 ++++
 tools/perf/util/parse-events.h       |    2 +
 tools/perf/util/parse-events.y       |   10 ++-
 5 files changed, 149 insertions(+), 87 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 1969d3f..ecfbf20 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -873,6 +873,20 @@ static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
 	return test__checkevent_genhw(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", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config", 3 == evsel->attr.config2);
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -954,6 +968,10 @@ static struct test__event_st {
 		.name  = "L1-dcache-load-miss:kp",
 		.check = test__checkevent_genhw_modifier,
 	},
+	{
+		.name  = "cpu/config=1,config1=2,config2=3/u",
+		.check = test__checkevent_pmu,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
index 32adc40..d3f4e62 100644
--- a/tools/perf/util/parse-events-bison.c
+++ b/tools/perf/util/parse-events-bison.c
@@ -380,18 +380,18 @@ union yyalloc
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  23
+#define YYFINAL  25
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   35
+#define YYLAST   43
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  19
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  14
+#define YYNNTS  15
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  30
+#define YYNRULES  32
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  50
+#define YYNSTATES  54
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -437,34 +437,34 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint8 yyprhs[] =
 {
-       0,     0,     3,     7,     9,    12,    14,    16,    19,    21,
-      24,    27,    30,    35,    38,    44,    48,    50,    56,    60,
-      64,    68,    70,    74,    76,    80,    84,    86,    87,    89,
-      91
+       0,     0,     3,     7,     9,    12,    14,    16,    18,    21,
+      23,    26,    29,    32,    37,    42,    45,    51,    55,    57,
+      63,    67,    71,    75,    77,    81,    83,    87,    91,    93,
+      94,    96,    98
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
       20,     0,    -1,    20,    14,    21,    -1,    21,    -1,    22,
-       7,    -1,    22,    -1,    23,    -1,    24,    31,    -1,    25,
-      -1,    26,    31,    -1,    27,    31,    -1,    28,    31,    -1,
-       4,    15,    29,    15,    -1,     4,    32,    -1,     9,    16,
-      10,    16,    10,    -1,     9,    16,    10,    -1,     9,    -1,
-      11,     3,    17,     8,    31,    -1,    11,     3,    31,    -1,
-       6,    17,     6,    -1,     3,    17,     3,    -1,     5,    -1,
-      29,    14,    30,    -1,    30,    -1,     6,    18,     6,    -1,
-       6,    18,     3,    -1,    17,    -1,    -1,    15,    -1,    17,
-      -1,    -1
+       7,    -1,    22,    -1,    23,    -1,    24,    -1,    25,    32,
+      -1,    26,    -1,    27,    32,    -1,    28,    32,    -1,    29,
+      32,    -1,     6,    15,    30,    15,    -1,     4,    15,    30,
+      15,    -1,     4,    33,    -1,     9,    16,    10,    16,    10,
+      -1,     9,    16,    10,    -1,     9,    -1,    11,     3,    17,
+       8,    32,    -1,    11,     3,    32,    -1,     6,    17,     6,
+      -1,     3,    17,     3,    -1,     5,    -1,    30,    14,    31,
+      -1,    31,    -1,     6,    18,     6,    -1,     6,    18,     3,
+      -1,    17,    -1,    -1,    15,    -1,    17,    -1,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
        0,    53,    53,    53,    56,    61,    63,    64,    65,    66,
-      67,    68,    71,    80,    89,    94,    99,   105,   110,   116,
-     122,   128,   134,   144,   156,   165,   174,   174,   176,   176,
-     176
+      67,    68,    69,    72,    79,    88,    97,   102,   107,   113,
+     118,   124,   130,   136,   142,   152,   164,   173,   182,   182,
+     184,   184,   184
 };
 #endif
 
@@ -477,7 +477,7 @@ static const char *const yytname[] =
   "PE_NAME", "PE_MODIFIER_EVENT", "PE_MODIFIER_BP", "PE_NAME_CACHE_TYPE",
   "PE_NAME_CACHE_OP_RESULT", "PE_PREFIX_MEM", "PE_PREFIX_RAW", "PE_ERROR",
   "','", "'/'", "'-'", "':'", "'='", "$accept", "events", "event",
-  "event_def", "event_legacy_symbol", "event_legacy_cache",
+  "event_def", "event_pmu", "event_legacy_symbol", "event_legacy_cache",
   "event_legacy_mem", "event_legacy_tracepoint", "event_legacy_numeric",
   "event_legacy_raw", "event_config", "event_term", "sep_dc",
   "sep_slash_dc", 0
@@ -498,18 +498,18 @@ static const yytype_uint16 yytoknum[] =
 static const yytype_uint8 yyr1[] =
 {
        0,    19,    20,    20,    21,    21,    22,    22,    22,    22,
-      22,    22,    23,    23,    24,    24,    24,    25,    25,    26,
-      27,    28,    29,    29,    30,    30,    31,    31,    32,    32,
-      32
+      22,    22,    22,    23,    24,    24,    25,    25,    25,    26,
+      26,    27,    28,    29,    30,    30,    31,    31,    32,    32,
+      33,    33,    33
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     3,     1,     2,     1,     1,     2,     1,     2,
-       2,     2,     4,     2,     5,     3,     1,     5,     3,     3,
-       3,     1,     3,     1,     3,     3,     1,     0,     1,     1,
-       0
+       0,     2,     3,     1,     2,     1,     1,     1,     2,     1,
+       2,     2,     2,     4,     4,     2,     5,     3,     1,     5,
+       3,     3,     3,     1,     3,     1,     3,     3,     1,     0,
+       1,     1,     0
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -517,37 +517,39 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,    30,    21,     0,    16,     0,     0,     3,     5,
-       6,    27,     8,    27,    27,    27,     0,    28,    29,    13,
-       0,     0,    27,     1,     0,     4,    26,     7,     9,    10,
-      11,    20,     0,     0,    23,    19,    15,    26,    18,     2,
-       0,     0,    12,     0,    27,    25,    24,    22,    14,    17
+       0,     0,    32,    23,     0,    18,     0,     0,     3,     5,
+       6,     7,    29,     9,    29,    29,    29,     0,    30,    31,
+      15,     0,     0,     0,    29,     1,     0,     4,    28,     8,
+      10,    11,    12,    22,     0,     0,    25,     0,    21,    17,
+      28,    20,     2,     0,     0,    14,    13,     0,    29,    27,
+      26,    24,    16,    19
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
       -1,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      33,    34,    27,    19
+      16,    35,    36,    29,    20
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -14
+#define YYPACT_NINF -15
 static const yytype_int8 yypact[] =
 {
-       1,    -3,    -2,   -14,    -1,     6,    17,     3,   -14,    14,
-     -14,     7,   -14,     7,     7,     7,    20,    19,   -14,   -14,
-      21,    16,    11,   -14,     1,   -14,   -14,   -14,   -14,   -14,
-     -14,   -14,    12,     4,   -14,   -14,    13,    24,   -14,   -14,
-       5,    19,   -14,    23,     7,   -14,   -14,   -14,   -14,   -14
+       2,   -13,    -1,   -15,     4,    11,    12,     3,   -15,    13,
+     -15,   -15,     1,   -15,     1,     1,     1,    23,    22,   -15,
+     -15,    22,    24,    19,    14,   -15,     2,   -15,   -15,   -15,
+     -15,   -15,   -15,   -15,    15,     8,   -15,    10,   -15,    16,
+      27,   -15,   -15,     6,    22,   -15,   -15,    26,     1,   -15,
+     -15,   -15,   -15,   -15
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -14,   -14,    10,   -14,   -14,   -14,   -14,   -14,   -14,   -14,
-     -14,    -6,   -13,   -14
+     -15,   -15,    17,   -15,   -15,   -15,   -15,   -15,   -15,   -15,
+     -15,    18,    -7,   -14,   -15
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -557,18 +559,20 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      28,    29,    30,    23,     1,     2,     3,     4,    45,    38,
-       5,    46,     6,    17,    16,    18,    20,    24,    41,    42,
-      22,    25,    21,    31,    26,    32,    36,    35,    37,    43,
-      40,    49,    44,    48,    39,    47
+      30,    31,    32,    25,    17,     1,     2,     3,     4,    49,
+      41,     5,    50,     6,    18,    24,    19,    26,    28,    21,
+      27,    22,    44,    45,    44,    46,    33,    23,    34,    39,
+      38,    40,    47,    43,    53,    48,    52,    51,     0,    37,
+       0,     0,     0,    42
 };
 
-static const yytype_uint8 yycheck[] =
+static const yytype_int8 yycheck[] =
 {
-      13,    14,    15,     0,     3,     4,     5,     6,     3,    22,
-       9,     6,    11,    15,    17,    17,    17,    14,    14,    15,
-       3,     7,    16,     3,    17,     6,    10,     6,    17,    16,
-      18,    44,     8,    10,    24,    41
+      14,    15,    16,     0,    17,     3,     4,     5,     6,     3,
+      24,     9,     6,    11,    15,     3,    17,    14,    17,    15,
+       7,    17,    14,    15,    14,    15,     3,    16,     6,    10,
+       6,    17,    16,    18,    48,     8,    10,    44,    -1,    21,
+      -1,    -1,    -1,    26
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -576,10 +580,11 @@ static const yytype_uint8 yycheck[] =
 static const yytype_uint8 yystos[] =
 {
        0,     3,     4,     5,     6,     9,    11,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    17,    15,    17,    32,
-      17,    16,     3,     0,    14,     7,    17,    31,    31,    31,
-      31,     3,     6,    29,    30,     6,    10,    17,    31,    21,
-      18,    14,    15,    16,     8,     3,     6,    30,    10,    31
+      23,    24,    25,    26,    27,    28,    29,    17,    15,    17,
+      33,    15,    17,    16,     3,     0,    14,     7,    17,    32,
+      32,    32,    32,     3,     6,    30,    31,    30,     6,    10,
+      17,    32,    21,    18,    14,    15,    15,    16,     8,     3,
+       6,    31,    10,    32
 };
 
 #define yyerrok		(yyerrstatus = 0)
@@ -1421,10 +1426,20 @@ yyreduce:
 ;}
     break;
 
-  case 12:
+  case 13:
+
+/* Line 1464 of yacc.c  */
+#line 73 "util/parse-events.y"
+    {
+	ABORT_ON(parse_events_add_pmu(list, idx, (yyvsp[(1) - (4)].str), (yyvsp[(3) - (4)].head)));
+	parse_events__free_terms((yyvsp[(3) - (4)].head));
+;}
+    break;
+
+  case 14:
 
 /* Line 1464 of yacc.c  */
-#line 72 "util/parse-events.y"
+#line 80 "util/parse-events.y"
     {
 	int type = (yyvsp[(1) - (4)].num) >> 16;
 	int config = (yyvsp[(1) - (4)].num) & 255;
@@ -1434,10 +1449,10 @@ yyreduce:
 ;}
     break;
 
-  case 13:
+  case 15:
 
 /* Line 1464 of yacc.c  */
-#line 81 "util/parse-events.y"
+#line 89 "util/parse-events.y"
     {
 	int type = (yyvsp[(1) - (2)].num) >> 16;
 	int config = (yyvsp[(1) - (2)].num) & 255;
@@ -1446,82 +1461,82 @@ yyreduce:
 ;}
     break;
 
-  case 14:
+  case 16:
 
 /* Line 1464 of yacc.c  */
-#line 90 "util/parse-events.y"
+#line 98 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
 ;}
     break;
 
-  case 15:
+  case 17:
 
 /* Line 1464 of yacc.c  */
-#line 95 "util/parse-events.y"
+#line 103 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
 ;}
     break;
 
-  case 16:
+  case 18:
 
 /* Line 1464 of yacc.c  */
-#line 100 "util/parse-events.y"
+#line 108 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
 ;}
     break;
 
-  case 17:
+  case 19:
 
 /* Line 1464 of yacc.c  */
-#line 106 "util/parse-events.y"
+#line 114 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
 ;}
     break;
 
-  case 18:
+  case 20:
 
 /* Line 1464 of yacc.c  */
-#line 111 "util/parse-events.y"
+#line 119 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
 ;}
     break;
 
-  case 19:
+  case 21:
 
 /* Line 1464 of yacc.c  */
-#line 117 "util/parse-events.y"
+#line 125 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_tracepoint(list, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
 ;}
     break;
 
-  case 20:
+  case 22:
 
 /* Line 1464 of yacc.c  */
-#line 123 "util/parse-events.y"
+#line 131 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
 ;}
     break;
 
-  case 21:
+  case 23:
 
 /* Line 1464 of yacc.c  */
-#line 129 "util/parse-events.y"
+#line 137 "util/parse-events.y"
     {
 	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
 ;}
     break;
 
-  case 22:
+  case 24:
 
 /* Line 1464 of yacc.c  */
-#line 135 "util/parse-events.y"
+#line 143 "util/parse-events.y"
     {
 	struct list_head *head = (yyvsp[(1) - (3)].head);
 	struct parse_events__term *term = (yyvsp[(3) - (3)].term);
@@ -1532,10 +1547,10 @@ yyreduce:
 ;}
     break;
 
-  case 23:
+  case 25:
 
 /* Line 1464 of yacc.c  */
-#line 145 "util/parse-events.y"
+#line 153 "util/parse-events.y"
     {
 	struct list_head *head = malloc(sizeof(*head));
 	struct parse_events__term *term = (yyvsp[(1) - (1)].term);
@@ -1547,10 +1562,10 @@ yyreduce:
 ;}
     break;
 
-  case 24:
+  case 26:
 
 /* Line 1464 of yacc.c  */
-#line 157 "util/parse-events.y"
+#line 165 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
@@ -1560,10 +1575,10 @@ yyreduce:
 ;}
     break;
 
-  case 25:
+  case 27:
 
 /* Line 1464 of yacc.c  */
-#line 166 "util/parse-events.y"
+#line 174 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
@@ -1576,7 +1591,7 @@ yyreduce:
 
 
 /* Line 1464 of yacc.c  */
-#line 1580 "util/parse-events-bison.c"
+#line 1595 "util/parse-events-bison.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1788,7 +1803,7 @@ yyreturn:
 
 
 /* Line 1684 of yacc.c  */
-#line 178 "util/parse-events.y"
+#line 186 "util/parse-events.y"
 
 
 void parse_events_error(struct list_head *list __used, int *idx __used,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 7423049..cce8b7a 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -12,6 +12,7 @@
 #include "header.h"
 #include "debugfs.h"
 #include "parse-events-flex.h"
+#include "pmu.h"
 
 #define MAX_NAME_LEN 100
 
@@ -632,6 +633,24 @@ 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,
+			 char *name, struct list_head *head_config)
+{
+	struct perf_event_attr attr;
+	struct perf_pmu *pmu;
+
+	pmu = perf_pmu__find(name);
+	if (!pmu)
+		return -EINVAL;
+
+	memset(&attr, 0, sizeof(attr));
+
+	if (perf_pmu__config(pmu, &attr, head_config))
+		return -EINVAL;
+
+	return add_event(list, idx, &attr, (char *) "pmu");
+}
+
 int parse_events_modifier(struct list_head *list, char *str)
 {
 	struct perf_evsel *evsel;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2737f1e..0ebc68c 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -65,6 +65,8 @@ int parse_events_add_cache(struct list_head *list, int *idx,
 			   char *type, char *op_result1, char *op_result2);
 int parse_events_add_breakpoint(struct list_head *list, int *idx,
 				void *ptr, char *type);
+int parse_events_add_pmu(struct list_head *list, int *idx,
+			 char *pmu , struct list_head *head_config);
 void parse_events_error(struct list_head *list, int *idx,
 			char const *msg);
 
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 0be12dc..588f115 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -60,13 +60,21 @@ event_def PE_MODIFIER_EVENT
 |
 event_def
 
-event_def: event_legacy_symbol |
+event_def: event_pmu |
+	   event_legacy_symbol |
 	   event_legacy_cache sep_dc |
 	   event_legacy_mem |
 	   event_legacy_tracepoint sep_dc |
 	   event_legacy_numeric sep_dc |
 	   event_legacy_raw sep_dc
 
+event_pmu:
+PE_NAME '/' event_config '/'
+{
+	ABORT_ON(parse_events_add_pmu(list, idx, $1, $3));
+	parse_events__free_terms($3);
+}
+
 event_legacy_symbol:
 PE_VALUE_SYM '/' event_config '/'
 {
-- 
1.7.4.4


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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-01-27 14:34                         ` [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device Jiri Olsa
@ 2012-01-27 21:08                           ` Corey Ashford
  2012-01-27 21:19                             ` Peter Zijlstra
  2012-01-30  9:52                             ` Jiri Olsa
  0 siblings, 2 replies; 91+ messages in thread
From: Corey Ashford @ 2012-01-27 21:08 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, a.p.zijlstra, mingo, paulus, linux-kernel

On 01/27/2012 06:34 AM, Jiri Olsa wrote:
> Adding sysfs group 'format' attribute for pmu device that
> contains a syntax description on how to construct raw events.
> 
> The event configuration is described in following
> struct pefr_event_attr attributes:
> 
>   config
>   config1
>   config2
> 
> Each sysfs attribute within the format attribute group,
> describes mapping of name and bitfield definition within
> one of above attributes.
> 
> eg:
>   "/sys/...<dev>/format/event" contains "config:0-7"
>   "/sys/...<dev>/format/umask" contains "config:8-15"
>   "/sys/...<dev>/format/usr"   contains "config:16"
> 
> the attribute value syntax is:
> 
>   line:      config ':' bits
>   config:    'config' | 'config1' | 'config2"
>   bits:      bits ',' bit_term | bit_term
>   bit_term:  VALUE '-' VALUE | VALUE
> 
> Adding format_defined bool to the struct pmu to specify wether
> pmu defines its own set of format attributes (within the
> attr_groups member) or the default format attributes should be
> used:
>   "/sys/...<dev>/format/config"  contains "config:0-63"
>   "/sys/...<dev>/format/config1" contains "config1:0-63"
>   "/sys/...<dev>/format/config2" contains "config2:0-63"


Hi Jiri,

I've been out of the perf_events loop for some time, but I did finally
notice your patch series thread.

I think what you've done is very good and I'm excited to see progress in
this area.  However, it's not clear to me that it is as generalized as
it needs to be for some PMU's.  I say this because not all events on a
given PMU will have the same needed fields.

As an example, the IBM PowerEN processor has roughly 20 different PMU's
on it.  Some of those PMU's are quite complex and divide their events up
into subsets, each with different fields.  For example, some events may
have a PID matching field, and others may have an bus number matching
field, or matching mode field, etc.  The fields are different widths,
and may overlap in the config/1/2 space.

It seems that there are two approaches you could take:

1) Keep your format, but allow the fields to overlap in the bit space.
For example:

  "/sys/...<dev>/format/event" contains "config:0-7"
  "/sys/...<dev>/format/pidmatch" contains "config:8-15"
  "/sys/...<dev>/format/busmatch"   contains "config:8-13"

Note that busmatch overlaps pidmatch

2) Create event groups that have their overlapping config space
separated out:

  "/sys/...<dev>/format/event" contains "config:0-7"

  "/sys/...<dev>.1/format/pidmatch" contains "config:8-15"

  "/sys/...<dev>.2/format/busmatch"   contains "config:8-13"


Notice the .1 and .2 on the <dev>.

This might help the user understand which fields go together.  I'm not
sold on the .1 syntax... you could do it as <dev>.<event-group-name>/ or
<dev>/<event-group-name>/... or whatever seems to make the most sense
and is relatively easy to implement and use.

- Corey


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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-01-27 21:08                           ` Corey Ashford
@ 2012-01-27 21:19                             ` Peter Zijlstra
  2012-02-01  0:47                               ` Corey Ashford
  2012-01-30  9:52                             ` Jiri Olsa
  1 sibling, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-01-27 21:19 UTC (permalink / raw)
  To: Corey Ashford; +Cc: Jiri Olsa, acme, mingo, paulus, linux-kernel

On Fri, 2012-01-27 at 13:08 -0800, Corey Ashford wrote:
> s an example, the IBM PowerEN processor has roughly 20 different PMU's
> on it.  Some of those PMU's are quite complex and divide their events up
> into subsets, each with different fields.  For example, some events may
> have a PID matching field, and others may have an bus number matching
> field, or matching mode field, etc.  The fields are different widths,
> and may overlap in the config/1/2 space.
> 
> It seems that there are two approaches you could take:
> 
> 1) Keep your format, but allow the fields to overlap in the bit space.
> For example:
> 
>   "/sys/...<dev>/format/event" contains "config:0-7"
>   "/sys/...<dev>/format/pidmatch" contains "config:8-15"
>   "/sys/...<dev>/format/busmatch"   contains "config:8-13"
> 
> Note that busmatch overlaps pidmatch
> 
> 2) Create event groups that have their overlapping config space
> separated out:
> 
>   "/sys/...<dev>/format/event" contains "config:0-7"
> 
>   "/sys/...<dev>.1/format/pidmatch" contains "config:8-15"
> 
>   "/sys/...<dev>.2/format/busmatch"   contains "config:8-13"
> 
> 
> Notice the .1 and .2 on the <dev>.
> 
> This might help the user understand which fields go together.  I'm not
> sold on the .1 syntax... you could do it as <dev>.<event-group-name>/ or
> <dev>/<event-group-name>/... or whatever seems to make the most sense
> and is relatively easy to implement and use. 

Why try and stuff those 20 in a single driver? Have 20 drivers and each
their own format/ hierarchy.

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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-01-27 21:08                           ` Corey Ashford
  2012-01-27 21:19                             ` Peter Zijlstra
@ 2012-01-30  9:52                             ` Jiri Olsa
  2012-02-01  1:25                               ` Corey Ashford
  1 sibling, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-01-30  9:52 UTC (permalink / raw)
  To: Corey Ashford, acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel

On Fri, Jan 27, 2012 at 01:08:38PM -0800, Corey Ashford wrote:
> On 01/27/2012 06:34 AM, Jiri Olsa wrote:
> > Adding sysfs group 'format' attribute for pmu device that
> > contains a syntax description on how to construct raw events.
> > 
> > The event configuration is described in following
> > struct pefr_event_attr attributes:
> > 
> >   config
> >   config1
> >   config2
> > 
> > Each sysfs attribute within the format attribute group,
> > describes mapping of name and bitfield definition within
> > one of above attributes.
> > 
> > eg:
> >   "/sys/...<dev>/format/event" contains "config:0-7"
> >   "/sys/...<dev>/format/umask" contains "config:8-15"
> >   "/sys/...<dev>/format/usr"   contains "config:16"
> > 
> > the attribute value syntax is:
> > 
> >   line:      config ':' bits
> >   config:    'config' | 'config1' | 'config2"
> >   bits:      bits ',' bit_term | bit_term
> >   bit_term:  VALUE '-' VALUE | VALUE
> > 
> > Adding format_defined bool to the struct pmu to specify wether
> > pmu defines its own set of format attributes (within the
> > attr_groups member) or the default format attributes should be
> > used:
> >   "/sys/...<dev>/format/config"  contains "config:0-63"
> >   "/sys/...<dev>/format/config1" contains "config1:0-63"
> >   "/sys/...<dev>/format/config2" contains "config2:0-63"
> 
> 
> Hi Jiri,
> 
> I've been out of the perf_events loop for some time, but I did finally
> notice your patch series thread.
> 
> I think what you've done is very good and I'm excited to see progress in
> this area.  However, it's not clear to me that it is as generalized as
> it needs to be for some PMU's.  I say this because not all events on a
> given PMU will have the same needed fields.

ok, I wasn't aware of this

> 
> As an example, the IBM PowerEN processor has roughly 20 different PMU's
> on it.  Some of those PMU's are quite complex and divide their events up
> into subsets, each with different fields.  For example, some events may
> have a PID matching field, and others may have an bus number matching
> field, or matching mode field, etc.  The fields are different widths,
> and may overlap in the config/1/2 space.
> 
> It seems that there are two approaches you could take:
> 
> 1) Keep your format, but allow the fields to overlap in the bit space.
> For example:
> 
>   "/sys/...<dev>/format/event" contains "config:0-7"
>   "/sys/...<dev>/format/pidmatch" contains "config:8-15"
>   "/sys/...<dev>/format/busmatch"   contains "config:8-13"
> 
> Note that busmatch overlaps pidmatch

currently format fields definitions may overlap, there's no check
to prevent that

> 
> 2) Create event groups that have their overlapping config space
> separated out:
> 
>   "/sys/...<dev>/format/event" contains "config:0-7"
> 
>   "/sys/...<dev>.1/format/pidmatch" contains "config:8-15"
> 
>   "/sys/...<dev>.2/format/busmatch"   contains "config:8-13"
> 
> 
> Notice the .1 and .2 on the <dev>.
> 
> This might help the user understand which fields go together.  I'm not
> sold on the .1 syntax... you could do it as <dev>.<event-group-name>/ or
> <dev>/<event-group-name>/... or whatever seems to make the most sense
> and is relatively easy to implement and use.

Though I'm not sure we want allow separate devices inside single pmu,
I think we could have multiple format groups if necessary :)

some quick ideas:

1) having format group attribute under format like:
   <dev>/format/group1/..
   <dev>/format/group2/..
   <dev>/format/group2/..
   ...

2) having format group name within the format attribute name like:
   <dev>/format/group1-krava1
   <dev>/format/group1-krava2
   <dev>/format/group2-krava3
   ...

3) having group name inside the foramt attributes like:
   cat <dev>/format/group1-krava1
   group1 config:0-1,62-63


I think I like the most ad 1)..

We could have something like default format directory if there's
only a single format group, like:
   <dev>/format/default/krava1
   <dev>/format/default/krava2
   ...

The perf event syntax could have something like '::' to classify
format attribute with a group like (none would go to default dir):

   cpu/group1::config=1,group2::config1=2,config2=3/u
or 
   cpu::group1/config=1,config1=2,config2=3/u


Or we could say the format field names could not overlap and then
we dont need to specify group at all :) It'd be just for user's
awareness..

Any idea if we at all want to go this way? ;)

thanks,
jirka

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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-01-27 21:19                             ` Peter Zijlstra
@ 2012-02-01  0:47                               ` Corey Ashford
  0 siblings, 0 replies; 91+ messages in thread
From: Corey Ashford @ 2012-02-01  0:47 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, acme, mingo, paulus, linux-kernel, Carl Love

On 01/27/2012 01:19 PM, Peter Zijlstra wrote:
> On Fri, 2012-01-27 at 13:08 -0800, Corey Ashford wrote:
>> s an example, the IBM PowerEN processor has roughly 20 different PMU's
>> on it.  Some of those PMU's are quite complex and divide their events up
>> into subsets, each with different fields.  For example, some events may
>> have a PID matching field, and others may have an bus number matching
>> field, or matching mode field, etc.  The fields are different widths,
>> and may overlap in the config/1/2 space.
>>
>> It seems that there are two approaches you could take:
>>
>> 1) Keep your format, but allow the fields to overlap in the bit space.
>> For example:
>>
>>   "/sys/...<dev>/format/event" contains "config:0-7"
>>   "/sys/...<dev>/format/pidmatch" contains "config:8-15"
>>   "/sys/...<dev>/format/busmatch"   contains "config:8-13"
>>
>> Note that busmatch overlaps pidmatch
>>
>> 2) Create event groups that have their overlapping config space
>> separated out:
>>
>>   "/sys/...<dev>/format/event" contains "config:0-7"
>>
>>   "/sys/...<dev>.1/format/pidmatch" contains "config:8-15"
>>
>>   "/sys/...<dev>.2/format/busmatch"   contains "config:8-13"
>>
>>
>> Notice the .1 and .2 on the <dev>.
>>
>> This might help the user understand which fields go together.  I'm not
>> sold on the .1 syntax... you could do it as <dev>.<event-group-name>/ or
>> <dev>/<event-group-name>/... or whatever seems to make the most sense
>> and is relatively easy to implement and use. 
> 
> Why try and stuff those 20 in a single driver? Have 20 drivers and each
> their own format/ hierarchy.

I'm sure that could work.  Since sysfs seems to be fairly independent
(if necessary) of the hardware structure, I suppose this wouldn't be a
problem.

What do you think of Jiri's (Jirka's ?) other ideas of subdividing the
format directory?

- Corey


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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-01-30  9:52                             ` Jiri Olsa
@ 2012-02-01  1:25                               ` Corey Ashford
  2012-02-01 13:13                                 ` Jiri Olsa
  2012-02-01 13:36                                 ` Peter Zijlstra
  0 siblings, 2 replies; 91+ messages in thread
From: Corey Ashford @ 2012-02-01  1:25 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, a.p.zijlstra, mingo, paulus, linux-kernel

On 01/30/2012 01:52 AM, Jiri Olsa wrote:
> On Fri, Jan 27, 2012 at 01:08:38PM -0800, Corey Ashford wrote:
>> On 01/27/2012 06:34 AM, Jiri Olsa wrote:
>>> Adding sysfs group 'format' attribute for pmu device that
>>> contains a syntax description on how to construct raw events.
>>>
>>> The event configuration is described in following
>>> struct pefr_event_attr attributes:
>>>
>>>   config
>>>   config1
>>>   config2
>>>
>>> Each sysfs attribute within the format attribute group,
>>> describes mapping of name and bitfield definition within
>>> one of above attributes.
>>>
>>> eg:
>>>   "/sys/...<dev>/format/event" contains "config:0-7"
>>>   "/sys/...<dev>/format/umask" contains "config:8-15"
>>>   "/sys/...<dev>/format/usr"   contains "config:16"
>>>
>>> the attribute value syntax is:
>>>
>>>   line:      config ':' bits
>>>   config:    'config' | 'config1' | 'config2"
>>>   bits:      bits ',' bit_term | bit_term
>>>   bit_term:  VALUE '-' VALUE | VALUE
>>>
>>> Adding format_defined bool to the struct pmu to specify wether
>>> pmu defines its own set of format attributes (within the
>>> attr_groups member) or the default format attributes should be
>>> used:
>>>   "/sys/...<dev>/format/config"  contains "config:0-63"
>>>   "/sys/...<dev>/format/config1" contains "config1:0-63"
>>>   "/sys/...<dev>/format/config2" contains "config2:0-63"
>>
>>
>> Hi Jiri,
>>
>> I've been out of the perf_events loop for some time, but I did finally
>> notice your patch series thread.
>>
>> I think what you've done is very good and I'm excited to see progress in
>> this area.  However, it's not clear to me that it is as generalized as
>> it needs to be for some PMU's.  I say this because not all events on a
>> given PMU will have the same needed fields.
> 
> ok, I wasn't aware of this
> 
>>
>> As an example, the IBM PowerEN processor has roughly 20 different PMU's
>> on it.  Some of those PMU's are quite complex and divide their events up
>> into subsets, each with different fields.  For example, some events may
>> have a PID matching field, and others may have an bus number matching
>> field, or matching mode field, etc.  The fields are different widths,
>> and may overlap in the config/1/2 space.
>>
>> It seems that there are two approaches you could take:
>>
>> 1) Keep your format, but allow the fields to overlap in the bit space.
>> For example:
>>
>>   "/sys/...<dev>/format/event" contains "config:0-7"
>>   "/sys/...<dev>/format/pidmatch" contains "config:8-15"
>>   "/sys/...<dev>/format/busmatch"   contains "config:8-13"
>>
>> Note that busmatch overlaps pidmatch
> 
> currently format fields definitions may overlap, there's no check
> to prevent that
> 
>>
>> 2) Create event groups that have their overlapping config space
>> separated out:
>>
>>   "/sys/...<dev>/format/event" contains "config:0-7"
>>
>>   "/sys/...<dev>.1/format/pidmatch" contains "config:8-15"
>>
>>   "/sys/...<dev>.2/format/busmatch"   contains "config:8-13"
>>
>>
>> Notice the .1 and .2 on the <dev>.
>>
>> This might help the user understand which fields go together.  I'm not
>> sold on the .1 syntax... you could do it as <dev>.<event-group-name>/ or
>> <dev>/<event-group-name>/... or whatever seems to make the most sense
>> and is relatively easy to implement and use.
> 
> Though I'm not sure we want allow separate devices inside single pmu,
> I think we could have multiple format groups if necessary :)
> 
> some quick ideas:
> 
> 1) having format group attribute under format like:
>    <dev>/format/group1/..
>    <dev>/format/group2/..
>    <dev>/format/group2/..
>    ...
> 
> 2) having format group name within the format attribute name like:
>    <dev>/format/group1-krava1
>    <dev>/format/group1-krava2
>    <dev>/format/group2-krava3
>    ...
> 
> 3) having group name inside the foramt attributes like:
>    cat <dev>/format/group1-krava1
>    group1 config:0-1,62-63
> 
> 
> I think I like the most ad 1)..
> 
> We could have something like default format directory if there's
> only a single format group, like:
>    <dev>/format/default/krava1
>    <dev>/format/default/krava2
>    ...
> 
> The perf event syntax could have something like '::' to classify
> format attribute with a group like (none would go to default dir):
> 
>    cpu/group1::config=1,group2::config1=2,config2=3/u

The "[::<group>|]" syntax is good.

Are you are suggesting that a single event could use multiple groups
because they may share some common fields, such as the event code?  If
so, I think that might be confusing.   I think it would be better to
have every group fully lay out the bits in the config{,1,2} fields so
that you only need to specify one group per event, even if that leads to
some redundancy (e.g. group1..n all have an eventcode field.)

Something I missed before is that your config sysfs attribute group can
look like:

config1:0-1,62-63

How does the user specify a value for these two bit fields, or does he
concatenate the bit fields together, and perf will split it apart again?
e.g. cpu/group1::config1=1,2/u   ?


> or 
>    cpu::group1/config=1,config1=2,config2=3/u
> 
> 
> Or we could say the format field names could not overlap and then
> we dont need to specify group at all :) It'd be just for user's
> awareness..

perf would then "want" to check for overlap and also for fields coming
from different groups.  In some cases, I think you'd want to have the
same name for a field, but have the field a different size, or perhaps a
different interpretation.   For example "busid" might be a desirable
name for fields in two different event groups, but their sizes and
position are different.  Of course the quick fix is to name them
uniquely, but since they are in subdirectories, it isn't really obvious
that the names have to be unique.

One other comment that occurs to me is that it would be nice for perf to
know when a supplied value is out of range, or will have undefined
results.  For example, a field may be 8 bits wide, but not all 8-bit
values are legal.  For example, there may be 208 events, and the codes
may be somehwhat or even very sparsely encoded.  So, ideally, a config
field in sysfs might look like this:

config1:0-7:0x0-0xd8,0xdb-0xe2,0xe4-0xe6

This way perf could check for valid values before stuffing them into
registers, and give a good error message to the user.  If there is no
restriction field, it would be assumed all of the possible values are valid.

I think the kernel code needs to check for bad values as well, because
people can bypass the restrictions exposed by sysfs and use the
perf_events API directly.


- Corey


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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-02-01  1:25                               ` Corey Ashford
@ 2012-02-01 13:13                                 ` Jiri Olsa
  2012-02-01 14:18                                   ` Peter Zijlstra
  2012-02-01 13:36                                 ` Peter Zijlstra
  1 sibling, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-02-01 13:13 UTC (permalink / raw)
  To: Corey Ashford; +Cc: acme, a.p.zijlstra, mingo, paulus, linux-kernel

On Tue, Jan 31, 2012 at 05:25:26PM -0800, Corey Ashford wrote:
> On 01/30/2012 01:52 AM, Jiri Olsa wrote:
> > On Fri, Jan 27, 2012 at 01:08:38PM -0800, Corey Ashford wrote:
> >> On 01/27/2012 06:34 AM, Jiri Olsa wrote:
> >>> Adding sysfs group 'format' attribute for pmu device that
> >>> contains a syntax description on how to construct raw events.
> >>>

SNIP

> >> This might help the user understand which fields go together.  I'm not
> >> sold on the .1 syntax... you could do it as <dev>.<event-group-name>/ or
> >> <dev>/<event-group-name>/... or whatever seems to make the most sense
> >> and is relatively easy to implement and use.
> > 
> > Though I'm not sure we want allow separate devices inside single pmu,
> > I think we could have multiple format groups if necessary :)
> > 
> > some quick ideas:
> > 
> > 1) having format group attribute under format like:
> >    <dev>/format/group1/..
> >    <dev>/format/group2/..
> >    <dev>/format/group2/..
> >    ...
> > 
> > 2) having format group name within the format attribute name like:
> >    <dev>/format/group1-krava1
> >    <dev>/format/group1-krava2
> >    <dev>/format/group2-krava3
> >    ...
> > 
> > 3) having group name inside the foramt attributes like:
> >    cat <dev>/format/group1-krava1
> >    group1 config:0-1,62-63
> > 
> > 
> > I think I like the most ad 1)..
> > 
> > We could have something like default format directory if there's
> > only a single format group, like:
> >    <dev>/format/default/krava1
> >    <dev>/format/default/krava2
> >    ...
> > 
> > The perf event syntax could have something like '::' to classify
> > format attribute with a group like (none would go to default dir):
> > 
> >    cpu/group1::config=1,group2::config1=2,config2=3/u
> 
> The "[::<group>|]" syntax is good.
> 
> Are you are suggesting that a single event could use multiple groups
> because they may share some common fields, such as the event code?  If
> so, I think that might be confusing.   I think it would be better to
> have every group fully lay out the bits in the config{,1,2} fields so
> that you only need to specify one group per event, even if that leads to
> some redundancy (e.g. group1..n all have an eventcode field.)

ok, it'd be the 'cpu::group1/config=1,config1=2,config2=3/u' then..

but let's see what Peter thinks about this, since he first suggested
to 'fix' this by having separate pmu drivers.. not format groups :)

> 
> Something I missed before is that your config sysfs attribute group can
> look like:
> 
> config1:0-1,62-63
> 
> How does the user specify a value for these two bit fields, or does he
> concatenate the bit fields together, and perf will split it apart again?
> e.g. cpu/group1::config1=1,2/u   ?

user just set the value for the field and perf makes sure it is spread
over the config[12] bits as configured

so as for your example, following format definiton:
	# cat <pmu>/format/krava
        config1:0-1,62-63

with user settings:
	cpu/krava=15/u

fills bits 0,1,62,63 of config1 with 1s

> 
> 
> > or 
> >    cpu::group1/config=1,config1=2,config2=3/u
> > 
> > 
> > Or we could say the format field names could not overlap and then
> > we dont need to specify group at all :) It'd be just for user's
> > awareness..
> 
> perf would then "want" to check for overlap and also for fields coming
> from different groups.  In some cases, I think you'd want to have the
> same name for a field, but have the field a different size, or perhaps a
> different interpretation.   For example "busid" might be a desirable
> name for fields in two different event groups, but their sizes and
> position are different.  Of course the quick fix is to name them
> uniquely, but since they are in subdirectories, it isn't really obvious
> that the names have to be unique.
> 
> One other comment that occurs to me is that it would be nice for perf to
> know when a supplied value is out of range, or will have undefined
> results.  For example, a field may be 8 bits wide, but not all 8-bit
> values are legal.  For example, there may be 208 events, and the codes
> may be somehwhat or even very sparsely encoded.  So, ideally, a config
> field in sysfs might look like this:
> 
> config1:0-7:0x0-0xd8,0xdb-0xe2,0xe4-0xe6
> 
> This way perf could check for valid values before stuffing them into
> registers, and give a good error message to the user.  If there is no
> restriction field, it would be assumed all of the possible values are valid.
> 
> I think the kernel code needs to check for bad values as well, because
> people can bypass the restrictions exposed by sysfs and use the
> perf_events API directly.

ok, I think some kind of such restriction could be added as optional ':'
behind the current format if needed.. np

thanks,
jirka

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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-02-01  1:25                               ` Corey Ashford
  2012-02-01 13:13                                 ` Jiri Olsa
@ 2012-02-01 13:36                                 ` Peter Zijlstra
  2012-02-02  0:33                                   ` Corey Ashford
  1 sibling, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-01 13:36 UTC (permalink / raw)
  To: Corey Ashford; +Cc: Jiri Olsa, acme, mingo, paulus, linux-kernel

On Tue, 2012-01-31 at 17:25 -0800, Corey Ashford wrote:
> 
> One other comment that occurs to me is that it would be nice for perf to
> know when a supplied value is out of range, or will have undefined
> results.  For example, a field may be 8 bits wide, but not all 8-bit
> values are legal.  For example, there may be 208 events, and the codes
> may be somehwhat or even very sparsely encoded.  So, ideally, a config
> field in sysfs might look like this:
> 
> config1:0-7:0x0-0xd8,0xdb-0xe2,0xe4-0xe6
> 
> This way perf could check for valid values before stuffing them into
> registers, and give a good error message to the user.  If there is no
> restriction field, it would be assumed all of the possible values are valid.
> 
> I think the kernel code needs to check for bad values as well, because
> people can bypass the restrictions exposed by sysfs and use the
> perf_events API directly. 

Define bad? The only case where perf cares (from a kernel pov) is when
it can make the hardware melt and similar things. Programming the PMU in
a non-nonsensical but non-destructive way is fine, you get what you ask
for.




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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-02-01 13:13                                 ` Jiri Olsa
@ 2012-02-01 14:18                                   ` Peter Zijlstra
  2012-02-01 14:31                                     ` Jiri Olsa
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-01 14:18 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: Corey Ashford, acme, mingo, paulus, linux-kernel

On Wed, 2012-02-01 at 14:13 +0100, Jiri Olsa wrote:
> > Are you are suggesting that a single event could use multiple groups
> > because they may share some common fields, such as the event code?  If
> > so, I think that might be confusing.   I think it would be better to
> > have every group fully lay out the bits in the config{,1,2} fields so
> > that you only need to specify one group per event, even if that leads to
> > some redundancy (e.g. group1..n all have an eventcode field.)
> 
> ok, it'd be the 'cpu::group1/config=1,config1=2,config2=3/u' then..
> 
> but let's see what Peter thinks about this, since he first suggested
> to 'fix' this by having separate pmu drivers.. not format groups :) 

I'm not convinced we need the whole grouping thing. Even x86 might have
overlapping definitions, even for a single PMU (config1 contents will
radically differ depending on the actual events used for instance).

All we should do is warn the user when overlapping masks are used in a
single event definition and other than that just do as they tell us.

PMUs can always do an informal namespace thing if really needed, eg. by
using a consistent prefix.


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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-02-01 14:18                                   ` Peter Zijlstra
@ 2012-02-01 14:31                                     ` Jiri Olsa
  2012-02-01 14:40                                       ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-02-01 14:31 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Corey Ashford, acme, mingo, paulus, linux-kernel

On Wed, Feb 01, 2012 at 03:18:52PM +0100, Peter Zijlstra wrote:
> On Wed, 2012-02-01 at 14:13 +0100, Jiri Olsa wrote:
> > > Are you are suggesting that a single event could use multiple groups
> > > because they may share some common fields, such as the event code?  If
> > > so, I think that might be confusing.   I think it would be better to
> > > have every group fully lay out the bits in the config{,1,2} fields so
> > > that you only need to specify one group per event, even if that leads to
> > > some redundancy (e.g. group1..n all have an eventcode field.)
> > 
> > ok, it'd be the 'cpu::group1/config=1,config1=2,config2=3/u' then..
> > 
> > but let's see what Peter thinks about this, since he first suggested
> > to 'fix' this by having separate pmu drivers.. not format groups :) 
> 
> I'm not convinced we need the whole grouping thing. Even x86 might have
> overlapping definitions, even for a single PMU (config1 contents will
> radically differ depending on the actual events used for instance).

well, I think let's go with what we have now, and see if need/want
to care about format groups later after we use it for a while..

since the "cpu/..../" syntax is new interface, there should be no
problem to change it

> 
> All we should do is warn the user when overlapping masks are used in a
> single event definition and other than that just do as they tell us.

that should be no problem..
do you want it in to take this.. ooor is later ok ;)

jirka

> 
> PMUs can always do an informal namespace thing if really needed, eg. by
> using a consistent prefix.
> 

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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-02-01 14:31                                     ` Jiri Olsa
@ 2012-02-01 14:40                                       ` Peter Zijlstra
  0 siblings, 0 replies; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-01 14:40 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: Corey Ashford, acme, mingo, paulus, linux-kernel

On Wed, 2012-02-01 at 15:31 +0100, Jiri Olsa wrote:
> ooor is later ok ;)

later is fine ;-)

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

* Re: [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device
  2012-02-01 13:36                                 ` Peter Zijlstra
@ 2012-02-02  0:33                                   ` Corey Ashford
  0 siblings, 0 replies; 91+ messages in thread
From: Corey Ashford @ 2012-02-02  0:33 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jiri Olsa, acme, mingo, paulus, linux-kernel

On 02/01/2012 05:36 AM, Peter Zijlstra wrote:
> On Tue, 2012-01-31 at 17:25 -0800, Corey Ashford wrote:
>>
>> One other comment that occurs to me is that it would be nice for perf to
>> know when a supplied value is out of range, or will have undefined
>> results.  For example, a field may be 8 bits wide, but not all 8-bit
>> values are legal.  For example, there may be 208 events, and the codes
>> may be somehwhat or even very sparsely encoded.  So, ideally, a config
>> field in sysfs might look like this:
>>
>> config1:0-7:0x0-0xd8,0xdb-0xe2,0xe4-0xe6
>>
>> This way perf could check for valid values before stuffing them into
>> registers, and give a good error message to the user.  If there is no
>> restriction field, it would be assumed all of the possible values are valid.
>>
>> I think the kernel code needs to check for bad values as well, because
>> people can bypass the restrictions exposed by sysfs and use the
>> perf_events API directly. 
> 
> Define bad? The only case where perf cares (from a kernel pov) is when
> it can make the hardware melt and similar things. Programming the PMU in
> a non-nonsensical but non-destructive way is fine, you get what you ask
> for.

The main definition of "bad" would be a known config that has no meaning
(or perhaps is improperly implemented on the chip).  This would just
give the user some extra help that he might have incorrectly configured
the PMU.  Perf could identify down to the specific field that may not be
set correctly.  You could add an override switch to perf (--force-config
etc.) that would allow the user to bypass the check if he really wanted
to use that config.

It's also conceivable that there would be known PMU modes, that let's
say, stores values into a memory buffer (like IBS, etc), that if you use
a particular config, it would overwhelm the memory bus and choke the
processor down.

That said, this feature would just be nice to have, and is only on my
wish list.

Thanks for considering comments,

- Corey


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

* [tip:perf/core] perf evlist: Make splice_list_tail method public
  2012-01-27 14:34                         ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
@ 2012-02-07 19:31                           ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: tip-bot for Jiri Olsa @ 2012-02-07 19:31 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa,
	tglx, cjashfor, mingo

Commit-ID:  0529bc1fe1e3e509a2fc06fe887b0c76b1eb01f9
Gitweb:     http://git.kernel.org/tip/0529bc1fe1e3e509a2fc06fe887b0c76b1eb01f9
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Fri, 27 Jan 2012 15:34:20 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 1 Feb 2012 15:29:53 -0200

perf evlist: Make splice_list_tail method public

Making perf_evlist__splice_list_tail globaly accessible.

It is used in the upcomming paches.

Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1327674868-10486-2-git-send-email-jolsa@redhat.com
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/evlist.c |    6 +++---
 tools/perf/util/evlist.h |    5 +++++
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index a6d50e3..a57a8cf 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -97,9 +97,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 	++evlist->nr_entries;
 }
 
-static void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
-					  struct list_head *list,
-					  int nr_entries)
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries)
 {
 	list_splice_tail(list, &evlist->entries);
 	evlist->nr_entries += nr_entries;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 9c51660..1b4282b 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -117,4 +117,9 @@ u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
 
 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
+
+void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+				   struct list_head *list,
+				   int nr_entries);
+
 #endif /* __PERF_EVLIST_H */

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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (8 preceding siblings ...)
  2012-01-27 14:34                         ` [PATCH 9/9] perf, tool: Add support to specify pmu style event Jiri Olsa
@ 2012-02-13 13:13                         ` Jiri Olsa
  2012-02-14 16:28                         ` Peter Zijlstra
  10 siblings, 0 replies; 91+ messages in thread
From: Jiri Olsa @ 2012-02-13 13:13 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor; +Cc: linux-kernel

hi,
any feedback? ;)
I saw 1/9 was already taken, thanks
I can send rebased patchset if needed..

thanks,
jirka

On Fri, Jan 27, 2012 at 03:34:19PM +0100, Jiri Olsa wrote:
> hi,
> Here's new version of event parsing patchset. To summarize:
>  - adding event parser bison/flex generator
>  - the event syntax stays as it was
>  - adding event format sysfs group attribute
>    for pmu device
>  - adding new syntax to specify raw events based
>    on the sysfs pmu's format attribute
>    eg. "cpu/config=1,config1=2,config2=3/u"
> 
> There are helping patches 1-4, which I did not want to
> mangle with the actual change. Patches 5-9 implement
> the feature itself.
> 
> v4 changes:
>  - 5/9 changed sysfs pmu format definitions to the group attribute,
>        each line (in previous patch) is now represented by single
>        sysfs attribute under format group
>  - 6/9 fix raw events so the number is always considered to be hex number
>  - 8/9 move config[12] definitions to be processed by the parser
> 
> Attached patches:
>  1/9 perf, tool: Make perf_evlist__splice_list_tail global
>  2/9 perf, tool: Remove unused functions from debugfs object
>  3/9 perf, tool: Add sysfs mountpoint interface
>  4/9 perf, tool: Add bitmap_or function into bitmap object
>  5/9 perf: Adding sysfs group format attribute for pmu device
>  6/9 perf, tool: Add parser generator for events parsing
>  7/9 perf, tool: Add config options support for event parsing
>  8/9 perf, tool: Add perf pmu object to access pmu format definition
>  9/9 perf, tool: Add support to specify pmu style event
> 
> 
> thanks,
> jirka
> ---
>  .../testing/sysfs-bus-event_source-devices-format  |   14 +
>  include/linux/perf_event.h                         |   22 +
>  kernel/events/core.c                               |   22 +
>  tools/perf/Makefile                                |   31 +
>  tools/perf/builtin-test.c                          |   52 +-
>  tools/perf/util/bitmap.c                           |   10 +
>  tools/perf/util/debugfs.c                          |  141 --
>  tools/perf/util/debugfs.h                          |    6 -
>  tools/perf/util/evlist.c                           |    6 +-
>  tools/perf/util/evlist.h                           |    5 +
>  tools/perf/util/include/linux/bitmap.h             |   11 +
>  tools/perf/util/parse-events-bison.c               | 1813 ++++++++++++++++
>  tools/perf/util/parse-events-bison.h               |   81 +
>  tools/perf/util/parse-events-flex.c                | 2225 ++++++++++++++++++++
>  tools/perf/util/parse-events-flex.h                |  316 +++
>  tools/perf/util/parse-events.c                     |  552 ++---
>  tools/perf/util/parse-events.h                     |   37 +
>  tools/perf/util/parse-events.l                     |  107 +
>  tools/perf/util/parse-events.y                     |  191 ++
>  tools/perf/util/pmu-bison.c                        | 1663 +++++++++++++++
>  tools/perf/util/pmu-bison.h                        |   73 +
>  tools/perf/util/pmu-flex.c                         | 1821 ++++++++++++++++
>  tools/perf/util/pmu-flex.h                         |  316 +++
>  tools/perf/util/pmu.c                              |  462 ++++
>  tools/perf/util/pmu.h                              |   41 +
>  tools/perf/util/pmu.l                              |   43 +
>  tools/perf/util/pmu.y                              |   93 +
>  tools/perf/util/sysfs.c                            |   60 +
>  tools/perf/util/sysfs.h                            |    6 +
>  29 files changed, 9740 insertions(+), 480 deletions(-)

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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
                                           ` (9 preceding siblings ...)
  2012-02-13 13:13                         ` [PATCHv4 0/9] perf tool: parser generator for events parsing Jiri Olsa
@ 2012-02-14 16:28                         ` Peter Zijlstra
  2012-02-14 16:43                           ` Peter Zijlstra
  10 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-14 16:28 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Fri, 2012-01-27 at 15:34 +0100, Jiri Olsa wrote:
> hi,
> Here's new version of event parsing patchset. To summarize:
>  - adding event parser bison/flex generator
>  - the event syntax stays as it was
>  - adding event format sysfs group attribute
>    for pmu device
>  - adding new syntax to specify raw events based
>    on the sysfs pmu's format attribute
>    eg. "cpu/config=1,config1=2,config2=3/u"
> 
> There are helping patches 1-4, which I did not want to
> mangle with the actual change. Patches 5-9 implement
> the feature itself.
> 
> v4 changes:
>  - 5/9 changed sysfs pmu format definitions to the group attribute,
>        each line (in previous patch) is now represented by single
>        sysfs attribute under format group
>  - 6/9 fix raw events so the number is always considered to be hex number
>  - 8/9 move config[12] definitions to be processed by the parser


I added the below but all I managed was to crash my kernel, its probably
a simple thing, but sysfs didn't give a hint.

---
Subject: perf, x86: Add simple format descriptions
From: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date: Tue Feb 14 16:37:27 CET 2012


Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
 arch/x86/kernel/cpu/perf_event.c       |    7 ++++++
 arch/x86/kernel/cpu/perf_event.h       |    1 
 arch/x86/kernel/cpu/perf_event_amd.c   |   18 +++++++++++++++++
 arch/x86/kernel/cpu/perf_event_intel.c |   34 +++++++++++++++++++++++++++++++++
 arch/x86/kernel/cpu/perf_event_p6.c    |   18 +++++++++++++++++
 include/linux/perf_event.h             |    6 -----
 kernel/events/core.c                   |   22 ---------------------
 7 files changed, 78 insertions(+), 28 deletions(-)
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1250,6 +1250,11 @@ static void __init pmu_check_apic(void)
 	pr_info("no hardware sampling interrupt available.\n");
 }
 
+static struct attribute_group x86_pmu_format_group = {
+	.name = "format",
+	.attrs = NULL,
+};
+
 static int __init init_hw_perf_events(void)
 {
 	struct x86_pmu_quirk *quirk;
@@ -1324,6 +1329,7 @@ static int __init init_hw_perf_events(vo
 	}
 
 	x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+	x86_pmu_format_group.attrs = x86_pmu.format_attrs;
 
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.cntval_bits);
@@ -1604,6 +1610,7 @@ static struct attribute_group x86_pmu_at
 
 static const struct attribute_group *x86_pmu_attr_groups[] = {
 	&x86_pmu_attr_group,
+	&x86_pmu_format_group,
 	NULL,
 };
 
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -311,6 +311,7 @@ struct x86_pmu {
 	 * sysfs attrs
 	 */
 	int		attr_rdpmc;
+	struct attribute **format_attrs;
 
 	/*
 	 * CPU Hotplug hooks
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -398,6 +398,20 @@ static void amd_pmu_cpu_dead(int cpu)
 	}
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7,32-35");
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *amd_format_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+};
+
 static __initconst const struct x86_pmu amd_pmu = {
 	.name			= "AMD",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -420,6 +434,8 @@ static __initconst const struct x86_pmu 
 	.get_event_constraints	= amd_get_event_constraints,
 	.put_event_constraints	= amd_put_event_constraints,
 
+	.format_attrs		= amd_format_attr,
+
 	.cpu_prepare		= amd_pmu_cpu_prepare,
 	.cpu_starting		= amd_pmu_cpu_starting,
 	.cpu_dead		= amd_pmu_cpu_dead,
@@ -590,6 +606,8 @@ static __initconst const struct x86_pmu 
 	.cpu_starting		= amd_pmu_cpu_starting,
 	.cpu_dead		= amd_pmu_cpu_dead,
 #endif
+
+	.format_attrs		= amd_format_attr,
 };
 
 __init int amd_pmu_init(void)
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1382,6 +1382,23 @@ static void core_pmu_enable_all(int adde
 	}
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(any,	"config:21"	); /* v3 + */
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_arch_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+};
+
 static __initconst const struct x86_pmu core_pmu = {
 	.name			= "core",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -1406,6 +1423,7 @@ static __initconst const struct x86_pmu 
 	.put_event_constraints	= intel_put_event_constraints,
 	.event_constraints	= intel_core_event_constraints,
 	.guest_get_msrs		= core_guest_get_msrs,
+	.format_attrs		= intel_arch_formats_attr,
 };
 
 struct intel_shared_regs *allocate_shared_regs(int cpu)
@@ -1486,6 +1504,20 @@ static void intel_pmu_cpu_dying(int cpu)
 	fini_debug_store_on_cpu(cpu);
 }
 
+PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
+
+static struct attribute *intel_arch3_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_any.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+
+	&format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */
+};
+
 static __initconst const struct x86_pmu intel_pmu = {
 	.name			= "Intel",
 	.handle_irq		= intel_pmu_handle_irq,
@@ -1509,6 +1541,8 @@ static __initconst const struct x86_pmu 
 	.get_event_constraints	= intel_get_event_constraints,
 	.put_event_constraints	= intel_put_event_constraints,
 
+	.format_attrs		= intel_arch3_formats_attr,
+
 	.cpu_prepare		= intel_pmu_cpu_prepare,
 	.cpu_starting		= intel_pmu_cpu_starting,
 	.cpu_dying		= intel_pmu_cpu_dying,
--- a/arch/x86/kernel/cpu/perf_event_p6.c
+++ b/arch/x86/kernel/cpu/perf_event_p6.c
@@ -87,6 +87,22 @@ static void p6_pmu_enable_event(struct p
 	(void)checking_wrmsrl(hwc->config_base, val);
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_p6_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+};
+
 static __initconst const struct x86_pmu p6_pmu = {
 	.name			= "p6",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -115,6 +131,8 @@ static __initconst const struct x86_pmu 
 	.cntval_mask		= (1ULL << 32) - 1,
 	.get_event_constraints	= x86_get_event_constraints,
 	.event_constraints	= p6_event_constraints,
+
+	.format_attrs		= intel_p6_formats_attr,
 };
 
 __init int p6_pmu_init(void)
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -628,12 +628,6 @@ struct pmu {
 	int				task_ctx_nr;
 
 	/*
-	 * True if the pmu defines its own set of format attributes within
-	 * attr_groups. If false, default format attributes are used.
-	 */
-	bool				format_defined;
-
-	/*
 	 * Fully disable/enable this PMU, can be used to protect from the PMI
 	 * as well as for lazy/batch writing of the MSRs.
 	 */
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5540,22 +5540,6 @@ static struct bus_type pmu_bus = {
 	.dev_attrs	= pmu_dev_attrs,
 };
 
-/* Default format attributes. */
-PMU_FORMAT_ATTR(config,  "config:0-63");
-PMU_FORMAT_ATTR(config1, "config1:0-63");
-PMU_FORMAT_ATTR(config2, "config2:0-63");
-
-static struct attribute *format_attrs[] = {
-	&format_attr_config.attr,
-	&format_attr_config1.attr,
-	&format_attr_config2.attr,
-};
-
-static struct attribute_group format_attr_group = {
-	.name   = "format",
-	.attrs  = format_attrs,
-};
-
 static void pmu_dev_release(struct device *dev)
 {
 	kfree(dev);
@@ -5582,12 +5566,6 @@ static int pmu_dev_alloc(struct pmu *pmu
 	if (ret)
 		goto free_dev;
 
-	if (!pmu->format_defined) {
-		ret = sysfs_create_group(&pmu->dev->kobj, &format_attr_group);
-		if (ret)
-			goto free_dev;
-	}
-
 out:
 	return ret;
 


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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-14 16:28                         ` Peter Zijlstra
@ 2012-02-14 16:43                           ` Peter Zijlstra
  2012-02-14 20:20                             ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-14 16:43 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel, Greg KH

On Tue, 2012-02-14 at 17:28 +0100, Peter Zijlstra wrote:
> 
> I added the below but all I managed was to crash my kernel, its probably
> a simple thing, but sysfs didn't give a hint.

This isn't it either..

crash looks like:

general protection fault: 0000 [#1] PREEMPT SMP 
CPU 0 
Modules linked in:

Pid: 1, comm: swapper/0 Not tainted 3.3.0-rc3-01426-g2ce21a5-dirty #78 Supermicro X8DTN/X8DTN
RIP: 0010:[<ffffffff812e258e>]  [<ffffffff812e258e>] strcmp+0x4/0x21
RSP: 0018:ffff880236879c90  EFLAGS: 00010286
RAX: ffff880235ac7660 RBX: 0000000000000000 RCX: ffff880236870000
RDX: 0000000000000000 RSI: ffffffff81b295a6 RDI: 6e7500746e657665
RBP: ffff880236879c90 R08: 0000000000000180 R09: 6e7500746e657665
R10: ffffffff812ddedd R11: ffff880236879dc0 R12: 0000000000000000
R13: ffff880235ac7630 R14: 6e7500746e657665 R15: 0000000000000008
FS:  0000000000000000(0000) GS:ffff880237c00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000000 CR3: 0000000001c05000 CR4: 00000000000007f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process swapper/0 (pid: 1, threadinfo ffff880236878000, task ffff880236870000)
Stack:
 ffff880236879cc0 ffffffff811996e2 ffff880235ac7ab0 ffff880236879d30
 ffff880236879d30 ffff880235ac7ab0 ffff880236879ce0 ffffffff81199957
 ffff880236879d30 ffff880235ac75a0 ffff880236879d10 ffffffff81199a06
Call Trace:
 [<ffffffff811996e2>] sysfs_find_dirent+0x79/0xda
 [<ffffffff81199957>] __sysfs_add_one+0x73/0xc3
 [<ffffffff81199a06>] sysfs_add_one+0x1b/0xab
 [<ffffffff81198fa8>] sysfs_add_file_mode+0x7e/0xb7
 [<ffffffff8119b841>] internal_create_group+0xed/0x168
 [<ffffffff8119b8e7>] sysfs_create_group+0x13/0x18
 [<ffffffff814861fc>] device_add_groups+0x2a/0x69
 [<ffffffff81198ff3>] ? sysfs_add_file+0x12/0x14
 [<ffffffff81486f8f>] device_add+0x37f/0x636
 [<ffffffff8148672b>] ? kzalloc.clone.0+0xe/0x10
 [<ffffffff810f069a>] pmu_dev_alloc+0x88/0xa4
 [<ffffffff81d11114>] ? init_kprobe_trace+0x90/0x90
 [<ffffffff81d1115f>] perf_event_sysfs_init+0x4b/0x9a
 [<ffffffff81d11114>] ? init_kprobe_trace+0x90/0x90
 [<ffffffff8100020f>] do_one_initcall+0x7f/0x139
 [<ffffffff81cf65ba>] kernel_init+0xa2/0x122
 [<ffffffff8109083e>] ? schedule_tail+0x31/0x74
 [<ffffffff817af2a4>] kernel_thread_helper+0x4/0x10
 [<ffffffff81cf6518>] ? parse_early_options+0x20/0x20
 [<ffffffff817af2a0>] ? gs_change+0x13/0x13
Code: 48 ff c1 80 39 00 75 f8 eb 0d 48 ff c1 48 ff ca 75 05 c6 01 00 eb
0e 40 8a 3e 48 ff c6 40 88 39 40 84 ff 75 e5 c9 c3 55 48 89 e5 <8a> 07
8a 16 48 ff c7 48 ff c6 38 d0 74 07 19 c0 83 c8 01 eb 06 
RIP  [<ffffffff812e258e>] strcmp+0x4/0x21
 RSP <ffff880236879c90>
---[ end trace 5283cffd22793f50 ]---


And yes, I already send greg a patch for that sillyness in
sysfs_find_dirent.

---
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1605,6 +1605,7 @@ static struct attribute *x86_pmu_attrs[]
 };
 
 static struct attribute_group x86_pmu_attr_group = {
+	.name = "attributes",
 	.attrs = x86_pmu_attrs,
 };
 


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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-14 16:43                           ` Peter Zijlstra
@ 2012-02-14 20:20                             ` Peter Zijlstra
  2012-02-14 20:57                               ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-14 20:20 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel, Greg KH

On Tue, 2012-02-14 at 17:43 +0100, Peter Zijlstra wrote:
> > I added the below but all I managed was to crash my kernel, its probably
> > a simple thing, but sysfs didn't give a hint. 

OK, this one works. the attributes thing wants NULL termination. Thanks
for mentioning that Jiri.

---
Subject: perf, x86: Add simple format descriptions
From: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date: Tue Feb 14 16:37:27 CET 2012


Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
 arch/x86/kernel/cpu/perf_event.c       |    7 ++++++
 arch/x86/kernel/cpu/perf_event.h       |    1 
 arch/x86/kernel/cpu/perf_event_amd.c   |   19 +++++++++++++++++
 arch/x86/kernel/cpu/perf_event_intel.c |   36 +++++++++++++++++++++++++++++++++
 arch/x86/kernel/cpu/perf_event_p6.c    |   19 +++++++++++++++++
 include/linux/perf_event.h             |    6 -----
 kernel/events/core.c                   |   22 --------------------
 7 files changed, 82 insertions(+), 28 deletions(-)
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1250,6 +1250,11 @@ static void __init pmu_check_apic(void)
 	pr_info("no hardware sampling interrupt available.\n");
 }
 
+static struct attribute_group x86_pmu_format_group = {
+	.name = "format",
+	.attrs = NULL,
+};
+
 static int __init init_hw_perf_events(void)
 {
 	struct x86_pmu_quirk *quirk;
@@ -1324,6 +1329,7 @@ static int __init init_hw_perf_events(vo
 	}
 
 	x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+	x86_pmu_format_group.attrs = x86_pmu.format_attrs;
 
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.cntval_bits);
@@ -1604,6 +1610,7 @@ static struct attribute_group x86_pmu_at
 
 static const struct attribute_group *x86_pmu_attr_groups[] = {
 	&x86_pmu_attr_group,
+	&x86_pmu_format_group,
 	NULL,
 };
 
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -311,6 +311,7 @@ struct x86_pmu {
 	 * sysfs attrs
 	 */
 	int		attr_rdpmc;
+	struct attribute **format_attrs;
 
 	/*
 	 * CPU Hotplug hooks
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -398,6 +398,21 @@ static void amd_pmu_cpu_dead(int cpu)
 	}
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7,32-35");
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *amd_format_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
 static __initconst const struct x86_pmu amd_pmu = {
 	.name			= "AMD",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -420,6 +435,8 @@ static __initconst const struct x86_pmu 
 	.get_event_constraints	= amd_get_event_constraints,
 	.put_event_constraints	= amd_put_event_constraints,
 
+	.format_attrs		= amd_format_attr,
+
 	.cpu_prepare		= amd_pmu_cpu_prepare,
 	.cpu_starting		= amd_pmu_cpu_starting,
 	.cpu_dead		= amd_pmu_cpu_dead,
@@ -590,6 +607,8 @@ static __initconst const struct x86_pmu 
 	.cpu_starting		= amd_pmu_cpu_starting,
 	.cpu_dead		= amd_pmu_cpu_dead,
 #endif
+
+	.format_attrs		= amd_format_attr,
 };
 
 __init int amd_pmu_init(void)
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1382,6 +1382,24 @@ static void core_pmu_enable_all(int adde
 	}
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(any,	"config:21"	); /* v3 + */
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_arch_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
 static __initconst const struct x86_pmu core_pmu = {
 	.name			= "core",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -1406,6 +1424,7 @@ static __initconst const struct x86_pmu 
 	.put_event_constraints	= intel_put_event_constraints,
 	.event_constraints	= intel_core_event_constraints,
 	.guest_get_msrs		= core_guest_get_msrs,
+	.format_attrs		= intel_arch_formats_attr,
 };
 
 struct intel_shared_regs *allocate_shared_regs(int cpu)
@@ -1486,6 +1505,21 @@ static void intel_pmu_cpu_dying(int cpu)
 	fini_debug_store_on_cpu(cpu);
 }
 
+PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
+
+static struct attribute *intel_arch3_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_any.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+
+	&format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */
+	NULL,
+};
+
 static __initconst const struct x86_pmu intel_pmu = {
 	.name			= "Intel",
 	.handle_irq		= intel_pmu_handle_irq,
@@ -1509,6 +1543,8 @@ static __initconst const struct x86_pmu 
 	.get_event_constraints	= intel_get_event_constraints,
 	.put_event_constraints	= intel_put_event_constraints,
 
+	.format_attrs		= intel_arch3_formats_attr,
+
 	.cpu_prepare		= intel_pmu_cpu_prepare,
 	.cpu_starting		= intel_pmu_cpu_starting,
 	.cpu_dying		= intel_pmu_cpu_dying,
--- a/arch/x86/kernel/cpu/perf_event_p6.c
+++ b/arch/x86/kernel/cpu/perf_event_p6.c
@@ -87,6 +87,23 @@ static void p6_pmu_enable_event(struct p
 	(void)checking_wrmsrl(hwc->config_base, val);
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_p6_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
 static __initconst const struct x86_pmu p6_pmu = {
 	.name			= "p6",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -115,6 +132,8 @@ static __initconst const struct x86_pmu 
 	.cntval_mask		= (1ULL << 32) - 1,
 	.get_event_constraints	= x86_get_event_constraints,
 	.event_constraints	= p6_event_constraints,
+
+	.format_attrs		= intel_p6_formats_attr,
 };
 
 __init int p6_pmu_init(void)
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -628,12 +628,6 @@ struct pmu {
 	int				task_ctx_nr;
 
 	/*
-	 * True if the pmu defines its own set of format attributes within
-	 * attr_groups. If false, default format attributes are used.
-	 */
-	bool				format_defined;
-
-	/*
 	 * Fully disable/enable this PMU, can be used to protect from the PMI
 	 * as well as for lazy/batch writing of the MSRs.
 	 */
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5540,22 +5540,6 @@ static struct bus_type pmu_bus = {
 	.dev_attrs	= pmu_dev_attrs,
 };
 
-/* Default format attributes. */
-PMU_FORMAT_ATTR(config,  "config:0-63");
-PMU_FORMAT_ATTR(config1, "config1:0-63");
-PMU_FORMAT_ATTR(config2, "config2:0-63");
-
-static struct attribute *format_attrs[] = {
-	&format_attr_config.attr,
-	&format_attr_config1.attr,
-	&format_attr_config2.attr,
-};
-
-static struct attribute_group format_attr_group = {
-	.name   = "format",
-	.attrs  = format_attrs,
-};
-
 static void pmu_dev_release(struct device *dev)
 {
 	kfree(dev);
@@ -5582,12 +5566,6 @@ static int pmu_dev_alloc(struct pmu *pmu
 	if (ret)
 		goto free_dev;
 
-	if (!pmu->format_defined) {
-		ret = sysfs_create_group(&pmu->dev->kobj, &format_attr_group);
-		if (ret)
-			goto free_dev;
-	}
-
 out:
 	return ret;
 


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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-14 20:20                             ` Peter Zijlstra
@ 2012-02-14 20:57                               ` Peter Zijlstra
  2012-02-14 21:03                                 ` Peter Zijlstra
  2012-02-15  9:04                                 ` Jiri Olsa
  0 siblings, 2 replies; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-14 20:57 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Tue, 2012-02-14 at 21:20 +0100, Peter Zijlstra wrote:
> OK, this one works. the attributes thing wants NULL termination.
> Thanks
> for mentioning that Jiri. 

OK, it mostly works, except:

perf record -e "cpu/config=0x108000c0/upp" ./loop_1b_locks

doesn't seem to work...

One thing that might be nice is not having to do =1 for single bit
fields, so that we can write: inv,edge instead of inv=1,edge=1.



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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-14 20:57                               ` Peter Zijlstra
@ 2012-02-14 21:03                                 ` Peter Zijlstra
  2012-02-15  9:24                                   ` Jiri Olsa
  2012-02-15  9:04                                 ` Jiri Olsa
  1 sibling, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-14 21:03 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel, Stephane Eranian

On Tue, 2012-02-14 at 21:57 +0100, Peter Zijlstra wrote:
> On Tue, 2012-02-14 at 21:20 +0100, Peter Zijlstra wrote:
> > OK, this one works. the attributes thing wants NULL termination.
> > Thanks
> > for mentioning that Jiri. 
> 
> OK, it mostly works, except:
> 
> perf record -e "cpu/config=0x108000c0/upp" ./loop_1b_locks
> 
> doesn't seem to work...

This seems to come back to hardcoding config* vs including it in every
single format description.

I prefer to have all perf_event_attr fields (of interest) hard-coded in
the parser so that we can omit them for all actual format descriptions.

These would be: period, config, config1, config2 and stephane's new
branch_sample_type, although that might want to get a shorter name.

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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-14 20:57                               ` Peter Zijlstra
  2012-02-14 21:03                                 ` Peter Zijlstra
@ 2012-02-15  9:04                                 ` Jiri Olsa
  2012-02-15 11:03                                   ` Peter Zijlstra
  1 sibling, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-02-15  9:04 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Tue, Feb 14, 2012 at 09:57:10PM +0100, Peter Zijlstra wrote:
> On Tue, 2012-02-14 at 21:20 +0100, Peter Zijlstra wrote:
> > OK, this one works. the attributes thing wants NULL termination.
> > Thanks
> > for mentioning that Jiri. 
> 
> OK, it mostly works, except:
> 
> perf record -e "cpu/config=0x108000c0/upp" ./loop_1b_locks
> 
> doesn't seem to work...
> 
> One thing that might be nice is not having to do =1 for single bit
> fields, so that we can write: inv,edge instead of inv=1,edge=1.

ok, would you think there's any use for following behaviour:
whenever field is written without the assignment, all the field defined
bits are set.. regardless if it's sengle ot multiple bit field..

looks like this would ease the implementation a little,
not mentioning the above behaviour could be usefull ;)

jirka

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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-14 21:03                                 ` Peter Zijlstra
@ 2012-02-15  9:24                                   ` Jiri Olsa
  2012-02-15 11:18                                     ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-02-15  9:24 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: acme, mingo, paulus, cjashfor, linux-kernel, Stephane Eranian

On Tue, Feb 14, 2012 at 10:03:11PM +0100, Peter Zijlstra wrote:
> On Tue, 2012-02-14 at 21:57 +0100, Peter Zijlstra wrote:
> > On Tue, 2012-02-14 at 21:20 +0100, Peter Zijlstra wrote:
> > > OK, this one works. the attributes thing wants NULL termination.
> > > Thanks
> > > for mentioning that Jiri. 
> > 
> > OK, it mostly works, except:
> > 
> > perf record -e "cpu/config=0x108000c0/upp" ./loop_1b_locks
> > 
> > doesn't seem to work...
> 
> This seems to come back to hardcoding config* vs including it in every
> single format description.
> 
> I prefer to have all perf_event_attr fields (of interest) hard-coded in
> the parser so that we can omit them for all actual format descriptions.
> 
> These would be: period, config, config1, config2 and stephane's new
> branch_sample_type, although that might want to get a shorter name.

right, for pmu/.../ syntax there are allowed only fields from 'format'
directory are so far.. with exceptions like: cycles/period=100000/

so I'll hardcode following config fields:
	config
	config1
	config2
	period
	branch_sample_type (branch, branch_type, branch_st  ???)

to be used in xxx/.../ syntax

also we need to choose some strategy of format field name shadowing
with hardcoded fields:

- BUILD_BUG in kernel PMU_FORMAT_ATTR
- not allowed.. report error in perf runtime
- allowed - hardcoded field have precedence
- allowed - format field values have precedence

I'd say either allow shadowing(with whatever precedence we this is better),
or have the BUILD_BUG line in kernel..

jirka

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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-15  9:04                                 ` Jiri Olsa
@ 2012-02-15 11:03                                   ` Peter Zijlstra
  0 siblings, 0 replies; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-15 11:03 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel

On Wed, 2012-02-15 at 10:04 +0100, Jiri Olsa wrote:
> On Tue, Feb 14, 2012 at 09:57:10PM +0100, Peter Zijlstra wrote:
> > On Tue, 2012-02-14 at 21:20 +0100, Peter Zijlstra wrote:
> > > OK, this one works. the attributes thing wants NULL termination.
> > > Thanks
> > > for mentioning that Jiri. 
> > 
> > OK, it mostly works, except:
> > 
> > perf record -e "cpu/config=0x108000c0/upp" ./loop_1b_locks
> > 
> > doesn't seem to work...
> > 
> > One thing that might be nice is not having to do =1 for single bit
> > fields, so that we can write: inv,edge instead of inv=1,edge=1.
> 
> ok, would you think there's any use for following behaviour:
> whenever field is written without the assignment, all the field defined
> bits are set.. regardless if it's sengle ot multiple bit field..
> 
> looks like this would ease the implementation a little,
> not mentioning the above behaviour could be usefull ;)

I'm not sure that behaviour would be useful for anything other than
this, but sure -- or set the value to 1 when not set, either works.

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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-15  9:24                                   ` Jiri Olsa
@ 2012-02-15 11:18                                     ` Peter Zijlstra
  2012-02-15 13:32                                       ` Jiri Olsa
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-15 11:18 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel, Stephane Eranian

On Wed, 2012-02-15 at 10:24 +0100, Jiri Olsa wrote:
> On Tue, Feb 14, 2012 at 10:03:11PM +0100, Peter Zijlstra wrote:

> > These would be: period, config, config1, config2 and stephane's new
> > branch_sample_type, although that might want to get a shorter name.
> 
> right, for pmu/.../ syntax there are allowed only fields from 'format'
> directory are so far.. with exceptions like: cycles/period=100000/
> 
> so I'll hardcode following config fields:
> 	config
> 	config1
> 	config2
> 	period
> 	branch_sample_type (branch, branch_type, branch_st  ???)

Uhmm,.. Stephane any particular preference on this?

> to be used in xxx/.../ syntax
> 
> also we need to choose some strategy of format field name shadowing
> with hardcoded fields:
> 
> - BUILD_BUG in kernel PMU_FORMAT_ATTR
> - not allowed.. report error in perf runtime
> - allowed - hardcoded field have precedence
> - allowed - format field values have precedence
> 
> I'd say either allow shadowing(with whatever precedence we this is better),
> or have the BUILD_BUG line in kernel..

I agree, if we can get the BUILD_BUG thing working that might be the
best option, otherwise we can do the precedence thing. We could even add
a syntax to resolve the namespace conflict in the latter case (eg. use
'$' PE_NAME to mean the hardcoded in case of conflict).



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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-15 11:18                                     ` Peter Zijlstra
@ 2012-02-15 13:32                                       ` Jiri Olsa
  2012-02-15 13:39                                         ` Peter Zijlstra
  0 siblings, 1 reply; 91+ messages in thread
From: Jiri Olsa @ 2012-02-15 13:32 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: acme, mingo, paulus, cjashfor, linux-kernel, Stephane Eranian

On Wed, Feb 15, 2012 at 12:18:32PM +0100, Peter Zijlstra wrote:
> On Wed, 2012-02-15 at 10:24 +0100, Jiri Olsa wrote:
> > On Tue, Feb 14, 2012 at 10:03:11PM +0100, Peter Zijlstra wrote:
> 
> > > These would be: period, config, config1, config2 and stephane's new
> > > branch_sample_type, although that might want to get a shorter name.
> > 
> > right, for pmu/.../ syntax there are allowed only fields from 'format'
> > directory are so far.. with exceptions like: cycles/period=100000/
> > 
> > so I'll hardcode following config fields:
> > 	config
> > 	config1
> > 	config2
> > 	period
> > 	branch_sample_type (branch, branch_type, branch_st  ???)
> 
> Uhmm,.. Stephane any particular preference on this?
> 
> > to be used in xxx/.../ syntax
> > 
> > also we need to choose some strategy of format field name shadowing
> > with hardcoded fields:
> > 
> > - BUILD_BUG in kernel PMU_FORMAT_ATTR
> > - not allowed.. report error in perf runtime
> > - allowed - hardcoded field have precedence
> > - allowed - format field values have precedence
> > 
> > I'd say either allow shadowing(with whatever precedence we this is better),
> > or have the BUILD_BUG line in kernel..
> 
> I agree, if we can get the BUILD_BUG thing working that might be the
> best option, otherwise we can do the precedence thing. We could even add
> a syntax to resolve the namespace conflict in the latter case (eg. use
> '$' PE_NAME to mean the hardcoded in case of conflict).
err.. I could not get the BUILD_BUG working... looks like string
comparison is something you are not supposed to do in cpp.. ;)

currently, I have the hardcoded fields to have a precedence,
and I'd workaround/fix it if there's need.. later I mean..

also, any idea when's the branch_sample_type going in?

thanks,
jirka

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

* Re: [PATCHv4 0/9] perf tool: parser generator for events parsing
  2012-02-15 13:32                                       ` Jiri Olsa
@ 2012-02-15 13:39                                         ` Peter Zijlstra
  0 siblings, 0 replies; 91+ messages in thread
From: Peter Zijlstra @ 2012-02-15 13:39 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, mingo, paulus, cjashfor, linux-kernel, Stephane Eranian

On Wed, 2012-02-15 at 14:32 +0100, Jiri Olsa wrote:
> also, any idea when's the branch_sample_type going in?

any day now, I've queued it and will see if it compiles runs in a bit
after which I'll try and throw it over the wall to mingo.

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

* [tip:perf/core] perf tools: Remove unused functions from debugfs object
  2012-01-27 14:34                         ` [PATCH 2/9] perf, tool: Remove unused functions from debugfs object Jiri Olsa
@ 2012-02-17  9:51                           ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: tip-bot for Jiri Olsa @ 2012-02-17  9:51 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa,
	tglx, cjashfor, mingo

Commit-ID:  2837609fefbfe8f1248bfce09d9f0b44d5eb713d
Gitweb:     http://git.kernel.org/tip/2837609fefbfe8f1248bfce09d9f0b44d5eb713d
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Fri, 27 Jan 2012 15:34:21 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 13 Feb 2012 23:25:38 -0200

perf tools: Remove unused functions from debugfs object

Following debugfs object functions are not referenced
within the code:

  int debugfs_valid_entry(const char *path);
  int debugfs_umount(void);
  int debugfs_write(const char *entry, const char *value);
  int debugfs_read(const char *entry, char *buffer, size_t size);
  void debugfs_force_cleanup(void);
  int debugfs_make_path(const char *element, char *buffer, int size);

Removing them.

Cc: Corey Ashford <cjashfor@linux.vnet.ibm.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/1327674868-10486-3-git-send-email-jolsa@redhat.com
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/debugfs.c |  141 ---------------------------------------------
 tools/perf/util/debugfs.h |    6 --
 2 files changed, 0 insertions(+), 147 deletions(-)

diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index ffc35e7..dd8b193 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -15,32 +15,6 @@ static const char *debugfs_known_mountpoints[] = {
 	0,
 };
 
-/* use this to force a umount */
-void debugfs_force_cleanup(void)
-{
-	debugfs_find_mountpoint();
-	debugfs_premounted = 0;
-	debugfs_umount();
-}
-
-/* construct a full path to a debugfs element */
-int debugfs_make_path(const char *element, char *buffer, int size)
-{
-	int len;
-
-	if (strlen(debugfs_mountpoint) == 0) {
-		buffer[0] = '\0';
-		return -1;
-	}
-
-	len = strlen(debugfs_mountpoint) + strlen(element) + 1;
-	if (len >= size)
-		return len+1;
-
-	snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
-	return 0;
-}
-
 static int debugfs_found;
 
 /* find the path to the mounted debugfs */
@@ -97,17 +71,6 @@ int debugfs_valid_mountpoint(const char *debugfs)
 	return 0;
 }
 
-
-int debugfs_valid_entry(const char *path)
-{
-	struct stat st;
-
-	if (stat(path, &st))
-		return -errno;
-
-	return 0;
-}
-
 static void debugfs_set_tracing_events_path(const char *mountpoint)
 {
 	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -149,107 +112,3 @@ void debugfs_set_path(const char *mountpoint)
 	snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
 	debugfs_set_tracing_events_path(mountpoint);
 }
-
-/* umount the debugfs */
-
-int debugfs_umount(void)
-{
-	char umountcmd[128];
-	int ret;
-
-	/* if it was already mounted, leave it */
-	if (debugfs_premounted)
-		return 0;
-
-	/* make sure it's a valid mount point */
-	ret = debugfs_valid_mountpoint(debugfs_mountpoint);
-	if (ret)
-		return ret;
-
-	snprintf(umountcmd, sizeof(umountcmd),
-		 "/bin/umount %s", debugfs_mountpoint);
-	return system(umountcmd);
-}
-
-int debugfs_write(const char *entry, const char *value)
-{
-	char path[PATH_MAX + 1];
-	int ret, count;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* get how many chars we're going to write */
-	count = strlen(value);
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDWR);
-	if (fd < 0)
-		return -errno;
-
-	while (count > 0) {
-		/* write it */
-		ret = write(fd, value, count);
-		if (ret <= 0) {
-			if (ret == EAGAIN)
-				continue;
-			close(fd);
-			return -errno;
-		}
-		count -= ret;
-	}
-
-	/* close it */
-	close(fd);
-
-	/* return success */
-	return 0;
-}
-
-/*
- * read a debugfs entry
- * returns the number of chars read or a negative errno
- */
-int debugfs_read(const char *entry, char *buffer, size_t size)
-{
-	char path[PATH_MAX + 1];
-	int ret;
-	int fd;
-
-	/* construct the path */
-	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
-
-	/* verify that it exists */
-	ret = debugfs_valid_entry(path);
-	if (ret)
-		return ret;
-
-	/* open the debugfs entry */
-	fd = open(path, O_RDONLY);
-	if (fd < 0)
-		return -errno;
-
-	do {
-		/* read it */
-		ret = read(fd, buffer, size);
-		if (ret == 0) {
-			close(fd);
-			return EOF;
-		}
-	} while (ret < 0 && errno == EAGAIN);
-
-	/* close it */
-	close(fd);
-
-	/* make *sure* there's a null character at the end */
-	buffer[ret] = '\0';
-
-	/* return the number of chars read */
-	return ret;
-}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 4a878f7..68f3e87 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -3,14 +3,8 @@
 
 const char *debugfs_find_mountpoint(void);
 int debugfs_valid_mountpoint(const char *debugfs);
-int debugfs_valid_entry(const char *path);
 char *debugfs_mount(const char *mountpoint);
-int debugfs_umount(void);
 void debugfs_set_path(const char *mountpoint);
-int debugfs_write(const char *entry, const char *value);
-int debugfs_read(const char *entry, char *buffer, size_t size);
-void debugfs_force_cleanup(void);
-int debugfs_make_path(const char *element, char *buffer, int size);
 
 extern char debugfs_mountpoint[];
 extern char tracing_events_path[];

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

* [tip:perf/core] perf tools: Add sysfs mountpoint interface
  2012-01-27 14:34                         ` [PATCH 3/9] perf, tool: Add sysfs mountpoint interface Jiri Olsa
@ 2012-02-17  9:52                           ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: tip-bot for Jiri Olsa @ 2012-02-17  9:52 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa,
	tglx, cjashfor, mingo

Commit-ID:  e90fda0635401225ca7c2343bea2f6d279347d10
Gitweb:     http://git.kernel.org/tip/e90fda0635401225ca7c2343bea2f6d279347d10
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Fri, 27 Jan 2012 15:34:22 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 13 Feb 2012 23:27:15 -0200

perf tools: Add sysfs mountpoint interface

Adding sysfs object to provide sysfs mount information in the same way
as debugfs object does.

The object provides following function:
  sysfs_find_mountpoint

which returns the sysfs mount mount.

Cc: Corey Ashford <cjashfor@linux.vnet.ibm.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/1327674868-10486-4-git-send-email-jolsa@redhat.com
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Makefile     |    2 +
 tools/perf/util/sysfs.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/sysfs.h |    6 ++++
 3 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 8359fa1..e011b50 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -259,6 +259,7 @@ LIB_H += util/callchain.h
 LIB_H += util/build-id.h
 LIB_H += util/debug.h
 LIB_H += util/debugfs.h
+LIB_H += util/sysfs.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
 LIB_H += util/evlist.h
@@ -305,6 +306,7 @@ LIB_OBJS += $(OUTPUT)util/build-id.o
 LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
+LIB_OBJS += $(OUTPUT)util/sysfs.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
 LIB_OBJS += $(OUTPUT)util/evlist.o
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
new file mode 100644
index 0000000..48c6902
--- /dev/null
+++ b/tools/perf/util/sysfs.c
@@ -0,0 +1,60 @@
+
+#include "util.h"
+#include "sysfs.h"
+
+static const char * const sysfs_known_mountpoints[] = {
+	"/sys",
+	0,
+};
+
+static int sysfs_found;
+char sysfs_mountpoint[PATH_MAX];
+
+static int sysfs_valid_mountpoint(const char *sysfs)
+{
+	struct statfs st_fs;
+
+	if (statfs(sysfs, &st_fs) < 0)
+		return -ENOENT;
+	else if (st_fs.f_type != (long) SYSFS_MAGIC)
+		return -ENOENT;
+
+	return 0;
+}
+
+const char *sysfs_find_mountpoint(void)
+{
+	const char * const *ptr;
+	char type[100];
+	FILE *fp;
+
+	if (sysfs_found)
+		return (const char *) sysfs_mountpoint;
+
+	ptr = sysfs_known_mountpoints;
+	while (*ptr) {
+		if (sysfs_valid_mountpoint(*ptr) == 0) {
+			sysfs_found = 1;
+			strcpy(sysfs_mountpoint, *ptr);
+			return sysfs_mountpoint;
+		}
+		ptr++;
+	}
+
+	/* give up and parse /proc/mounts */
+	fp = fopen("/proc/mounts", "r");
+	if (fp == NULL)
+		return NULL;
+
+	while (!sysfs_found &&
+	       fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
+		      sysfs_mountpoint, type) == 2) {
+
+		if (strcmp(type, "sysfs") == 0)
+			sysfs_found = 1;
+	}
+
+	fclose(fp);
+
+	return sysfs_found ? sysfs_mountpoint : NULL;
+}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
new file mode 100644
index 0000000..a813b72
--- /dev/null
+++ b/tools/perf/util/sysfs.h
@@ -0,0 +1,6 @@
+#ifndef __SYSFS_H__
+#define __SYSFS_H__
+
+const char *sysfs_find_mountpoint(void);
+
+#endif /* __DEBUGFS_H__ */

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

* [tip:perf/core] perf tools: Add bitmap_or function into bitmap object
  2012-01-27 14:34                         ` [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object Jiri Olsa
@ 2012-02-17  9:53                           ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 91+ messages in thread
From: tip-bot for Jiri Olsa @ 2012-02-17  9:53 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa,
	tglx, cjashfor, mingo

Commit-ID:  850f8127fa3666737881aecb3b16e8ede85e58f4
Gitweb:     http://git.kernel.org/tip/850f8127fa3666737881aecb3b16e8ede85e58f4
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Fri, 27 Jan 2012 15:34:23 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 13 Feb 2012 23:28:10 -0200

perf tools: Add bitmap_or function into bitmap object

Adding implementation os bitmap_or function to the bitmap object. It is
stolen from the kernel lib/bitmap.o object.

It is used in upcomming patches.

Cc: Corey Ashford <cjashfor@linux.vnet.ibm.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/1327674868-10486-5-git-send-email-jolsa@redhat.com
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/bitmap.c               |   10 ++++++++++
 tools/perf/util/include/linux/bitmap.h |   11 +++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
index 5e230ac..0a1adc1 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/perf/util/bitmap.c
@@ -19,3 +19,13 @@ int __bitmap_weight(const unsigned long *bitmap, int bits)
 
 	return w;
 }
+
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits)
+{
+	int k;
+	int nr = BITS_TO_LONGS(bits);
+
+	for (k = 0; k < nr; k++)
+		dst[k] = bitmap1[k] | bitmap2[k];
+}
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index eda4416..bb162e4 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -5,6 +5,8 @@
 #include <linux/bitops.h>
 
 int __bitmap_weight(const unsigned long *bitmap, int bits);
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+		 const unsigned long *bitmap2, int bits);
 
 #define BITMAP_LAST_WORD_MASK(nbits)					\
 (									\
@@ -32,4 +34,13 @@ static inline int bitmap_weight(const unsigned long *src, int nbits)
 	return __bitmap_weight(src, nbits);
 }
 
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+			     const unsigned long *src2, int nbits)
+{
+	if (small_const_nbits(nbits))
+		*dst = *src1 | *src2;
+	else
+		__bitmap_or(dst, src1, src2, nbits);
+}
+
 #endif /* _PERF_BITOPS_H */

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

end of thread, other threads:[~2012-02-17  9:54 UTC | newest]

Thread overview: 91+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-15 15:30 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
2011-12-15 15:30 ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Jiri Olsa
2011-12-16 14:02   ` Peter Zijlstra
2011-12-16 14:03     ` Peter Zijlstra
2011-12-20 10:31       ` Jiri Olsa
2011-12-20 10:47         ` Peter Zijlstra
2011-12-20 11:30           ` Peter Zijlstra
2011-12-20 11:39             ` Peter Zijlstra
2011-12-21 16:16               ` new syntax for perf event Jiri Olsa
2012-01-05  9:17                 ` Jiri Olsa
2012-01-05 14:10                 ` Peter Zijlstra
2012-01-09 15:28                   ` Jiri Olsa
2012-01-09 15:43                     ` Peter Zijlstra
2012-01-16 12:31                     ` [RFCv3 0/9] perf tool: parser generator for events parsing Jiri Olsa
2012-01-16 12:31                       ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
2012-01-16 12:31                       ` [PATCH 2/9] perf, tool: Remove unused functions from debugfs object Jiri Olsa
2012-01-16 12:31                       ` [PATCH 3/9] perf, tool: Add sysfs mountpoint interface Jiri Olsa
2012-01-16 12:31                       ` [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object Jiri Olsa
2012-01-16 12:31                       ` [PATCH 5/9] perf: Add sysfs format attribute for pmu device Jiri Olsa
2012-01-23 15:13                         ` Eric W. Biederman
2012-01-23 15:33                           ` Jiri Olsa
2012-01-24 15:22                             ` Peter Zijlstra
2012-01-24 19:40                               ` Eric W. Biederman
2012-01-25  8:54                                 ` Jiri Olsa
2012-01-26 16:26                         ` Peter Zijlstra
2012-01-27 12:32                           ` Jiri Olsa
2012-01-16 12:31                       ` [PATCH 6/9] perf, tool: Add parser generator for events parsing Jiri Olsa
2012-01-24 16:02                         ` Peter Zijlstra
2012-01-25  8:42                           ` Jiri Olsa
2012-01-16 12:31                       ` [PATCH 7/9] perf, tool: Add config options support for event parsing Jiri Olsa
2012-01-16 12:31                       ` [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition Jiri Olsa
2012-01-16 12:31                       ` [PATCH 9/9] perf, tool: Add support to specify pmu style event Jiri Olsa
2012-01-24 15:22                       ` [RFCv3 0/9] perf tool: parser generator for events parsing Peter Zijlstra
2012-01-24 16:26                       ` Peter Zijlstra
2012-01-25  0:53                         ` Greg KH
2012-01-25 10:49                           ` Peter Zijlstra
2012-01-25 14:37                             ` Jiri Olsa
2012-01-26 16:23                               ` Peter Zijlstra
2012-01-26 16:27                                 ` Greg KH
2012-01-25 17:01                             ` Greg KH
2012-01-27 14:34                       ` [PATCHv4 " Jiri Olsa
2012-01-27 14:34                         ` [PATCH 1/9] perf, tool: Make perf_evlist__splice_list_tail global Jiri Olsa
2012-02-07 19:31                           ` [tip:perf/core] perf evlist: Make splice_list_tail method public tip-bot for Jiri Olsa
2012-01-27 14:34                         ` [PATCH 2/9] perf, tool: Remove unused functions from debugfs object Jiri Olsa
2012-02-17  9:51                           ` [tip:perf/core] perf tools: " tip-bot for Jiri Olsa
2012-01-27 14:34                         ` [PATCH 3/9] perf, tool: Add sysfs mountpoint interface Jiri Olsa
2012-02-17  9:52                           ` [tip:perf/core] perf tools: " tip-bot for Jiri Olsa
2012-01-27 14:34                         ` [PATCH 4/9] perf, tool: Add bitmap_or function into bitmap object Jiri Olsa
2012-02-17  9:53                           ` [tip:perf/core] perf tools: " tip-bot for Jiri Olsa
2012-01-27 14:34                         ` [PATCH 5/9] perf: Adding sysfs group format attribute for pmu device Jiri Olsa
2012-01-27 21:08                           ` Corey Ashford
2012-01-27 21:19                             ` Peter Zijlstra
2012-02-01  0:47                               ` Corey Ashford
2012-01-30  9:52                             ` Jiri Olsa
2012-02-01  1:25                               ` Corey Ashford
2012-02-01 13:13                                 ` Jiri Olsa
2012-02-01 14:18                                   ` Peter Zijlstra
2012-02-01 14:31                                     ` Jiri Olsa
2012-02-01 14:40                                       ` Peter Zijlstra
2012-02-01 13:36                                 ` Peter Zijlstra
2012-02-02  0:33                                   ` Corey Ashford
2012-01-27 14:34                         ` [PATCH 6/9] perf, tool: Add parser generator for events parsing Jiri Olsa
2012-01-27 14:34                         ` [PATCH 7/9] perf, tool: Add config options support for event parsing Jiri Olsa
2012-01-27 14:34                         ` [PATCH 8/9] perf, tool: Add perf pmu object to access pmu format definition Jiri Olsa
2012-01-27 14:34                         ` [PATCH 9/9] perf, tool: Add support to specify pmu style event Jiri Olsa
2012-02-13 13:13                         ` [PATCHv4 0/9] perf tool: parser generator for events parsing Jiri Olsa
2012-02-14 16:28                         ` Peter Zijlstra
2012-02-14 16:43                           ` Peter Zijlstra
2012-02-14 20:20                             ` Peter Zijlstra
2012-02-14 20:57                               ` Peter Zijlstra
2012-02-14 21:03                                 ` Peter Zijlstra
2012-02-15  9:24                                   ` Jiri Olsa
2012-02-15 11:18                                     ` Peter Zijlstra
2012-02-15 13:32                                       ` Jiri Olsa
2012-02-15 13:39                                         ` Peter Zijlstra
2012-02-15  9:04                                 ` Jiri Olsa
2012-02-15 11:03                                   ` Peter Zijlstra
2011-12-22 19:32             ` [PATCH 1/3] perf, tool: Add " Vince Weaver
2011-12-19 14:37     ` Jiri Olsa
2011-12-20 10:29     ` [PATCHv2 0/2] perf tool: " Jiri Olsa
2011-12-20 10:29       ` [PATCHv2 1/2] perf, tool: Add " Jiri Olsa
2011-12-20 10:29       ` [PATCHv2 2/2] perf, tool: Add more automated tests for event parsing Jiri Olsa
2011-12-20 17:37   ` [PATCH 1/3] perf, tool: Add parser generator for events parsing Arnaldo Carvalho de Melo
2011-12-21  9:55     ` Jiri Olsa
2011-12-15 15:30 ` [PATCH 2/3] perf, tool: Add new event group management Jiri Olsa
2011-12-20 17:47   ` Arnaldo Carvalho de Melo
2011-12-20 21:20     ` Peter Zijlstra
2011-12-21 11:54       ` Arnaldo Carvalho de Melo
2011-12-15 15:30 ` [PATCH 3/3] perf, tool: Add more automated tests for event parsing Jiri Olsa
2011-12-20 17:38   ` Arnaldo Carvalho de Melo
2011-12-21  8:47   ` [tip:perf/core] perf test: " tip-bot for Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).