All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/3] perf tool: Add new event group management
@ 2012-03-20 18:15 Jiri Olsa
  2012-03-20 18:15 ` [PATCH 1/3] perf, tool: Fix various casting issues for 32 bits Jiri Olsa
                   ` (2 more replies)
  0 siblings, 3 replies; 28+ messages in thread
From: Jiri Olsa @ 2012-03-20 18:15 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec; +Cc: linux-kernel

hi,
adding support for creating event groups based on the way they
are specified on the command line. Also attaching several fixies
to current code.

attached patches:
 1/3 perf, tool: Fix various casting issues for 32 bits
 2/3 perf, tool: Fix modifier to be applied on correct events
 3/3 perf, tool: Add new event group management

I added automated tests and run some record and stats tests
based on the examples (attached in the 3/3 changelog), and
so far so good..

thanks for comments,
jirka
---
 tools/perf/Makefile                  |    2 +
 tools/perf/builtin-record.c          |    8 +-
 tools/perf/builtin-stat.c            |   10 +-
 tools/perf/builtin-test.c            |  126 +++++++-
 tools/perf/builtin-top.c             |    8 +-
 tools/perf/perf.h                    |    3 +-
 tools/perf/util/evlist.c             |    4 +-
 tools/perf/util/evlist.h             |    3 +-
 tools/perf/util/evsel.c              |   32 ++-
 tools/perf/util/evsel.h              |    9 +-
 tools/perf/util/group.c              |   22 ++
 tools/perf/util/group.h              |   32 ++
 tools/perf/util/header.c             |    2 +-
 tools/perf/util/parse-events-bison.c |  675 +++++++++++++++++++---------------
 tools/perf/util/parse-events-bison.h |   15 +-
 tools/perf/util/parse-events.c       |   47 ++-
 tools/perf/util/parse-events.h       |   10 +-
 tools/perf/util/parse-events.y       |   40 ++-
 tools/perf/util/python.c             |    4 +
 tools/perf/util/top.h                |    2 +-
 20 files changed, 687 insertions(+), 367 deletions(-)

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

* [PATCH 1/3] perf, tool: Fix various casting issues for 32 bits
  2012-03-20 18:15 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
@ 2012-03-20 18:15 ` Jiri Olsa
  2012-03-23  8:29   ` [tip:perf/urgent] perf tools: " tip-bot for Jiri Olsa
  2012-03-20 18:15 ` [PATCH 2/3] perf, tool: Fix modifier to be applied on correct events Jiri Olsa
  2012-03-20 18:15 ` [PATCH 3/3] perf, tool: Add new event group management Jiri Olsa
  2 siblings, 1 reply; 28+ messages in thread
From: Jiri Olsa @ 2012-03-20 18:15 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

- util/parse-events.c(parse_events_add_breakpoint)
  need to use unsigned long instead of u64, otherwise
  we get following gcc error on 32 bits:
     error: cast from pointer to integer of different size

- util/header.c(print_event_desc)
  cannot retype to signed type, otherwise we get following
  gcc error on 32 bits:
     error: comparison between signed and unsigned integer expressions

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

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index fcd9cf3..4c7c2d7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1177,7 +1177,7 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
 		goto error;
 
 	msz = sizeof(attr);
-	if (sz < (ssize_t)msz)
+	if (sz < msz)
 		msz = sz;
 
 	for (i = 0 ; i < nre; i++) {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 201b40f..f542a63 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -569,7 +569,7 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
 	char name[MAX_NAME_LEN];
 
 	memset(&attr, 0, sizeof(attr));
-	attr.bp_addr = (u64) ptr;
+	attr.bp_addr = (unsigned long) ptr;
 
 	if (parse_breakpoint_type(type, &attr))
 		return -EINVAL;
-- 
1.7.7.6


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

* [PATCH 2/3] perf, tool: Fix modifier to be applied on correct events
  2012-03-20 18:15 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
  2012-03-20 18:15 ` [PATCH 1/3] perf, tool: Fix various casting issues for 32 bits Jiri Olsa
@ 2012-03-20 18:15 ` Jiri Olsa
  2012-03-23  8:30   ` [tip:perf/urgent] perf tools: " tip-bot for Jiri Olsa
  2012-03-20 18:15 ` [PATCH 3/3] perf, tool: Add new event group management Jiri Olsa
  2 siblings, 1 reply; 28+ messages in thread
From: Jiri Olsa @ 2012-03-20 18:15 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  Cc: linux-kernel, Jiri Olsa

The event modifier needs to be applied only on the event definition
it is attached to.

The current state is that in case of multiple events definition
(in single '-e' option, separated by ',') all will get modifier
of the last one.

Fixing this by adding separated list for each event definition,
so the modifier is applied only to proper event(s). Added
automated test to catch this, plus some other modifier tests.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-test.c            |  116 ++++++-
 tools/perf/util/parse-events-bison.c |  675 +++++++++++++++++++---------------
 tools/perf/util/parse-events-bison.h |   15 +-
 tools/perf/util/parse-events.c       |   27 +-
 tools/perf/util/parse-events.h       |    7 +-
 tools/perf/util/parse-events.y       |   40 ++-
 6 files changed, 543 insertions(+), 337 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 8687423..1c5b980 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -877,6 +877,58 @@ static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
 	return test__checkevent_genhw(evlist);
 }
 
+static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint(evlist);
+}
+
+static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_x(evlist);
+}
+
+static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_r(evlist);
+}
+
+static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_w(evlist);
+}
+
 static int test__checkevent_pmu(struct perf_evlist *evlist)
 {
 
@@ -893,6 +945,47 @@ static int test__checkevent_pmu(struct perf_evlist *evlist)
 	return 0;
 }
 
+static int test__checkevent_list(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* r1 */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* syscalls:sys_enter_open:k */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+		evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* 1:1:hp */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -975,9 +1068,29 @@ static struct test__event_st {
 		.check = test__checkevent_genhw_modifier,
 	},
 	{
+		.name  = "mem:0:u",
+		.check = test__checkevent_breakpoint_modifier,
+	},
+	{
+		.name  = "mem:0:x:k",
+		.check = test__checkevent_breakpoint_x_modifier,
+	},
+	{
+		.name  = "mem:0:r:hp",
+		.check = test__checkevent_breakpoint_r_modifier,
+	},
+	{
+		.name  = "mem:0:w:up",
+		.check = test__checkevent_breakpoint_w_modifier,
+	},
+	{
 		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
 		.check = test__checkevent_pmu,
 	},
+	{
+		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
+		.check = test__checkevent_list,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
@@ -1003,10 +1116,9 @@ static int test__parse_events(void)
 		}
 
 		ret = e->check(evlist);
+		perf_evlist__delete(evlist);
 		if (ret)
 			break;
-
-		perf_evlist__delete(evlist);
 	}
 
 	return ret;
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
index 4a0fd6d..4a4e02a 100644
--- a/tools/perf/util/parse-events-bison.c
+++ b/tools/perf/util/parse-events-bison.c
@@ -1,9 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.4.3.  */
+/* A Bison parser, made by GNU Bison 2.5.  */
 
-/* Skeleton implementation for Bison's Yacc-like parsers in C
+/* Bison implementation for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2009, 2010 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2011 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
@@ -45,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.4.3"
+#define YYBISON_VERSION "2.5"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -74,8 +73,8 @@
 
 /* Copy the first part of user declarations.  */
 
-/* Line 189 of yacc.c  */
-#line 6 "util/parse-events.y"
+/* Line 268 of yacc.c  */
+#line 7 "util/parse-events.y"
 
 
 #define YYDEBUG 1
@@ -96,8 +95,8 @@ do { \
 
 
 
-/* Line 189 of yacc.c  */
-#line 101 "util/parse-events-bison.c"
+/* Line 268 of yacc.c  */
+#line 100 "util/parse-events-bison.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -145,8 +144,8 @@ do { \
 typedef union YYSTYPE
 {
 
-/* Line 214 of yacc.c  */
-#line 45 "util/parse-events.y"
+/* Line 293 of yacc.c  */
+#line 46 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
@@ -155,8 +154,8 @@ typedef union YYSTYPE
 
 
 
-/* Line 214 of yacc.c  */
-#line 160 "util/parse-events-bison.c"
+/* Line 293 of yacc.c  */
+#line 159 "util/parse-events-bison.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -167,8 +166,8 @@ typedef union YYSTYPE
 /* Copy the second part of user declarations.  */
 
 
-/* Line 264 of yacc.c  */
-#line 172 "util/parse-events-bison.c"
+/* Line 343 of yacc.c  */
+#line 171 "util/parse-events-bison.c"
 
 #ifdef short
 # undef short
@@ -271,11 +270,11 @@ YYID (yyi)
 #    define alloca _alloca
 #   else
 #    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (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
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
 #     endif
 #    endif
 #   endif
@@ -298,24 +297,24 @@ YYID (yyi)
 #  ifndef YYSTACK_ALLOC_MAXIMUM
 #   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
 #  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
        && ! ((defined YYMALLOC || defined malloc) \
 	     && (defined YYFREE || defined free)))
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
 #   endif
 #  endif
 #  ifndef YYMALLOC
 #   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+#   if ! defined malloc && ! defined EXIT_SUCCESS && (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__ \
+#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
@@ -344,23 +343,7 @@ union yyalloc
      ((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
+# define YYCOPY_NEEDED 1
 
 /* Relocate STACK from its old location to the new one.  The
    local variables YYSIZE and YYSTACKSIZE give the old and new number of
@@ -380,6 +363,26 @@ union yyalloc
 
 #endif
 
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* 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
+#endif /* !YYCOPY_NEEDED */
+
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  25
 /* YYLAST -- Last index in YYTABLE.  */
@@ -463,10 +466,10 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    54,    54,    54,    57,    62,    64,    65,    66,    67,
-      68,    69,    70,    73,    80,    89,    98,   103,   108,   114,
-     119,   125,   131,   137,   143,   153,   165,   174,   183,   192,
-     200,   208,   208,   210,   210,   210
+       0,    55,    55,    55,    58,    69,    74,    75,    76,    77,
+      78,    79,    80,    83,    90,    99,   108,   113,   118,   124,
+     129,   135,   141,   147,   153,   163,   175,   184,   193,   202,
+     210,   218,   218,   220,   220,   220
 };
 #endif
 
@@ -514,8 +517,8 @@ static const yytype_uint8 yyr2[] =
        1,     1,     0,     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
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE doesn't specify something else to do.  Zero
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
@@ -556,8 +559,7 @@ static const yytype_int8 yypgoto[] =
 
 /* 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.  */
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
@@ -568,6 +570,12 @@ static const yytype_uint8 yytable[] =
       38,    54,     0,    43
 };
 
+#define yypact_value_is_default(yystate) \
+  ((yystate) == (-15))
+
+#define yytable_value_is_error(yytable_value) \
+  YYID (0)
+
 static const yytype_int8 yycheck[] =
 {
       14,    15,    16,     0,     3,     4,     5,    16,     7,    18,
@@ -622,13 +630,12 @@ do								\
     {								\
       yychar = (Token);						\
       yylval = (Value);						\
-      yytoken = YYTRANSLATE (yychar);				\
       YYPOPSTACK (1);						\
       goto yybackup;						\
     }								\
   else								\
     {								\
-      yyerror (list, idx, YY_("syntax error: cannot back up")); \
+      yyerror (list_all, list_event, idx, YY_("syntax error: cannot back up")); \
       YYERROR;							\
     }								\
 while (YYID (0))
@@ -664,19 +671,10 @@ 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.  */
+/* This macro is provided for backward compatibility. */
 
 #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
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 #endif
 
 
@@ -708,7 +706,7 @@ do {									  \
     {									  \
       YYFPRINTF (stderr, "%s ", Title);					  \
       yy_symbol_print (stderr,						  \
-		  Type, Value, list, idx); \
+		  Type, Value, list_all, list_event, idx); \
       YYFPRINTF (stderr, "\n");						  \
     }									  \
 } while (YYID (0))
@@ -722,20 +720,22 @@ do {									  \
 #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)
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx)
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, list_all, list_event, idx)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
   if (!yyvaluep)
     return;
-  YYUSE (list);
+  YYUSE (list_all);
+  YYUSE (list_event);
   YYUSE (idx);
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
@@ -758,14 +758,15 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx)
 #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)
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, list, idx)
+yy_symbol_print (yyoutput, yytype, yyvaluep, list_all, list_event, idx)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
@@ -774,7 +775,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, list, idx)
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx);
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, list_all, list_event, idx);
   YYFPRINTF (yyoutput, ")");
 }
 
@@ -817,13 +818,14 @@ do {								\
 #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)
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yy_reduce_print (yyvsp, yyrule, list, idx)
+yy_reduce_print (yyvsp, yyrule, list_all, list_event, idx)
     YYSTYPE *yyvsp;
     int yyrule;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
@@ -838,7 +840,7 @@ yy_reduce_print (yyvsp, yyrule, list, idx)
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
 		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       , list, idx);
+		       		       , list_all, list_event, idx);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -846,7 +848,7 @@ yy_reduce_print (yyvsp, yyrule, list, idx)
 # define YY_REDUCE_PRINT(Rule)		\
 do {					\
   if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule, list, idx); \
+    yy_reduce_print (yyvsp, Rule, list_all, list_event, idx); \
 } while (YYID (0))
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
@@ -876,7 +878,6 @@ int yydebug;
 # define YYMAXDEPTH 10000
 #endif
 
-\f
 
 #if YYERROR_VERBOSE
 
@@ -979,115 +980,142 @@ yytnamerr (char *yyres, const char *yystr)
 }
 # 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];
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
 
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  YYSIZE_T yysize1;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = 0;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - Assume YYFAIL is not used.  It's too flawed to consider.  See
+       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+       for details.  YYERROR is fine as it does not invoke this
+       function.
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
     {
-      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;
-	  }
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          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 yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+                if (! (yysize <= yysize1
+                       && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                  return 2;
+                yysize = yysize1;
+              }
+        }
+    }
 
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
 
-      if (yysize_overflow)
-	return YYSIZE_MAXIMUM;
+  yysize1 = yysize + yystrlen (yyformat);
+  if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+    return 2;
+  yysize = yysize1;
 
-      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;
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
     }
+
+  /* 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 = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
 }
 #endif /* YYERROR_VERBOSE */
-\f
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
@@ -1097,19 +1125,21 @@ yysyntax_error (char *yyresult, int yystate, int yychar)
 #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)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yydestruct (yymsg, yytype, yyvaluep, list, idx)
+yydestruct (yymsg, yytype, yyvaluep, list_all, list_event, idx)
     const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
   YYUSE (yyvaluep);
-  YYUSE (list);
+  YYUSE (list_all);
+  YYUSE (list_event);
   YYUSE (idx);
 
   if (!yymsg)
@@ -1124,6 +1154,7 @@ yydestruct (yymsg, yytype, yyvaluep, list, idx)
     }
 }
 
+
 /* Prevent warnings from -Wmissing-prototypes.  */
 #ifdef YYPARSE_PARAM
 #if defined __STDC__ || defined __cplusplus
@@ -1133,7 +1164,7 @@ int yyparse ();
 #endif
 #else /* ! YYPARSE_PARAM */
 #if defined __STDC__ || defined __cplusplus
-int yyparse (struct list_head *list, int *idx);
+int yyparse (struct list_head *list_all, struct list_head *list_event, int *idx);
 #else
 int yyparse ();
 #endif
@@ -1150,10 +1181,9 @@ YYSTYPE yylval;
 int yynerrs;
 
 
-
-/*-------------------------.
-| yyparse or yypush_parse.  |
-`-------------------------*/
+/*----------.
+| yyparse.  |
+`----------*/
 
 #ifdef YYPARSE_PARAM
 #if (defined __STDC__ || defined __C99__FUNC__ \
@@ -1169,17 +1199,16 @@ yyparse (YYPARSE_PARAM)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 int
-yyparse (struct list_head *list, int *idx)
+yyparse (struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 int
-yyparse (list, idx)
-    struct list_head *list;
+yyparse (list_all, list_event, idx)
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 #endif
 {
-
-
     int yystate;
     /* Number of tokens to shift before error messages enabled.  */
     int yyerrstatus;
@@ -1334,7 +1363,7 @@ yybackup:
 
   /* First try to decide what to do without reference to lookahead token.  */
   yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
+  if (yypact_value_is_default (yyn))
     goto yydefault;
 
   /* Not known => get a lookahead token if don't already have one.  */
@@ -1365,8 +1394,8 @@ yybackup:
   yyn = yytable[yyn];
   if (yyn <= 0)
     {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-	goto yyerrlab;
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1421,124 +1450,139 @@ yyreduce:
     {
         case 4:
 
-/* Line 1464 of yacc.c  */
-#line 58 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 59 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_modifier(list, (yyvsp[(2) - (2)].str)));
-;}
+	/*
+	 * Apply modifier on all events added by single event definition
+	 * (there could be more events added for multiple tracepoint
+	 * definitions via '*?'.
+	 */
+	ABORT_ON(parse_events_modifier(list_event, (yyvsp[(2) - (2)].str)));
+	parse_events_update_lists(list_event, list_all);
+}
+    break;
+
+  case 5:
+
+/* Line 1806 of yacc.c  */
+#line 70 "util/parse-events.y"
+    {
+	parse_events_update_lists(list_event, list_all);
+}
     break;
 
   case 13:
 
-/* Line 1464 of yacc.c  */
-#line 74 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 84 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_pmu(list, idx, (yyvsp[(1) - (4)].str), (yyvsp[(3) - (4)].head)));
+	ABORT_ON(parse_events_add_pmu(list_event, 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 81 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 91 "util/parse-events.y"
     {
 	int type = (yyvsp[(1) - (4)].num) >> 16;
 	int config = (yyvsp[(1) - (4)].num) & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config, (yyvsp[(3) - (4)].head)));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, (yyvsp[(3) - (4)].head)));
 	parse_events__free_terms((yyvsp[(3) - (4)].head));
-;}
+}
     break;
 
   case 15:
 
-/* Line 1464 of yacc.c  */
-#line 90 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 100 "util/parse-events.y"
     {
 	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));
-;}
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
+}
     break;
 
   case 16:
 
-/* Line 1464 of yacc.c  */
-#line 99 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 109 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
-;}
+	ABORT_ON(parse_events_add_cache(list_event, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
+}
     break;
 
   case 17:
 
-/* Line 1464 of yacc.c  */
-#line 104 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 114 "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_event, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
+}
     break;
 
   case 18:
 
-/* Line 1464 of yacc.c  */
-#line 109 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 119 "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_event, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
+}
     break;
 
   case 19:
 
-/* Line 1464 of yacc.c  */
-#line 115 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 125 "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_breakpoint(list_event, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
+}
     break;
 
   case 20:
 
-/* Line 1464 of yacc.c  */
-#line 120 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 130 "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_event, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
+}
     break;
 
   case 21:
 
-/* Line 1464 of yacc.c  */
-#line 126 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 136 "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_tracepoint(list_event, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
+}
     break;
 
   case 22:
 
-/* Line 1464 of yacc.c  */
-#line 132 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 142 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
-;}
+	ABORT_ON(parse_events_add_numeric(list_event, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
+}
     break;
 
   case 23:
 
-/* Line 1464 of yacc.c  */
-#line 138 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 148 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
-;}
+	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
+}
     break;
 
   case 24:
 
-/* Line 1464 of yacc.c  */
-#line 144 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 154 "util/parse-events.y"
     {
 	struct list_head *head = (yyvsp[(1) - (3)].head);
 	struct parse_events__term *term = (yyvsp[(3) - (3)].term);
@@ -1546,13 +1590,13 @@ yyreduce:
 	ABORT_ON(!head);
 	list_add_tail(&term->list, head);
 	(yyval.head) = (yyvsp[(1) - (3)].head);
-;}
+}
     break;
 
   case 25:
 
-/* Line 1464 of yacc.c  */
-#line 154 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 164 "util/parse-events.y"
     {
 	struct list_head *head = malloc(sizeof(*head));
 	struct parse_events__term *term = (yyvsp[(1) - (1)].term);
@@ -1561,78 +1605,89 @@ yyreduce:
 	INIT_LIST_HEAD(head);
 	list_add_tail(&term->list, head);
 	(yyval.head) = head;
-;}
+}
     break;
 
   case 26:
 
-/* Line 1464 of yacc.c  */
-#line 166 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 176 "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 27:
 
-/* Line 1464 of yacc.c  */
-#line 175 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 185 "util/parse-events.y"
     {
 	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;
 
   case 28:
 
-/* Line 1464 of yacc.c  */
-#line 184 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 194 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
 	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
 		 (yyvsp[(1) - (1)].str), NULL, 1));
 	(yyval.term) = term;
-;}
+}
     break;
 
   case 29:
 
-/* Line 1464 of yacc.c  */
-#line 193 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 203 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
 	ABORT_ON(parse_events__new_term(&term, (yyvsp[(1) - (3)].num), NULL, NULL, (yyvsp[(3) - (3)].num)));
 	(yyval.term) = term;
-;}
+}
     break;
 
   case 30:
 
-/* Line 1464 of yacc.c  */
-#line 201 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 211 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
 	ABORT_ON(parse_events__new_term(&term, (yyvsp[(1) - (1)].num), NULL, NULL, 1));
 	(yyval.term) = term;
-;}
+}
     break;
 
 
 
-/* Line 1464 of yacc.c  */
-#line 1634 "util/parse-events-bison.c"
+/* Line 1806 of yacc.c  */
+#line 1678 "util/parse-events-bison.c"
       default: break;
     }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
@@ -1660,44 +1715,47 @@ yyreduce:
 | yyerrlab -- here on detecting error |
 `------------------------------------*/
 yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
       ++yynerrs;
 #if ! YYERROR_VERBOSE
-      yyerror (list, idx, YY_("syntax error"));
+      yyerror (list_all, list_event, idx, YY_("syntax error"));
 #else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
       {
-	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;
-	  }
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (list_all, list_event, idx, yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
       }
+# undef YYSYNTAX_ERROR
 #endif
     }
 
@@ -1717,7 +1775,7 @@ yyerrlab:
       else
 	{
 	  yydestruct ("Error: discarding",
-		      yytoken, &yylval, list, idx);
+		      yytoken, &yylval, list_all, list_event, idx);
 	  yychar = YYEMPTY;
 	}
     }
@@ -1756,7 +1814,7 @@ yyerrlab1:
   for (;;)
     {
       yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
+      if (!yypact_value_is_default (yyn))
 	{
 	  yyn += YYTERROR;
 	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -1773,7 +1831,7 @@ yyerrlab1:
 
 
       yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp, list, idx);
+		  yystos[yystate], yyvsp, list_all, list_event, idx);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -1808,15 +1866,20 @@ yyabortlab:
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
-  yyerror (list, idx, YY_("memory exhausted"));
+  yyerror (list_all, list_event, idx, YY_("memory exhausted"));
   yyresult = 2;
   /* Fall through.  */
 #endif
 
 yyreturn:
   if (yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-		 yytoken, &yylval, list, idx);
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval, list_all, list_event, idx);
+    }
   /* Do not reclaim the symbols of the rule which action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
@@ -1824,7 +1887,7 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp, list, idx);
+		  yystos[*yyssp], yyvsp, list_all, list_event, idx);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
@@ -1841,11 +1904,13 @@ yyreturn:
 
 
 
-/* Line 1684 of yacc.c  */
-#line 212 "util/parse-events.y"
+/* Line 2067 of yacc.c  */
+#line 222 "util/parse-events.y"
 
 
-void parse_events_error(struct list_head *list __used, int *idx __used,
+void parse_events_error(struct list_head *list_all __used,
+			struct list_head *list_event __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
index c58b765..0be3e5a 100644
--- a/tools/perf/util/parse-events-bison.h
+++ b/tools/perf/util/parse-events-bison.h
@@ -1,9 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.4.3.  */
+/* A Bison parser, made by GNU Bison 2.5.  */
 
-/* Skeleton interface for Bison's Yacc-like parsers in C
+/* Bison interface for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2009, 2010 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2011 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
@@ -59,8 +58,8 @@
 typedef union YYSTYPE
 {
 
-/* Line 1685 of yacc.c  */
-#line 45 "util/parse-events.y"
+/* Line 2068 of yacc.c  */
+#line 46 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
@@ -69,8 +68,8 @@ typedef union YYSTYPE
 
 
 
-/* Line 1685 of yacc.c  */
-#line 74 "util/parse-events-bison.h"
+/* Line 2068 of yacc.c  */
+#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 f542a63..5b3a0ef 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,7 +23,8 @@ struct event_symbol {
 	const char	*alias;
 };
 
-int parse_events_parse(struct list_head *list, int *idx);
+int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
+		       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
@@ -671,6 +672,18 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
 	return add_event(list, idx, &attr, (char *) "pmu");
 }
 
+void parse_events_update_lists(struct list_head *list_event,
+			       struct list_head *list_all)
+{
+	/*
+	 * Called for single event definition. Update the
+	 * 'all event' list, and reinit the 'signle event'
+	 * list, for next event definition.
+	 */
+	list_splice_tail(list_event, list_all);
+	INIT_LIST_HEAD(list_event);
+}
+
 int parse_events_modifier(struct list_head *list, char *str)
 {
 	struct perf_evsel *evsel;
@@ -736,14 +749,14 @@ int parse_events_modifier(struct list_head *list, char *str)
 
 int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
-	struct perf_evsel *evsel, *h;
 	LIST_HEAD(list);
+	LIST_HEAD(list_tmp);
 	YY_BUFFER_STATE buffer;
 	int ret, idx = evlist->nr_entries;
 
 	buffer = parse_events__scan_string(str);
 
-	ret = parse_events_parse(&list, &idx);
+	ret = parse_events_parse(&list, &list_tmp, &idx);
 
 	parse_events__flush_buffer(buffer);
 	parse_events__delete_buffer(buffer);
@@ -754,9 +767,11 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 		return 0;
 	}
 
-	list_for_each_entry_safe(evsel, h, &list, node)
-		perf_evsel__delete(evsel);
-
+	/*
+	 * There are 2 users - builtin-record and builtin-test objects.
+	 * Both call perf_evlist__delete in case of error, so we dont
+	 * need to bother.
+	 */
 	fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
 	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
 	return ret;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 6d7c74b..ca069f8 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -76,8 +76,11 @@ 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);
+void parse_events_update_lists(struct list_head *list_event,
+			       struct list_head *list_all);
+void parse_events_error(struct list_head *list_all,
+			struct list_head *list_event,
+			int *idx, char const *msg);
 
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 3a53019..d9637da 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,6 +1,7 @@
 
 %name-prefix "parse_events_"
-%parse-param {struct list_head *list}
+%parse-param {struct list_head *list_all}
+%parse-param {struct list_head *list_event}
 %parse-param {int *idx}
 
 %{
@@ -56,10 +57,19 @@ events ',' event | event
 event:
 event_def PE_MODIFIER_EVENT
 {
-	ABORT_ON(parse_events_modifier(list, $2));
+	/*
+	 * Apply modifier on all events added by single event definition
+	 * (there could be more events added for multiple tracepoint
+	 * definitions via '*?'.
+	 */
+	ABORT_ON(parse_events_modifier(list_event, $2));
+	parse_events_update_lists(list_event, list_all);
 }
 |
 event_def
+{
+	parse_events_update_lists(list_event, list_all);
+}
 
 event_def: event_pmu |
 	   event_legacy_symbol |
@@ -72,7 +82,7 @@ event_def: event_pmu |
 event_pmu:
 PE_NAME '/' event_config '/'
 {
-	ABORT_ON(parse_events_add_pmu(list, idx, $1, $3));
+	ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
 	parse_events__free_terms($3);
 }
 
@@ -82,7 +92,7 @@ PE_VALUE_SYM '/' event_config '/'
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config, $3));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
 	parse_events__free_terms($3);
 }
 |
@@ -91,52 +101,52 @@ 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));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
 }
 
 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));
+	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
-	ABORT_ON(parse_events_add_cache(list, idx, $1, $3, NULL));
+	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
 }
 |
 PE_NAME_CACHE_TYPE
 {
-	ABORT_ON(parse_events_add_cache(list, idx, $1, NULL, NULL));
+	ABORT_ON(parse_events_add_cache(list_event, 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));
+	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
 }
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
-	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) $2, NULL));
+	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
 }
 
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
-	ABORT_ON(parse_events_add_tracepoint(list, idx, $1, $3));
+	ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
 }
 
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3, NULL));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
 }
 
 event_legacy_raw:
 PE_RAW
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1, NULL));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
 }
 
 event_config:
@@ -211,7 +221,9 @@ sep_slash_dc: '/' | ':' |
 
 %%
 
-void parse_events_error(struct list_head *list __used, int *idx __used,
+void parse_events_error(struct list_head *list_all __used,
+			struct list_head *list_event __used,
+			int *idx __used,
 			char const *msg __used)
 {
 }
-- 
1.7.7.6


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

* [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:15 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
  2012-03-20 18:15 ` [PATCH 1/3] perf, tool: Fix various casting issues for 32 bits Jiri Olsa
  2012-03-20 18:15 ` [PATCH 2/3] perf, tool: Fix modifier to be applied on correct events Jiri Olsa
@ 2012-03-20 18:15 ` Jiri Olsa
  2012-03-20 18:44   ` Peter Zijlstra
                     ` (2 more replies)
  2 siblings, 3 replies; 28+ messages in thread
From: Jiri Olsa @ 2012-03-20 18:15 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec
  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

Updated automated test to check on group_leader settings.

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-test.c      |   10 ++++++++++
 tools/perf/builtin-top.c       |    8 +++++---
 tools/perf/perf.h              |    3 ++-
 tools/perf/util/evlist.c       |    4 ++--
 tools/perf/util/evlist.h       |    3 ++-
 tools/perf/util/evsel.c        |   32 +++++++++++++++++++++++++-------
 tools/perf/util/evsel.h        |    9 ++++++---
 tools/perf/util/group.c        |   22 ++++++++++++++++++++++
 tools/perf/util/group.h        |   32 ++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events.c |   18 ++++++++++++++++++
 tools/perf/util/parse-events.h |    3 ---
 tools/perf/util/python.c       |    4 ++++
 tools/perf/util/top.h          |    2 +-
 16 files changed, 142 insertions(+), 28 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 b492e3a..ea10b29 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -317,6 +317,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
@@ -378,6 +379,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 be4e1ee..a2c7dc2 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>
@@ -203,7 +204,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;
 fallback_missing_features:
 		if (opts->exclude_guest_missing)
@@ -791,8 +792,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",
+		     group_parse, 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 c941bb6..d0d3859 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 enum perf_group_opt	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)
@@ -1055,8 +1056,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",
+		     group_parse, PERF_GROUP_NONE),
 	OPT_BOOLEAN('c', "scale", &scale,
 		    "scale/normalize counters"),
 	OPT_INCR('v', "verbose", &verbose,
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 1c5b980..babdd77 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -14,6 +14,7 @@
 #include "util/symbol.h"
 #include "util/thread_map.h"
 #include "util/pmu.h"
+#include "util/group.h"
 #include "../../include/linux/hw_breakpoint.h"
 
 #include <sys/mman.h>
@@ -948,11 +949,14 @@ static int test__checkevent_pmu(struct perf_evlist *evlist)
 static int test__checkevent_list(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel;
+	struct perf_evsel *parsed_leader;
 
 	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
 
 	/* r1 */
 	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	parsed_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 config1", 0 == evsel->attr.config1);
@@ -961,6 +965,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
 	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 parsed_leader", parsed_leader);
 
 	/* syscalls:sys_enter_open:k */
 	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
@@ -973,6 +978,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
 	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 parsed_leader",
+			evsel->parsed_leader == parsed_leader);
 
 	/* 1:1:hp */
 	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
@@ -982,6 +989,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
 	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 parsed_leader",
+			evsel->parsed_leader == parsed_leader);
 
 	return 0;
 }
@@ -1168,6 +1177,7 @@ static int test__PERF_RECORD(void)
 		.no_delay   = true,
 		.freq	    = 10,
 		.mmap_pages = 256,
+		.group      = PERF_GROUP_NONE,
 	};
 	cpu_set_t *cpu_mask = NULL;
 	size_t cpu_mask_size = 0;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e3c63ae..fd04361 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"
 
@@ -850,7 +851,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;
@@ -1153,8 +1154,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",
+		    group_parse, 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 89e3355..b80b69d 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -108,6 +108,7 @@ void get_term_dimensions(struct winsize *ws);
 
 #include "../../include/linux/perf_event.h"
 #include "util/types.h"
+#include "util/group.h"
 #include <stdbool.h>
 
 struct perf_mmap {
@@ -212,7 +213,6 @@ struct perf_record_opts {
 	const char   *target_tid;
 	uid_t	     uid;
 	bool	     call_graph;
-	bool	     group;
 	bool	     inherit_stat;
 	bool	     no_delay;
 	bool	     no_inherit;
@@ -232,6 +232,7 @@ struct perf_record_opts {
 	u64	     default_interval;
 	u64	     user_interval;
 	const char   *cpu_list;
+	enum perf_group_opt group;
 };
 
 #endif
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 1986d80..c0bcffd 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -740,7 +740,7 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
 	evlist->selected = evsel;
 }
 
-int perf_evlist__open(struct perf_evlist *evlist, bool group)
+int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group)
 {
 	struct perf_evsel *evsel, *first;
 	int err, ncpus, nthreads;
@@ -750,7 +750,7 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group)
 	list_for_each_entry(evsel, &evlist->entries, node) {
 		struct xyarray *group_fd = NULL;
 
-		if (group && evsel != first)
+		if (group_is_single(group) && evsel != first)
 			group_fd = first->fd;
 
 		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 21f1c9e..3115e8d 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -6,6 +6,7 @@
 #include "../perf.h"
 #include "event.h"
 #include "util.h"
+#include "group.h"
 #include <unistd.h>
 
 struct pollfd;
@@ -78,7 +79,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
 
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
 
-int perf_evlist__open(struct perf_evlist *evlist, bool group);
+int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group);
 
 void perf_evlist__config_attrs(struct perf_evlist *evlist,
 			       struct perf_record_opts *opts);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 0221700..50a305d 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))
@@ -136,7 +137,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
 	attr->comm = track;
 
 	if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
-	    (!opts->group || evsel == first)) {
+	    (group_is_none(opts->group) || evsel == first)) {
 		attr->disabled = 1;
 		attr->enable_on_exec = 1;
 	}
@@ -293,8 +294,17 @@ int __perf_evsel__read(struct perf_evsel *evsel,
 	return 0;
 }
 
+static int parsed_leader_fd(struct perf_evsel *evsel,
+			    int cpu, int thread)
+{
+	BUG_ON(!evsel->parsed_leader);
+	/* The evsel->fd xyarray is initialized to -1. */
+	return FD(evsel->parsed_leader, cpu, thread);
+}
+
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-			      struct thread_map *threads, bool group,
+			      struct thread_map *threads,
+			      enum perf_group_opt group,
 			      struct xyarray *group_fds)
 {
 	int cpu, thread;
@@ -311,13 +321,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 = parsed_leader_fd(evsel, cpu, thread);
+
 			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
 								     pid,
 								     cpus->map[cpu],
@@ -327,7 +343,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);
 		}
 	}
@@ -372,7 +388,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, enum perf_group_opt group,
 		     struct xyarray *group_fd)
 {
 	if (cpus == NULL) {
@@ -387,7 +403,8 @@ 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,
+			     enum perf_group_opt group,
 			     struct xyarray *group_fd)
 {
 	return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
@@ -395,7 +412,8 @@ 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,
+				enum perf_group_opt 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 3158ca3..ae4023f 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       *parsed_leader;
 };
 
 struct cpu_map;
@@ -91,13 +92,15 @@ 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,
+			     enum perf_group_opt 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,
+				enum perf_group_opt group,
 				struct xyarray *group_fds);
 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-		     struct thread_map *threads, bool group,
+		     struct thread_map *threads, enum perf_group_opt group,
 		     struct xyarray *group_fds);
 void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
 
diff --git a/tools/perf/util/group.c b/tools/perf/util/group.c
new file mode 100644
index 0000000..68d18a2
--- /dev/null
+++ b/tools/perf/util/group.c
@@ -0,0 +1,22 @@
+#include <linux/compiler.h>
+#include "types.h"
+#include "util.h"
+#include "parse-options.h"
+#include "group.h"
+
+int group_parse(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..f97520a
--- /dev/null
+++ b/tools/perf/util/group.h
@@ -0,0 +1,32 @@
+#ifndef __GROUP_H__
+#define __GROUP_H__
+
+#include <stdbool.h>
+
+struct option;
+
+enum perf_group_opt {
+	PERF_GROUP_NONE,
+	PERF_GROUP_SINGLE,
+	PERF_GROUP_PARSED
+};
+
+int group_parse(const struct option *opt, const char *str,
+		int unset);
+
+static inline bool group_is_none(enum perf_group_opt group)
+{
+	return group == PERF_GROUP_NONE;
+}
+
+static inline bool group_is_single(enum perf_group_opt group)
+{
+	return group == PERF_GROUP_SINGLE;
+}
+
+static inline bool group_is_parsed(enum perf_group_opt 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 5b3a0ef..b6bccab98 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -747,6 +747,18 @@ int parse_events_modifier(struct list_head *list, char *str)
 	return 0;
 }
 
+static void update_parsed_leader(struct list_head *list)
+{
+	struct perf_evsel *evsel, *parsed_leader = NULL;
+
+	list_for_each_entry(evsel, list, node) {
+		if (!parsed_leader)
+			parsed_leader = evsel;
+
+		evsel->parsed_leader = parsed_leader;
+	}
+}
+
 int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
 	LIST_HEAD(list);
@@ -761,6 +773,12 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 	parse_events__flush_buffer(buffer);
 	parse_events__delete_buffer(buffer);
 
+	/*
+	 * Populate the parsed_leader even if we failed,
+	 * just to have complete data, because who knows.. ;)
+	 */
+	update_parsed_leader(&list);
+
 	if (!ret) {
 		int entries = idx - evlist->nr_entries;
 		perf_evlist__splice_list_tail(evlist, &list, entries);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ca069f8..d6c4d5d 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -64,9 +64,6 @@ 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);
-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,
 			     struct list_head *head_config);
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index e03b58a..6030758 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 ce61cb2..0d2cf8b 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -33,7 +33,7 @@ struct perf_top {
 	bool		   kptr_restrict_warned;
 	bool		   vmlinux_warned;
 	bool		   inherit;
-	bool		   group;
+	enum perf_group_opt group;
 	bool		   sample_id_all_missing;
 	bool		   exclude_guest_missing;
 	bool		   dump_symtab;
-- 
1.7.7.6


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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:15 ` [PATCH 3/3] perf, tool: Add new event group management Jiri Olsa
@ 2012-03-20 18:44   ` Peter Zijlstra
  2012-03-20 20:46     ` Ingo Molnar
                       ` (3 more replies)
  2012-03-20 20:08   ` Arnaldo Carvalho de Melo
  2012-03-21  2:12   ` Namhyung Kim
  2 siblings, 4 replies; 28+ messages in thread
From: Peter Zijlstra @ 2012-03-20 18:44 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: acme, mingo, paulus, cjashfor, fweisbec, linux-kernel, Thomas Gleixner

On Tue, 2012-03-20 at 19:15 +0100, Jiri Olsa wrote:
> 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 

I can't help but dislike the --group/--group parsed thing...

How about something like:

  event_group = "{", events, "}" , [ ":", event_group_mod ]

Such that you can write things like:

  perf record -e "{cpu-clock,cache-misses,cache-references}"

  perf stat -e "{cpu-clock,cycles},{cpu-clock,cache-misses,cache-references}"
  perf stat -e "{cpu-clock,cycles}" -e "{cpu-clock,cache-misses,cache-references}"

I'm not sure what the current behaviour of --group is, if you create a
group like this, do they all sample?

If so, we need some option like:

  perf record -e "{cpu-clock,cache-misses,cache-references}:1"

to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.

Now the disadvantage is that {} needs quotes on bash, the advantage is
that its completely natural on how to construct groups, without weird
--group/--group parsed. Also it provides a place for group modifiers.

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:15 ` [PATCH 3/3] perf, tool: Add new event group management Jiri Olsa
  2012-03-20 18:44   ` Peter Zijlstra
@ 2012-03-20 20:08   ` Arnaldo Carvalho de Melo
  2012-03-20 22:16     ` Jiri Olsa
  2012-03-21  2:12   ` Namhyung Kim
  2 siblings, 1 reply; 28+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-03-20 20:08 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, cjashfor, fweisbec, linux-kernel

Em Tue, Mar 20, 2012 at 07:15:41PM +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.

Why not just set a rule that if -g is present then each -e CSV is a
separate group?

- Arnaldo
 
> 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
> 
> Updated automated test to check on group_leader settings.
> 
> 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-test.c      |   10 ++++++++++
>  tools/perf/builtin-top.c       |    8 +++++---
>  tools/perf/perf.h              |    3 ++-
>  tools/perf/util/evlist.c       |    4 ++--
>  tools/perf/util/evlist.h       |    3 ++-
>  tools/perf/util/evsel.c        |   32 +++++++++++++++++++++++++-------
>  tools/perf/util/evsel.h        |    9 ++++++---
>  tools/perf/util/group.c        |   22 ++++++++++++++++++++++
>  tools/perf/util/group.h        |   32 ++++++++++++++++++++++++++++++++
>  tools/perf/util/parse-events.c |   18 ++++++++++++++++++
>  tools/perf/util/parse-events.h |    3 ---
>  tools/perf/util/python.c       |    4 ++++
>  tools/perf/util/top.h          |    2 +-
>  16 files changed, 142 insertions(+), 28 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 b492e3a..ea10b29 100644
> --- a/tools/perf/Makefile
> +++ b/tools/perf/Makefile
> @@ -317,6 +317,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
> @@ -378,6 +379,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 be4e1ee..a2c7dc2 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>
> @@ -203,7 +204,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;
>  fallback_missing_features:
>  		if (opts->exclude_guest_missing)
> @@ -791,8 +792,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",
> +		     group_parse, 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 c941bb6..d0d3859 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 enum perf_group_opt	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)
> @@ -1055,8 +1056,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",
> +		     group_parse, PERF_GROUP_NONE),
>  	OPT_BOOLEAN('c', "scale", &scale,
>  		    "scale/normalize counters"),
>  	OPT_INCR('v', "verbose", &verbose,
> diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
> index 1c5b980..babdd77 100644
> --- a/tools/perf/builtin-test.c
> +++ b/tools/perf/builtin-test.c
> @@ -14,6 +14,7 @@
>  #include "util/symbol.h"
>  #include "util/thread_map.h"
>  #include "util/pmu.h"
> +#include "util/group.h"
>  #include "../../include/linux/hw_breakpoint.h"
>  
>  #include <sys/mman.h>
> @@ -948,11 +949,14 @@ static int test__checkevent_pmu(struct perf_evlist *evlist)
>  static int test__checkevent_list(struct perf_evlist *evlist)
>  {
>  	struct perf_evsel *evsel;
> +	struct perf_evsel *parsed_leader;
>  
>  	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
>  
>  	/* r1 */
>  	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
> +	parsed_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 config1", 0 == evsel->attr.config1);
> @@ -961,6 +965,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
>  	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 parsed_leader", parsed_leader);
>  
>  	/* syscalls:sys_enter_open:k */
>  	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
> @@ -973,6 +978,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
>  	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 parsed_leader",
> +			evsel->parsed_leader == parsed_leader);
>  
>  	/* 1:1:hp */
>  	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
> @@ -982,6 +989,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
>  	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 parsed_leader",
> +			evsel->parsed_leader == parsed_leader);
>  
>  	return 0;
>  }
> @@ -1168,6 +1177,7 @@ static int test__PERF_RECORD(void)
>  		.no_delay   = true,
>  		.freq	    = 10,
>  		.mmap_pages = 256,
> +		.group      = PERF_GROUP_NONE,
>  	};
>  	cpu_set_t *cpu_mask = NULL;
>  	size_t cpu_mask_size = 0;
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index e3c63ae..fd04361 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"
>  
> @@ -850,7 +851,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;
> @@ -1153,8 +1154,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",
> +		    group_parse, 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 89e3355..b80b69d 100644
> --- a/tools/perf/perf.h
> +++ b/tools/perf/perf.h
> @@ -108,6 +108,7 @@ void get_term_dimensions(struct winsize *ws);
>  
>  #include "../../include/linux/perf_event.h"
>  #include "util/types.h"
> +#include "util/group.h"
>  #include <stdbool.h>
>  
>  struct perf_mmap {
> @@ -212,7 +213,6 @@ struct perf_record_opts {
>  	const char   *target_tid;
>  	uid_t	     uid;
>  	bool	     call_graph;
> -	bool	     group;
>  	bool	     inherit_stat;
>  	bool	     no_delay;
>  	bool	     no_inherit;
> @@ -232,6 +232,7 @@ struct perf_record_opts {
>  	u64	     default_interval;
>  	u64	     user_interval;
>  	const char   *cpu_list;
> +	enum perf_group_opt group;
>  };
>  
>  #endif
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 1986d80..c0bcffd 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -740,7 +740,7 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
>  	evlist->selected = evsel;
>  }
>  
> -int perf_evlist__open(struct perf_evlist *evlist, bool group)
> +int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group)
>  {
>  	struct perf_evsel *evsel, *first;
>  	int err, ncpus, nthreads;
> @@ -750,7 +750,7 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group)
>  	list_for_each_entry(evsel, &evlist->entries, node) {
>  		struct xyarray *group_fd = NULL;
>  
> -		if (group && evsel != first)
> +		if (group_is_single(group) && evsel != first)
>  			group_fd = first->fd;
>  
>  		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index 21f1c9e..3115e8d 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -6,6 +6,7 @@
>  #include "../perf.h"
>  #include "event.h"
>  #include "util.h"
> +#include "group.h"
>  #include <unistd.h>
>  
>  struct pollfd;
> @@ -78,7 +79,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
>  
>  union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
>  
> -int perf_evlist__open(struct perf_evlist *evlist, bool group);
> +int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group);
>  
>  void perf_evlist__config_attrs(struct perf_evlist *evlist,
>  			       struct perf_record_opts *opts);
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 0221700..50a305d 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))
> @@ -136,7 +137,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
>  	attr->comm = track;
>  
>  	if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
> -	    (!opts->group || evsel == first)) {
> +	    (group_is_none(opts->group) || evsel == first)) {
>  		attr->disabled = 1;
>  		attr->enable_on_exec = 1;
>  	}
> @@ -293,8 +294,17 @@ int __perf_evsel__read(struct perf_evsel *evsel,
>  	return 0;
>  }
>  
> +static int parsed_leader_fd(struct perf_evsel *evsel,
> +			    int cpu, int thread)
> +{
> +	BUG_ON(!evsel->parsed_leader);
> +	/* The evsel->fd xyarray is initialized to -1. */
> +	return FD(evsel->parsed_leader, cpu, thread);
> +}
> +
>  static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> -			      struct thread_map *threads, bool group,
> +			      struct thread_map *threads,
> +			      enum perf_group_opt group,
>  			      struct xyarray *group_fds)
>  {
>  	int cpu, thread;
> @@ -311,13 +321,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 = parsed_leader_fd(evsel, cpu, thread);
> +
>  			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
>  								     pid,
>  								     cpus->map[cpu],
> @@ -327,7 +343,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);
>  		}
>  	}
> @@ -372,7 +388,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, enum perf_group_opt group,
>  		     struct xyarray *group_fd)
>  {
>  	if (cpus == NULL) {
> @@ -387,7 +403,8 @@ 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,
> +			     enum perf_group_opt group,
>  			     struct xyarray *group_fd)
>  {
>  	return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
> @@ -395,7 +412,8 @@ 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,
> +				enum perf_group_opt 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 3158ca3..ae4023f 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       *parsed_leader;
>  };
>  
>  struct cpu_map;
> @@ -91,13 +92,15 @@ 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,
> +			     enum perf_group_opt 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,
> +				enum perf_group_opt group,
>  				struct xyarray *group_fds);
>  int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> -		     struct thread_map *threads, bool group,
> +		     struct thread_map *threads, enum perf_group_opt group,
>  		     struct xyarray *group_fds);
>  void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
>  
> diff --git a/tools/perf/util/group.c b/tools/perf/util/group.c
> new file mode 100644
> index 0000000..68d18a2
> --- /dev/null
> +++ b/tools/perf/util/group.c
> @@ -0,0 +1,22 @@
> +#include <linux/compiler.h>
> +#include "types.h"
> +#include "util.h"
> +#include "parse-options.h"
> +#include "group.h"
> +
> +int group_parse(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..f97520a
> --- /dev/null
> +++ b/tools/perf/util/group.h
> @@ -0,0 +1,32 @@
> +#ifndef __GROUP_H__
> +#define __GROUP_H__
> +
> +#include <stdbool.h>
> +
> +struct option;
> +
> +enum perf_group_opt {
> +	PERF_GROUP_NONE,
> +	PERF_GROUP_SINGLE,
> +	PERF_GROUP_PARSED
> +};
> +
> +int group_parse(const struct option *opt, const char *str,
> +		int unset);
> +
> +static inline bool group_is_none(enum perf_group_opt group)
> +{
> +	return group == PERF_GROUP_NONE;
> +}
> +
> +static inline bool group_is_single(enum perf_group_opt group)
> +{
> +	return group == PERF_GROUP_SINGLE;
> +}
> +
> +static inline bool group_is_parsed(enum perf_group_opt 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 5b3a0ef..b6bccab98 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -747,6 +747,18 @@ int parse_events_modifier(struct list_head *list, char *str)
>  	return 0;
>  }
>  
> +static void update_parsed_leader(struct list_head *list)
> +{
> +	struct perf_evsel *evsel, *parsed_leader = NULL;
> +
> +	list_for_each_entry(evsel, list, node) {
> +		if (!parsed_leader)
> +			parsed_leader = evsel;
> +
> +		evsel->parsed_leader = parsed_leader;
> +	}
> +}
> +
>  int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
>  {
>  	LIST_HEAD(list);
> @@ -761,6 +773,12 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
>  	parse_events__flush_buffer(buffer);
>  	parse_events__delete_buffer(buffer);
>  
> +	/*
> +	 * Populate the parsed_leader even if we failed,
> +	 * just to have complete data, because who knows.. ;)
> +	 */
> +	update_parsed_leader(&list);
> +
>  	if (!ret) {
>  		int entries = idx - evlist->nr_entries;
>  		perf_evlist__splice_list_tail(evlist, &list, entries);
> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> index ca069f8..d6c4d5d 100644
> --- a/tools/perf/util/parse-events.h
> +++ b/tools/perf/util/parse-events.h
> @@ -64,9 +64,6 @@ 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);
> -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,
>  			     struct list_head *head_config);
> diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> index e03b58a..6030758 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 ce61cb2..0d2cf8b 100644
> --- a/tools/perf/util/top.h
> +++ b/tools/perf/util/top.h
> @@ -33,7 +33,7 @@ struct perf_top {
>  	bool		   kptr_restrict_warned;
>  	bool		   vmlinux_warned;
>  	bool		   inherit;
> -	bool		   group;
> +	enum perf_group_opt group;
>  	bool		   sample_id_all_missing;
>  	bool		   exclude_guest_missing;
>  	bool		   dump_symtab;
> -- 
> 1.7.7.6

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:44   ` Peter Zijlstra
@ 2012-03-20 20:46     ` Ingo Molnar
  2012-03-20 22:18       ` Arnaldo Carvalho de Melo
  2012-03-21  9:15       ` Peter Zijlstra
  2012-03-20 22:36     ` Jiri Olsa
                       ` (2 subsequent siblings)
  3 siblings, 2 replies; 28+ messages in thread
From: Ingo Molnar @ 2012-03-20 20:46 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner


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

> Now the disadvantage is that {} needs quotes on bash, [...]

Not on my version of Bash:

 earth5:~> perf stat {}
 {}: No such file or directory
 Terminated
 earth5:~> perf stat true {}

  Performance counter stats for 'true {}':

it's passed in literally, AFAICS.

Thanks,

	Ingo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 20:08   ` Arnaldo Carvalho de Melo
@ 2012-03-20 22:16     ` Jiri Olsa
  0 siblings, 0 replies; 28+ messages in thread
From: Jiri Olsa @ 2012-03-20 22:16 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: a.p.zijlstra, mingo, paulus, cjashfor, fweisbec, linux-kernel

On Tue, Mar 20, 2012 at 05:08:40PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Mar 20, 2012 at 07:15:41PM +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.
> 
> Why not just set a rule that if -g is present then each -e CSV is a
> separate group?

hm, for some reason I thought I need to keep the old '-g,--group"
interface behaviour intact.. ;) no problem..

jirka

> 
> - Arnaldo
>  
> > 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
> > 
> > Updated automated test to check on group_leader settings.
> > 
> > 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-test.c      |   10 ++++++++++
> >  tools/perf/builtin-top.c       |    8 +++++---
> >  tools/perf/perf.h              |    3 ++-
> >  tools/perf/util/evlist.c       |    4 ++--
> >  tools/perf/util/evlist.h       |    3 ++-
> >  tools/perf/util/evsel.c        |   32 +++++++++++++++++++++++++-------
> >  tools/perf/util/evsel.h        |    9 ++++++---
> >  tools/perf/util/group.c        |   22 ++++++++++++++++++++++
> >  tools/perf/util/group.h        |   32 ++++++++++++++++++++++++++++++++
> >  tools/perf/util/parse-events.c |   18 ++++++++++++++++++
> >  tools/perf/util/parse-events.h |    3 ---
> >  tools/perf/util/python.c       |    4 ++++
> >  tools/perf/util/top.h          |    2 +-
> >  16 files changed, 142 insertions(+), 28 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 b492e3a..ea10b29 100644
> > --- a/tools/perf/Makefile
> > +++ b/tools/perf/Makefile
> > @@ -317,6 +317,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
> > @@ -378,6 +379,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 be4e1ee..a2c7dc2 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>
> > @@ -203,7 +204,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;
> >  fallback_missing_features:
> >  		if (opts->exclude_guest_missing)
> > @@ -791,8 +792,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",
> > +		     group_parse, 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 c941bb6..d0d3859 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 enum perf_group_opt	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)
> > @@ -1055,8 +1056,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",
> > +		     group_parse, PERF_GROUP_NONE),
> >  	OPT_BOOLEAN('c', "scale", &scale,
> >  		    "scale/normalize counters"),
> >  	OPT_INCR('v', "verbose", &verbose,
> > diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
> > index 1c5b980..babdd77 100644
> > --- a/tools/perf/builtin-test.c
> > +++ b/tools/perf/builtin-test.c
> > @@ -14,6 +14,7 @@
> >  #include "util/symbol.h"
> >  #include "util/thread_map.h"
> >  #include "util/pmu.h"
> > +#include "util/group.h"
> >  #include "../../include/linux/hw_breakpoint.h"
> >  
> >  #include <sys/mman.h>
> > @@ -948,11 +949,14 @@ static int test__checkevent_pmu(struct perf_evlist *evlist)
> >  static int test__checkevent_list(struct perf_evlist *evlist)
> >  {
> >  	struct perf_evsel *evsel;
> > +	struct perf_evsel *parsed_leader;
> >  
> >  	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
> >  
> >  	/* r1 */
> >  	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
> > +	parsed_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 config1", 0 == evsel->attr.config1);
> > @@ -961,6 +965,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
> >  	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 parsed_leader", parsed_leader);
> >  
> >  	/* syscalls:sys_enter_open:k */
> >  	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
> > @@ -973,6 +978,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
> >  	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 parsed_leader",
> > +			evsel->parsed_leader == parsed_leader);
> >  
> >  	/* 1:1:hp */
> >  	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
> > @@ -982,6 +989,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
> >  	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 parsed_leader",
> > +			evsel->parsed_leader == parsed_leader);
> >  
> >  	return 0;
> >  }
> > @@ -1168,6 +1177,7 @@ static int test__PERF_RECORD(void)
> >  		.no_delay   = true,
> >  		.freq	    = 10,
> >  		.mmap_pages = 256,
> > +		.group      = PERF_GROUP_NONE,
> >  	};
> >  	cpu_set_t *cpu_mask = NULL;
> >  	size_t cpu_mask_size = 0;
> > diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> > index e3c63ae..fd04361 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"
> >  
> > @@ -850,7 +851,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;
> > @@ -1153,8 +1154,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",
> > +		    group_parse, 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 89e3355..b80b69d 100644
> > --- a/tools/perf/perf.h
> > +++ b/tools/perf/perf.h
> > @@ -108,6 +108,7 @@ void get_term_dimensions(struct winsize *ws);
> >  
> >  #include "../../include/linux/perf_event.h"
> >  #include "util/types.h"
> > +#include "util/group.h"
> >  #include <stdbool.h>
> >  
> >  struct perf_mmap {
> > @@ -212,7 +213,6 @@ struct perf_record_opts {
> >  	const char   *target_tid;
> >  	uid_t	     uid;
> >  	bool	     call_graph;
> > -	bool	     group;
> >  	bool	     inherit_stat;
> >  	bool	     no_delay;
> >  	bool	     no_inherit;
> > @@ -232,6 +232,7 @@ struct perf_record_opts {
> >  	u64	     default_interval;
> >  	u64	     user_interval;
> >  	const char   *cpu_list;
> > +	enum perf_group_opt group;
> >  };
> >  
> >  #endif
> > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> > index 1986d80..c0bcffd 100644
> > --- a/tools/perf/util/evlist.c
> > +++ b/tools/perf/util/evlist.c
> > @@ -740,7 +740,7 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
> >  	evlist->selected = evsel;
> >  }
> >  
> > -int perf_evlist__open(struct perf_evlist *evlist, bool group)
> > +int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group)
> >  {
> >  	struct perf_evsel *evsel, *first;
> >  	int err, ncpus, nthreads;
> > @@ -750,7 +750,7 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group)
> >  	list_for_each_entry(evsel, &evlist->entries, node) {
> >  		struct xyarray *group_fd = NULL;
> >  
> > -		if (group && evsel != first)
> > +		if (group_is_single(group) && evsel != first)
> >  			group_fd = first->fd;
> >  
> >  		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
> > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> > index 21f1c9e..3115e8d 100644
> > --- a/tools/perf/util/evlist.h
> > +++ b/tools/perf/util/evlist.h
> > @@ -6,6 +6,7 @@
> >  #include "../perf.h"
> >  #include "event.h"
> >  #include "util.h"
> > +#include "group.h"
> >  #include <unistd.h>
> >  
> >  struct pollfd;
> > @@ -78,7 +79,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
> >  
> >  union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
> >  
> > -int perf_evlist__open(struct perf_evlist *evlist, bool group);
> > +int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group);
> >  
> >  void perf_evlist__config_attrs(struct perf_evlist *evlist,
> >  			       struct perf_record_opts *opts);
> > diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> > index 0221700..50a305d 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))
> > @@ -136,7 +137,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
> >  	attr->comm = track;
> >  
> >  	if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
> > -	    (!opts->group || evsel == first)) {
> > +	    (group_is_none(opts->group) || evsel == first)) {
> >  		attr->disabled = 1;
> >  		attr->enable_on_exec = 1;
> >  	}
> > @@ -293,8 +294,17 @@ int __perf_evsel__read(struct perf_evsel *evsel,
> >  	return 0;
> >  }
> >  
> > +static int parsed_leader_fd(struct perf_evsel *evsel,
> > +			    int cpu, int thread)
> > +{
> > +	BUG_ON(!evsel->parsed_leader);
> > +	/* The evsel->fd xyarray is initialized to -1. */
> > +	return FD(evsel->parsed_leader, cpu, thread);
> > +}
> > +
> >  static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> > -			      struct thread_map *threads, bool group,
> > +			      struct thread_map *threads,
> > +			      enum perf_group_opt group,
> >  			      struct xyarray *group_fds)
> >  {
> >  	int cpu, thread;
> > @@ -311,13 +321,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 = parsed_leader_fd(evsel, cpu, thread);
> > +
> >  			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
> >  								     pid,
> >  								     cpus->map[cpu],
> > @@ -327,7 +343,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);
> >  		}
> >  	}
> > @@ -372,7 +388,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, enum perf_group_opt group,
> >  		     struct xyarray *group_fd)
> >  {
> >  	if (cpus == NULL) {
> > @@ -387,7 +403,8 @@ 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,
> > +			     enum perf_group_opt group,
> >  			     struct xyarray *group_fd)
> >  {
> >  	return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
> > @@ -395,7 +412,8 @@ 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,
> > +				enum perf_group_opt 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 3158ca3..ae4023f 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       *parsed_leader;
> >  };
> >  
> >  struct cpu_map;
> > @@ -91,13 +92,15 @@ 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,
> > +			     enum perf_group_opt 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,
> > +				enum perf_group_opt group,
> >  				struct xyarray *group_fds);
> >  int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> > -		     struct thread_map *threads, bool group,
> > +		     struct thread_map *threads, enum perf_group_opt group,
> >  		     struct xyarray *group_fds);
> >  void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
> >  
> > diff --git a/tools/perf/util/group.c b/tools/perf/util/group.c
> > new file mode 100644
> > index 0000000..68d18a2
> > --- /dev/null
> > +++ b/tools/perf/util/group.c
> > @@ -0,0 +1,22 @@
> > +#include <linux/compiler.h>
> > +#include "types.h"
> > +#include "util.h"
> > +#include "parse-options.h"
> > +#include "group.h"
> > +
> > +int group_parse(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..f97520a
> > --- /dev/null
> > +++ b/tools/perf/util/group.h
> > @@ -0,0 +1,32 @@
> > +#ifndef __GROUP_H__
> > +#define __GROUP_H__
> > +
> > +#include <stdbool.h>
> > +
> > +struct option;
> > +
> > +enum perf_group_opt {
> > +	PERF_GROUP_NONE,
> > +	PERF_GROUP_SINGLE,
> > +	PERF_GROUP_PARSED
> > +};
> > +
> > +int group_parse(const struct option *opt, const char *str,
> > +		int unset);
> > +
> > +static inline bool group_is_none(enum perf_group_opt group)
> > +{
> > +	return group == PERF_GROUP_NONE;
> > +}
> > +
> > +static inline bool group_is_single(enum perf_group_opt group)
> > +{
> > +	return group == PERF_GROUP_SINGLE;
> > +}
> > +
> > +static inline bool group_is_parsed(enum perf_group_opt 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 5b3a0ef..b6bccab98 100644
> > --- a/tools/perf/util/parse-events.c
> > +++ b/tools/perf/util/parse-events.c
> > @@ -747,6 +747,18 @@ int parse_events_modifier(struct list_head *list, char *str)
> >  	return 0;
> >  }
> >  
> > +static void update_parsed_leader(struct list_head *list)
> > +{
> > +	struct perf_evsel *evsel, *parsed_leader = NULL;
> > +
> > +	list_for_each_entry(evsel, list, node) {
> > +		if (!parsed_leader)
> > +			parsed_leader = evsel;
> > +
> > +		evsel->parsed_leader = parsed_leader;
> > +	}
> > +}
> > +
> >  int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
> >  {
> >  	LIST_HEAD(list);
> > @@ -761,6 +773,12 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
> >  	parse_events__flush_buffer(buffer);
> >  	parse_events__delete_buffer(buffer);
> >  
> > +	/*
> > +	 * Populate the parsed_leader even if we failed,
> > +	 * just to have complete data, because who knows.. ;)
> > +	 */
> > +	update_parsed_leader(&list);
> > +
> >  	if (!ret) {
> >  		int entries = idx - evlist->nr_entries;
> >  		perf_evlist__splice_list_tail(evlist, &list, entries);
> > diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> > index ca069f8..d6c4d5d 100644
> > --- a/tools/perf/util/parse-events.h
> > +++ b/tools/perf/util/parse-events.h
> > @@ -64,9 +64,6 @@ 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);
> > -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,
> >  			     struct list_head *head_config);
> > diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> > index e03b58a..6030758 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 ce61cb2..0d2cf8b 100644
> > --- a/tools/perf/util/top.h
> > +++ b/tools/perf/util/top.h
> > @@ -33,7 +33,7 @@ struct perf_top {
> >  	bool		   kptr_restrict_warned;
> >  	bool		   vmlinux_warned;
> >  	bool		   inherit;
> > -	bool		   group;
> > +	enum perf_group_opt group;
> >  	bool		   sample_id_all_missing;
> >  	bool		   exclude_guest_missing;
> >  	bool		   dump_symtab;
> > -- 
> > 1.7.7.6

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 20:46     ` Ingo Molnar
@ 2012-03-20 22:18       ` Arnaldo Carvalho de Melo
  2012-03-21  9:15       ` Peter Zijlstra
  1 sibling, 0 replies; 28+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-03-20 22:18 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Peter Zijlstra, Jiri Olsa, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, Thomas Gleixner

Em Tue, Mar 20, 2012 at 09:46:25PM +0100, Ingo Molnar escreveu:
> 
> * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> 
> > Now the disadvantage is that {} needs quotes on bash, [...]
> 
> Not on my version of Bash:
> 
>  earth5:~> perf stat {}
>  {}: No such file or directory
>  Terminated
>  earth5:~> perf stat true {}
> 
>   Performance counter stats for 'true {}':
> 
> it's passed in literally, AFAICS.

I like it, but...

[acme@felicio ~]$ perf stat -e {cycles,cache-misses} ls
cache-misses: No such file or directory
Terminated
[acme@felicio ~]$ perf stat -e \{cycles,cache-misses\} ls
invalid or unsupported event: '{cycles,cache-misses}'
Run 'perf list' for a list of valid events

but:

[acme@felicio ~]$ perf stat -e [cycles,instructions] ls
perf stat -e [cycles,instructions] ls
invalid or unsupported event: '[cycles,instructions]'
Run 'perf list' for a list of valid events

[acme@felicio ~]$ perf stat -e [cycles,cache-misses]:u ls
invalid or unsupported event: '[cycles,cache-misses]:u'
Run 'perf list' for a list of valid events

And:

[acme@felicio ~]$ perf stat -e (cycles,cache-misses) ls
bash: syntax error near unexpected token `('
[acme@felicio ~]$

- Arnaldo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:44   ` Peter Zijlstra
  2012-03-20 20:46     ` Ingo Molnar
@ 2012-03-20 22:36     ` Jiri Olsa
  2012-03-21 11:54       ` Peter Zijlstra
  2012-03-21 10:42     ` Jiri Olsa
  2012-04-10 13:19     ` Jiri Olsa
  3 siblings, 1 reply; 28+ messages in thread
From: Jiri Olsa @ 2012-03-20 22:36 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: acme, mingo, paulus, cjashfor, fweisbec, linux-kernel, Thomas Gleixner

On Tue, Mar 20, 2012 at 07:44:41PM +0100, Peter Zijlstra wrote:
> On Tue, 2012-03-20 at 19:15 +0100, Jiri Olsa wrote:
> > 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 
> 
> I can't help but dislike the --group/--group parsed thing...
> 
> How about something like:
> 
>   event_group = "{", events, "}" , [ ":", event_group_mod ]
> 
> Such that you can write things like:
> 
>   perf record -e "{cpu-clock,cache-misses,cache-references}"
> 
>   perf stat -e "{cpu-clock,cycles},{cpu-clock,cache-misses,cache-references}"
>   perf stat -e "{cpu-clock,cycles}" -e "{cpu-clock,cache-misses,cache-references}"

there should be no problem with that

> 
> I'm not sure what the current behaviour of --group is, if you create a
> group like this, do they all sample?

I think so.. the --group switch just set the group_fd for the event syscall, nothing else

> 
> If so, we need some option like:
> 
>   perf record -e "{cpu-clock,cache-misses,cache-references}:1"
> 
> to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
> PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.

never happy, are you.. ;) seems like nice feature, will check

> 
> Now the disadvantage is that {} needs quotes on bash, the advantage is
> that its completely natural on how to construct groups, without weird
> --group/--group parsed. Also it provides a place for group modifiers.

looks like Arnaldo could use [] but I get different results:

[jolsa@dhcp-26-214 perf]$ ./perf stat -e [cycles,instructions] ls
invalid or unsupported event: 't'

need to check.. maybe escaping is small price for good readability,
but I'll think about some other way as well.

thanks for comments,
jirka

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:15 ` [PATCH 3/3] perf, tool: Add new event group management Jiri Olsa
  2012-03-20 18:44   ` Peter Zijlstra
  2012-03-20 20:08   ` Arnaldo Carvalho de Melo
@ 2012-03-21  2:12   ` Namhyung Kim
  2 siblings, 0 replies; 28+ messages in thread
From: Namhyung Kim @ 2012-03-21  2:12 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: acme, a.p.zijlstra, mingo, paulus, cjashfor, fweisbec, linux-kernel

Hi,

2012-03-21 3:15 AM, Jiri Olsa wrote:
> 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
> 
> Updated automated test to check on group_leader settings.
> 
> 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-test.c      |   10 ++++++++++
>   tools/perf/builtin-top.c       |    8 +++++---
>   tools/perf/perf.h              |    3 ++-
>   tools/perf/util/evlist.c       |    4 ++--
>   tools/perf/util/evlist.h       |    3 ++-
>   tools/perf/util/evsel.c        |   32 +++++++++++++++++++++++++-------
>   tools/perf/util/evsel.h        |    9 ++++++---
>   tools/perf/util/group.c        |   22 ++++++++++++++++++++++
>   tools/perf/util/group.h        |   32 ++++++++++++++++++++++++++++++++
>   tools/perf/util/parse-events.c |   18 ++++++++++++++++++
>   tools/perf/util/parse-events.h |    3 ---
>   tools/perf/util/python.c       |    4 ++++
>   tools/perf/util/top.h          |    2 +-
>   16 files changed, 142 insertions(+), 28 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 b492e3a..ea10b29 100644
> --- a/tools/perf/Makefile
> +++ b/tools/perf/Makefile
> @@ -317,6 +317,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
> @@ -378,6 +379,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 be4e1ee..a2c7dc2 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>
> @@ -203,7 +204,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;
>   fallback_missing_features:
>   		if (opts->exclude_guest_missing)
> @@ -791,8 +792,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",
> +		     group_parse, 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 c941bb6..d0d3859 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 enum perf_group_opt	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;

I think it'd be better if we had a something like is_group_leader(),
so that it can be converted like following:

	if (!is_group_leader(evsel))
		group_fd = evsel->group_leader->fd;

> 
>   	if (scale)
> @@ -1055,8 +1056,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",
> +		     group_parse, PERF_GROUP_NONE),
>   	OPT_BOOLEAN('c', "scale",&scale,
>   		    "scale/normalize counters"),
>   	OPT_INCR('v', "verbose",&verbose,
> diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
> index 1c5b980..babdd77 100644
> --- a/tools/perf/builtin-test.c
> +++ b/tools/perf/builtin-test.c
> @@ -14,6 +14,7 @@
>   #include "util/symbol.h"
>   #include "util/thread_map.h"
>   #include "util/pmu.h"
> +#include "util/group.h"
>   #include "../../include/linux/hw_breakpoint.h"
> 
>   #include<sys/mman.h>
> @@ -948,11 +949,14 @@ static int test__checkevent_pmu(struct perf_evlist *evlist)
>   static int test__checkevent_list(struct perf_evlist *evlist)
>   {
>   	struct perf_evsel *evsel;
> +	struct perf_evsel *parsed_leader;
> 
>   	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
> 
>   	/* r1 */
>   	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
> +	parsed_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 config1", 0 == evsel->attr.config1);
> @@ -961,6 +965,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
>   	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 parsed_leader", parsed_leader);
> 
>   	/* syscalls:sys_enter_open:k */
>   	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
> @@ -973,6 +978,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
>   	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 parsed_leader",
> +			evsel->parsed_leader == parsed_leader);
> 
>   	/* 1:1:hp */
>   	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
> @@ -982,6 +989,8 @@ static int test__checkevent_list(struct perf_evlist *evlist)
>   	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 parsed_leader",
> +			evsel->parsed_leader == parsed_leader);
> 
>   	return 0;
>   }
> @@ -1168,6 +1177,7 @@ static int test__PERF_RECORD(void)
>   		.no_delay   = true,
>   		.freq	    = 10,
>   		.mmap_pages = 256,
> +		.group      = PERF_GROUP_NONE,
>   	};
>   	cpu_set_t *cpu_mask = NULL;
>   	size_t cpu_mask_size = 0;
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index e3c63ae..fd04361 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"
> 
> @@ -850,7 +851,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;

Same here.


> 
>   		attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
> @@ -1153,8 +1154,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",
> +		    group_parse, 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 89e3355..b80b69d 100644
> --- a/tools/perf/perf.h
> +++ b/tools/perf/perf.h
> @@ -108,6 +108,7 @@ void get_term_dimensions(struct winsize *ws);
> 
>   #include "../../include/linux/perf_event.h"
>   #include "util/types.h"
> +#include "util/group.h"
>   #include<stdbool.h>
> 
>   struct perf_mmap {
> @@ -212,7 +213,6 @@ struct perf_record_opts {
>   	const char   *target_tid;
>   	uid_t	     uid;
>   	bool	     call_graph;
> -	bool	     group;
>   	bool	     inherit_stat;
>   	bool	     no_delay;
>   	bool	     no_inherit;
> @@ -232,6 +232,7 @@ struct perf_record_opts {
>   	u64	     default_interval;
>   	u64	     user_interval;
>   	const char   *cpu_list;
> +	enum perf_group_opt group;
>   };
> 
>   #endif
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 1986d80..c0bcffd 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -740,7 +740,7 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
>   	evlist->selected = evsel;
>   }
> 
> -int perf_evlist__open(struct perf_evlist *evlist, bool group)
> +int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group)
>   {
>   	struct perf_evsel *evsel, *first;
>   	int err, ncpus, nthreads;
> @@ -750,7 +750,7 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group)
>   	list_for_each_entry(evsel,&evlist->entries, node) {
>   		struct xyarray *group_fd = NULL;
> 
> -		if (group && evsel != first)
> +		if (group_is_single(group) && evsel != first)
>   			group_fd = first->fd;

Same here.


> 
>   		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index 21f1c9e..3115e8d 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -6,6 +6,7 @@
>   #include "../perf.h"
>   #include "event.h"
>   #include "util.h"
> +#include "group.h"
>   #include<unistd.h>
> 
>   struct pollfd;
> @@ -78,7 +79,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
> 
>   union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
> 
> -int perf_evlist__open(struct perf_evlist *evlist, bool group);
> +int perf_evlist__open(struct perf_evlist *evlist, enum perf_group_opt group);
> 
>   void perf_evlist__config_attrs(struct perf_evlist *evlist,
>   			       struct perf_record_opts *opts);
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 0221700..50a305d 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))
> @@ -136,7 +137,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
>   	attr->comm = track;
> 
>   	if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
> -	    (!opts->group || evsel == first)) {
> +	    (group_is_none(opts->group) || evsel == first)) {

This can be bit simpler:

	    (is_group_leader(evsel)) {


>   		attr->disabled = 1;
>   		attr->enable_on_exec = 1;
>   	}
> @@ -293,8 +294,17 @@ int __perf_evsel__read(struct perf_evsel *evsel,
>   	return 0;
>   }
> 
> +static int parsed_leader_fd(struct perf_evsel *evsel,
> +			    int cpu, int thread)
> +{
> +	BUG_ON(!evsel->parsed_leader);
> +	/* The evsel->fd xyarray is initialized to -1. */
> +	return FD(evsel->parsed_leader, cpu, thread);
> +}
> +
>   static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> -			      struct thread_map *threads, bool group,
> +			      struct thread_map *threads,
> +			      enum perf_group_opt group,
>   			      struct xyarray *group_fds)
>   {
>   	int cpu, thread;
> @@ -311,13 +321,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 = parsed_leader_fd(evsel, cpu, thread);
> +

This can be:
			if (!is_group_leader(evsel))
				group_fd = FD(evsel->group_leader, cpu, thread);

Thanks,
Namhyung


>   			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
>   								     pid,
>   								     cpus->map[cpu],
> @@ -327,7 +343,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);
>   		}
>   	}
> @@ -372,7 +388,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, enum perf_group_opt group,
>   		     struct xyarray *group_fd)
>   {
>   	if (cpus == NULL) {
> @@ -387,7 +403,8 @@ 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,
> +			     enum perf_group_opt group,
>   			     struct xyarray *group_fd)
>   {
>   	return __perf_evsel__open(evsel, cpus,&empty_thread_map.map, group,
> @@ -395,7 +412,8 @@ 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,
> +				enum perf_group_opt 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 3158ca3..ae4023f 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       *parsed_leader;
>   };
> 
>   struct cpu_map;
> @@ -91,13 +92,15 @@ 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,
> +			     enum perf_group_opt 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,
> +				enum perf_group_opt group,
>   				struct xyarray *group_fds);
>   int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> -		     struct thread_map *threads, bool group,
> +		     struct thread_map *threads, enum perf_group_opt group,
>   		     struct xyarray *group_fds);
>   void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
> 
> diff --git a/tools/perf/util/group.c b/tools/perf/util/group.c
> new file mode 100644
> index 0000000..68d18a2
> --- /dev/null
> +++ b/tools/perf/util/group.c
> @@ -0,0 +1,22 @@
> +#include<linux/compiler.h>
> +#include "types.h"
> +#include "util.h"
> +#include "parse-options.h"
> +#include "group.h"
> +
> +int group_parse(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..f97520a
> --- /dev/null
> +++ b/tools/perf/util/group.h
> @@ -0,0 +1,32 @@
> +#ifndef __GROUP_H__
> +#define __GROUP_H__
> +
> +#include<stdbool.h>
> +
> +struct option;
> +
> +enum perf_group_opt {
> +	PERF_GROUP_NONE,
> +	PERF_GROUP_SINGLE,
> +	PERF_GROUP_PARSED
> +};
> +
> +int group_parse(const struct option *opt, const char *str,
> +		int unset);
> +
> +static inline bool group_is_none(enum perf_group_opt group)
> +{
> +	return group == PERF_GROUP_NONE;
> +}
> +
> +static inline bool group_is_single(enum perf_group_opt group)
> +{
> +	return group == PERF_GROUP_SINGLE;
> +}
> +
> +static inline bool group_is_parsed(enum perf_group_opt 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 5b3a0ef..b6bccab98 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -747,6 +747,18 @@ int parse_events_modifier(struct list_head *list, char *str)
>   	return 0;
>   }
> 
> +static void update_parsed_leader(struct list_head *list)
> +{
> +	struct perf_evsel *evsel, *parsed_leader = NULL;
> +
> +	list_for_each_entry(evsel, list, node) {
> +		if (!parsed_leader)
> +			parsed_leader = evsel;
> +
> +		evsel->parsed_leader = parsed_leader;
> +	}
> +}
> +
>   int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
>   {
>   	LIST_HEAD(list);
> @@ -761,6 +773,12 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
>   	parse_events__flush_buffer(buffer);
>   	parse_events__delete_buffer(buffer);
> 
> +	/*
> +	 * Populate the parsed_leader even if we failed,
> +	 * just to have complete data, because who knows.. ;)
> +	 */
> +	update_parsed_leader(&list);
> +
>   	if (!ret) {
>   		int entries = idx - evlist->nr_entries;
>   		perf_evlist__splice_list_tail(evlist,&list, entries);
> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> index ca069f8..d6c4d5d 100644
> --- a/tools/perf/util/parse-events.h
> +++ b/tools/perf/util/parse-events.h
> @@ -64,9 +64,6 @@ 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);
> -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,
>   			     struct list_head *head_config);
> diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> index e03b58a..6030758 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 ce61cb2..0d2cf8b 100644
> --- a/tools/perf/util/top.h
> +++ b/tools/perf/util/top.h
> @@ -33,7 +33,7 @@ struct perf_top {
>   	bool		   kptr_restrict_warned;
>   	bool		   vmlinux_warned;
>   	bool		   inherit;
> -	bool		   group;
> +	enum perf_group_opt group;
>   	bool		   sample_id_all_missing;
>   	bool		   exclude_guest_missing;
>   	bool		   dump_symtab;


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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 20:46     ` Ingo Molnar
  2012-03-20 22:18       ` Arnaldo Carvalho de Melo
@ 2012-03-21  9:15       ` Peter Zijlstra
  2012-03-21  9:52         ` Ingo Molnar
  1 sibling, 1 reply; 28+ messages in thread
From: Peter Zijlstra @ 2012-03-21  9:15 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner

On Tue, 2012-03-20 at 21:46 +0100, Ingo Molnar wrote:
> * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> 
> > Now the disadvantage is that {} needs quotes on bash, [...]
> 
> Not on my version of Bash:
> 
>  earth5:~> perf stat {}
>  {}: No such file or directory
>  Terminated
>  earth5:~> perf stat true {}
> 
>   Performance counter stats for 'true {}':
> 
> it's passed in literally, AFAICS.

# echo {}
{}
# echo {en,dis}able
enable disable


It somehow special cases {}, which is horrible.

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21  9:15       ` Peter Zijlstra
@ 2012-03-21  9:52         ` Ingo Molnar
  2012-03-21 11:54           ` Peter Zijlstra
  0 siblings, 1 reply; 28+ messages in thread
From: Ingo Molnar @ 2012-03-21  9:52 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner


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

> # echo {}
> {}
> # echo {en,dis}able
> enable disable
> 
> 
> It somehow special cases {}, which is horrible.

Oh, indeed: brace expansion and sequence expressions both use 
curly braces:

 $ echo foo-{a,b,c}-bar
 foo-a-bar foo-b-bar foo-c-bar

 $ echo {1..10}
 1 2 3 4 5 6 7 8 9 10

Too bad, it would be rather intuitive. All the brace characters 
are taken by Bash.

Maybe something like:

 $ echo /minor-faults,major-faults/
 /minor-faults,major-faults/

although it looks a bit weird.

So ... how about using another grouping operator, such as '+'?

Something like:

 -e minor-faults+major-faults

While when comma separated they are not grouped, or so.

?

Thanks,

	Ingo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:44   ` Peter Zijlstra
  2012-03-20 20:46     ` Ingo Molnar
  2012-03-20 22:36     ` Jiri Olsa
@ 2012-03-21 10:42     ` Jiri Olsa
  2012-03-21 15:11       ` Arnaldo Carvalho de Melo
  2012-04-10 13:19     ` Jiri Olsa
  3 siblings, 1 reply; 28+ messages in thread
From: Jiri Olsa @ 2012-03-21 10:42 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: acme, mingo, paulus, cjashfor, fweisbec, linux-kernel, Thomas Gleixner

On Tue, Mar 20, 2012 at 07:44:41PM +0100, Peter Zijlstra wrote:
> On Tue, 2012-03-20 at 19:15 +0100, Jiri Olsa wrote:
> > 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 
> 
> I can't help but dislike the --group/--group parsed thing...
> 
> How about something like:
> 
>   event_group = "{", events, "}" , [ ":", event_group_mod ]
> 
> Such that you can write things like:
> 
>   perf record -e "{cpu-clock,cache-misses,cache-references}"
> 
>   perf stat -e "{cpu-clock,cycles},{cpu-clock,cache-misses,cache-references}"
>   perf stat -e "{cpu-clock,cycles}" -e "{cpu-clock,cache-misses,cache-references}"
> 
> I'm not sure what the current behaviour of --group is, if you create a
> group like this, do they all sample?
> 
> If so, we need some option like:
> 
>   perf record -e "{cpu-clock,cache-misses,cache-references}:1"
> 
> to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
> PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.
> 
> Now the disadvantage is that {} needs quotes on bash, the advantage is
> that its completely natural on how to construct groups, without weird
> --group/--group parsed. Also it provides a place for group modifiers.

how about '=group' keyword followed by ':' modifier
  perf record -e "cpu-clock,cache-misses,cache-references=group:1"

or '=$groupname' and use the group name in output like
  perf stat -e "task-clock,context-switches=krava:1" ls

     Performance counter stats for 'ls':

          1.003695 task-clock/krava          #    0.083 CPUs utilized          
                 0 context-switches/krava    #    0.000 K/sec                  


jirka

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21  9:52         ` Ingo Molnar
@ 2012-03-21 11:54           ` Peter Zijlstra
  2012-03-21 12:15             ` Ingo Molnar
  0 siblings, 1 reply; 28+ messages in thread
From: Peter Zijlstra @ 2012-03-21 11:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner

On Wed, 2012-03-21 at 10:52 +0100, Ingo Molnar wrote:
> * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> 
> > # echo {}
> > {}
> > # echo {en,dis}able
> > enable disable
> > 
> > 
> > It somehow special cases {}, which is horrible.
> 
> Oh, indeed: brace expansion and sequence expressions both use 
> curly braces:
> 
>  $ echo foo-{a,b,c}-bar
>  foo-a-bar foo-b-bar foo-c-bar
> 
>  $ echo {1..10}
>  1 2 3 4 5 6 7 8 9 10
> 
> Too bad, it would be rather intuitive. All the brace characters 
> are taken by Bash.
> 
> Maybe something like:
> 
>  $ echo /minor-faults,major-faults/
>  /minor-faults,major-faults/
> 
> although it looks a bit weird.
> 
> So ... how about using another grouping operator, such as '+'?
> 
> Something like:
> 
>  -e minor-faults+major-faults
> 
> While when comma separated they are not grouped, or so.

I would much prefer a syntax that's more natural but requires quoting
than one that's quirky and tailor made to avoid whatever current bash
does. For one, there's other shells out there that might have different
quoting needs and bash is of course free to extend its syntax.



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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 22:36     ` Jiri Olsa
@ 2012-03-21 11:54       ` Peter Zijlstra
  0 siblings, 0 replies; 28+ messages in thread
From: Peter Zijlstra @ 2012-03-21 11:54 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: acme, mingo, paulus, cjashfor, fweisbec, linux-kernel, Thomas Gleixner

On Tue, 2012-03-20 at 23:36 +0100, Jiri Olsa wrote:
> > If so, we need some option like:
> > 
> >   perf record -e "{cpu-clock,cache-misses,cache-references}:1"
> > 
> > to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
> > PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.
> 
> never happy, are you.. ;) seems like nice feature, will check 

Hehe, its a long standing feature request. Also tglx asked for it only a
few days ago.

I just saw a good opportunity ;-)

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21 11:54           ` Peter Zijlstra
@ 2012-03-21 12:15             ` Ingo Molnar
  2012-03-21 15:13               ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 28+ messages in thread
From: Ingo Molnar @ 2012-03-21 12:15 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Jiri Olsa, acme, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner


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

> On Wed, 2012-03-21 at 10:52 +0100, Ingo Molnar wrote:
> > * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> > 
> > > # echo {}
> > > {}
> > > # echo {en,dis}able
> > > enable disable
> > > 
> > > 
> > > It somehow special cases {}, which is horrible.
> > 
> > Oh, indeed: brace expansion and sequence expressions both use 
> > curly braces:
> > 
> >  $ echo foo-{a,b,c}-bar
> >  foo-a-bar foo-b-bar foo-c-bar
> > 
> >  $ echo {1..10}
> >  1 2 3 4 5 6 7 8 9 10
> > 
> > Too bad, it would be rather intuitive. All the brace characters 
> > are taken by Bash.
> > 
> > Maybe something like:
> > 
> >  $ echo /minor-faults,major-faults/
> >  /minor-faults,major-faults/
> > 
> > although it looks a bit weird.
> > 
> > So ... how about using another grouping operator, such as '+'?
> > 
> > Something like:
> > 
> >  -e minor-faults+major-faults
> > 
> > While when comma separated they are not grouped, or so.
> 
> I would much prefer a syntax that's more natural but requires 
> quoting than one that's quirky and tailor made to avoid 
> whatever current bash does. For one, there's other shells out 
> there that might have different quoting needs and bash is of 
> course free to extend its syntax.

Well, they are unlikely to extend to '+', it would break a 
boatload of scripts I suspect.

So the question would be, is a+b+c as event grouping a natural 
syntax? If not then lets use a quoted one that is.

Thanks,

	Ingo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21 10:42     ` Jiri Olsa
@ 2012-03-21 15:11       ` Arnaldo Carvalho de Melo
  2012-03-21 22:27         ` Jiri Olsa
  0 siblings, 1 reply; 28+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-03-21 15:11 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Peter Zijlstra, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner

Em Wed, Mar 21, 2012 at 11:42:14AM +0100, Jiri Olsa escreveu:
> On Tue, Mar 20, 2012 at 07:44:41PM +0100, Peter Zijlstra wrote:
> > If so, we need some option like:
> > 
> >   perf record -e "{cpu-clock,cache-misses,cache-references}:1"
> > 
> > to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
> > PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.
> > 
> > Now the disadvantage is that {} needs quotes on bash, the advantage is
> > that its completely natural on how to construct groups, without weird
> > --group/--group parsed. Also it provides a place for group modifiers.
> 
> how about '=group' keyword followed by ':' modifier
>   perf record -e "cpu-clock,cache-misses,cache-references=group:1"
> 
> or '=$groupname' and use the group name in output like
>   perf stat -e "task-clock,context-switches=krava:1" ls
> 
>      Performance counter stats for 'ls':
> 
>           1.003695 task-clock/krava          #    0.083 CPUs utilized          
>                  0 context-switches/krava    #    0.000 K/sec                  
> 

Humm, interesting, perhaps putting the group name before the =event_list
will be more intuitive?

I.e.:

  perf stat -e "krava=task-clock,context-switches:1" ls

- Arnaldo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21 12:15             ` Ingo Molnar
@ 2012-03-21 15:13               ` Arnaldo Carvalho de Melo
  2012-03-22  7:56                 ` Ingo Molnar
  0 siblings, 1 reply; 28+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-03-21 15:13 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Peter Zijlstra, Jiri Olsa, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, Thomas Gleixner

Em Wed, Mar 21, 2012 at 01:15:10PM +0100, Ingo Molnar escreveu:
> * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> > I would much prefer a syntax that's more natural but requires 
> > quoting than one that's quirky and tailor made to avoid 
> > whatever current bash does. For one, there's other shells out 
> > there that might have different quoting needs and bash is of 
> > course free to extend its syntax.
> 
> Well, they are unlikely to extend to '+', it would break a 
> boatload of scripts I suspect.
> 
> So the question would be, is a+b+c as event grouping a natural 
> syntax? If not then lets use a quoted one that is.

   -e groupname=event1,event2,event3

Seems intuitive, no?

- Arnaldo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21 15:11       ` Arnaldo Carvalho de Melo
@ 2012-03-21 22:27         ` Jiri Olsa
  2012-03-22 12:40           ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 28+ messages in thread
From: Jiri Olsa @ 2012-03-21 22:27 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner

On Wed, Mar 21, 2012 at 12:11:19PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Wed, Mar 21, 2012 at 11:42:14AM +0100, Jiri Olsa escreveu:
> > On Tue, Mar 20, 2012 at 07:44:41PM +0100, Peter Zijlstra wrote:
> > > If so, we need some option like:
> > > 
> > >   perf record -e "{cpu-clock,cache-misses,cache-references}:1"
> > > 
> > > to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
> > > PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.
> > > 
> > > Now the disadvantage is that {} needs quotes on bash, the advantage is
> > > that its completely natural on how to construct groups, without weird
> > > --group/--group parsed. Also it provides a place for group modifiers.
> > 
> > how about '=group' keyword followed by ':' modifier
> >   perf record -e "cpu-clock,cache-misses,cache-references=group:1"
> > 
> > or '=$groupname' and use the group name in output like
> >   perf stat -e "task-clock,context-switches=krava:1" ls
> > 
> >      Performance counter stats for 'ls':
> > 
> >           1.003695 task-clock/krava          #    0.083 CPUs utilized          
> >                  0 context-switches/krava    #    0.000 K/sec                  
> > 
> 
> Humm, interesting, perhaps putting the group name before the =event_list
> will be more intuitive?
> 
> I.e.:
> 
>   perf stat -e "krava=task-clock,context-switches:1" ls

yep, I put it at the end because of the ':' modifier stuff.
We have it for each event, and it'd be in conflict having
it at the end..

maybe we could put it like:
   perf stat -e "krava:1=task-clock,context-switches" ls

or put some other separator instead of ':' ... but ':' is the best ;)

jirka

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21 15:13               ` Arnaldo Carvalho de Melo
@ 2012-03-22  7:56                 ` Ingo Molnar
  2012-03-22 12:41                   ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 28+ messages in thread
From: Ingo Molnar @ 2012-03-22  7:56 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Jiri Olsa, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, Thomas Gleixner


* Arnaldo Carvalho de Melo <acme@redhat.com> wrote:

> Em Wed, Mar 21, 2012 at 01:15:10PM +0100, Ingo Molnar escreveu:
> > * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> > > I would much prefer a syntax that's more natural but requires 
> > > quoting than one that's quirky and tailor made to avoid 
> > > whatever current bash does. For one, there's other shells out 
> > > there that might have different quoting needs and bash is of 
> > > course free to extend its syntax.
> > 
> > Well, they are unlikely to extend to '+', it would break a 
> > boatload of scripts I suspect.
> > 
> > So the question would be, is a+b+c as event grouping a natural 
> > syntax? If not then lets use a quoted one that is.
> 
>    -e groupname=event1,event2,event3
> 
> Seems intuitive, no?

Hm, if there's no use for 'groupname' later on then it's a 
needlessly unspecified dimension. If this variant is picked then 
I'd suggest to make it a fixed:

  -e group=event1,event2,event3

kind of thing instead.

Thanks,

	Ingo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-21 22:27         ` Jiri Olsa
@ 2012-03-22 12:40           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 28+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-03-22 12:40 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Peter Zijlstra, mingo, paulus, cjashfor, fweisbec, linux-kernel,
	Thomas Gleixner

Em Wed, Mar 21, 2012 at 11:27:24PM +0100, Jiri Olsa escreveu:
> On Wed, Mar 21, 2012 at 12:11:19PM -0300, Arnaldo Carvalho de Melo wrote:
> > Em Wed, Mar 21, 2012 at 11:42:14AM +0100, Jiri Olsa escreveu:
> > > On Tue, Mar 20, 2012 at 07:44:41PM +0100, Peter Zijlstra wrote:
> > > > If so, we need some option like:
> > > > 
> > > >   perf record -e "{cpu-clock,cache-misses,cache-references}:1"
> > > > 
> > > > to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
> > > > PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.
> > > > 
> > > > Now the disadvantage is that {} needs quotes on bash, the advantage is
> > > > that its completely natural on how to construct groups, without weird
> > > > --group/--group parsed. Also it provides a place for group modifiers.
> > > 
> > > how about '=group' keyword followed by ':' modifier
> > >   perf record -e "cpu-clock,cache-misses,cache-references=group:1"
> > > 
> > > or '=$groupname' and use the group name in output like
> > >   perf stat -e "task-clock,context-switches=krava:1" ls
> > > 
> > >      Performance counter stats for 'ls':
> > > 
> > >           1.003695 task-clock/krava          #    0.083 CPUs utilized          
> > >                  0 context-switches/krava    #    0.000 K/sec                  
> > > 
> > 
> > Humm, interesting, perhaps putting the group name before the =event_list
> > will be more intuitive?
> > 
> > I.e.:
> > 
> >   perf stat -e "krava=task-clock,context-switches:1" ls
> 
> yep, I put it at the end because of the ':' modifier stuff.
> We have it for each event, and it'd be in conflict having
> it at the end..
> 
> maybe we could put it like:
>    perf stat -e "krava:1=task-clock,context-switches" ls
> 
> or put some other separator instead of ':' ... but ':' is the best ;)

That thought crossed my mind as well, indeed it seems more intuitive:
everything before the '=' defines the group wide attributes (name,
modifiers, whatevever else we need later) after it, the evlist, where
each evsel can have its own attributes.

- Arnaldo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-22  7:56                 ` Ingo Molnar
@ 2012-03-22 12:41                   ` Arnaldo Carvalho de Melo
  2012-03-22 13:54                     ` Ingo Molnar
  0 siblings, 1 reply; 28+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-03-22 12:41 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Peter Zijlstra, Jiri Olsa, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, Thomas Gleixner

Em Thu, Mar 22, 2012 at 08:56:34AM +0100, Ingo Molnar escreveu:
> 
> * Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
> 
> > Em Wed, Mar 21, 2012 at 01:15:10PM +0100, Ingo Molnar escreveu:
> > > * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> > > > I would much prefer a syntax that's more natural but requires 
> > > > quoting than one that's quirky and tailor made to avoid 
> > > > whatever current bash does. For one, there's other shells out 
> > > > there that might have different quoting needs and bash is of 
> > > > course free to extend its syntax.
> > > 
> > > Well, they are unlikely to extend to '+', it would break a 
> > > boatload of scripts I suspect.
> > > 
> > > So the question would be, is a+b+c as event grouping a natural 
> > > syntax? If not then lets use a quoted one that is.
> > 
> >    -e groupname=event1,event2,event3
> > 
> > Seems intuitive, no?
> 
> Hm, if there's no use for 'groupname' later on then it's a 
> needlessly unspecified dimension. If this variant is picked then 
> I'd suggest to make it a fixed:
> 
>   -e group=event1,event2,event3
> 
> kind of thing instead.

Jiri mentioned a use for the group name, no?

- Arnaldo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-22 12:41                   ` Arnaldo Carvalho de Melo
@ 2012-03-22 13:54                     ` Ingo Molnar
  2012-03-22 14:07                       ` Jiri Olsa
  0 siblings, 1 reply; 28+ messages in thread
From: Ingo Molnar @ 2012-03-22 13:54 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Jiri Olsa, mingo, paulus, cjashfor, fweisbec,
	linux-kernel, Thomas Gleixner


* Arnaldo Carvalho de Melo <acme@redhat.com> wrote:

> Em Thu, Mar 22, 2012 at 08:56:34AM +0100, Ingo Molnar escreveu:
> > 
> > * Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
> > 
> > > Em Wed, Mar 21, 2012 at 01:15:10PM +0100, Ingo Molnar escreveu:
> > > > * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> > > > > I would much prefer a syntax that's more natural but requires 
> > > > > quoting than one that's quirky and tailor made to avoid 
> > > > > whatever current bash does. For one, there's other shells out 
> > > > > there that might have different quoting needs and bash is of 
> > > > > course free to extend its syntax.
> > > > 
> > > > Well, they are unlikely to extend to '+', it would break a 
> > > > boatload of scripts I suspect.
> > > > 
> > > > So the question would be, is a+b+c as event grouping a natural 
> > > > syntax? If not then lets use a quoted one that is.
> > > 
> > >    -e groupname=event1,event2,event3
> > > 
> > > Seems intuitive, no?
> > 
> > Hm, if there's no use for 'groupname' later on then it's a 
> > needlessly unspecified dimension. If this variant is picked then 
> > I'd suggest to make it a fixed:
> > 
> >   -e group=event1,event2,event3
> > 
> > kind of thing instead.
> 
> Jiri mentioned a use for the group name, no?

Only for perf stat output, right?

Thanks,

	Ingo

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-22 13:54                     ` Ingo Molnar
@ 2012-03-22 14:07                       ` Jiri Olsa
  0 siblings, 0 replies; 28+ messages in thread
From: Jiri Olsa @ 2012-03-22 14:07 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, mingo, paulus,
	cjashfor, fweisbec, linux-kernel, Thomas Gleixner

On Thu, Mar 22, 2012 at 02:54:29PM +0100, Ingo Molnar wrote:
> 
> * Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
> 
> > Em Thu, Mar 22, 2012 at 08:56:34AM +0100, Ingo Molnar escreveu:
> > > 
> > > * Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
> > > 
> > > > Em Wed, Mar 21, 2012 at 01:15:10PM +0100, Ingo Molnar escreveu:
> > > > > * Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:
> > > > > > I would much prefer a syntax that's more natural but requires 
> > > > > > quoting than one that's quirky and tailor made to avoid 
> > > > > > whatever current bash does. For one, there's other shells out 
> > > > > > there that might have different quoting needs and bash is of 
> > > > > > course free to extend its syntax.
> > > > > 
> > > > > Well, they are unlikely to extend to '+', it would break a 
> > > > > boatload of scripts I suspect.
> > > > > 
> > > > > So the question would be, is a+b+c as event grouping a natural 
> > > > > syntax? If not then lets use a quoted one that is.
> > > > 
> > > >    -e groupname=event1,event2,event3
> > > > 
> > > > Seems intuitive, no?
> > > 
> > > Hm, if there's no use for 'groupname' later on then it's a 
> > > needlessly unspecified dimension. If this variant is picked then 
> > > I'd suggest to make it a fixed:
> > > 
> > >   -e group=event1,event2,event3
> > > 
> > > kind of thing instead.
> > 
> > Jiri mentioned a use for the group name, no?
> 
> Only for perf stat output, right?
> 

right.. hm, using it in perf report would need to have it
stored in the data file.. not sure thats worth the effort

maybe let's start with 'group:mod=' and we can add later something
like 'group/name:mod=' if there's need to see group name in output

I think it's better to have one event syntax for all commands

jirka

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

* [tip:perf/urgent] perf tools: Fix various casting issues for 32 bits
  2012-03-20 18:15 ` [PATCH 1/3] perf, tool: Fix various casting issues for 32 bits Jiri Olsa
@ 2012-03-23  8:29   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 28+ messages in thread
From: tip-bot for Jiri Olsa @ 2012-03-23  8:29 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa,
	fweisbec, tglx, cjashfor, mingo

Commit-ID:  9fafd98f1bf14276f95b69f0186ad5675f1e1a18
Gitweb:     http://git.kernel.org/tip/9fafd98f1bf14276f95b69f0186ad5675f1e1a18
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Tue, 20 Mar 2012 19:15:39 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 22 Mar 2012 15:11:18 -0300

perf tools: Fix various casting issues for 32 bits

- util/parse-events.c(parse_events_add_breakpoint)
  need to use unsigned long instead of u64, otherwise
  we get following gcc error on 32 bits:
     error: cast from pointer to integer of different size

- util/header.c(print_event_desc)
  cannot retype to signed type, otherwise we get following
  gcc error on 32 bits:
     error: comparison between signed and unsigned integer expressions

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

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index fcd9cf3..4c7c2d7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1177,7 +1177,7 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
 		goto error;
 
 	msz = sizeof(attr);
-	if (sz < (ssize_t)msz)
+	if (sz < msz)
 		msz = sz;
 
 	for (i = 0 ; i < nre; i++) {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 201b40f..f542a63 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -569,7 +569,7 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
 	char name[MAX_NAME_LEN];
 
 	memset(&attr, 0, sizeof(attr));
-	attr.bp_addr = (u64) ptr;
+	attr.bp_addr = (unsigned long) ptr;
 
 	if (parse_breakpoint_type(type, &attr))
 		return -EINVAL;

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

* [tip:perf/urgent] perf tools: Fix modifier to be applied on correct events
  2012-03-20 18:15 ` [PATCH 2/3] perf, tool: Fix modifier to be applied on correct events Jiri Olsa
@ 2012-03-23  8:30   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 28+ messages in thread
From: tip-bot for Jiri Olsa @ 2012-03-23  8:30 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, jolsa,
	fweisbec, tglx, cjashfor, mingo

Commit-ID:  5d7be90ed5cfb5dd3c9ab726d7daa91b86b81747
Gitweb:     http://git.kernel.org/tip/5d7be90ed5cfb5dd3c9ab726d7daa91b86b81747
Author:     Jiri Olsa <jolsa@redhat.com>
AuthorDate: Tue, 20 Mar 2012 19:15:40 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 22 Mar 2012 15:11:38 -0300

perf tools: Fix modifier to be applied on correct events

The event modifier needs to be applied only on the event definition it
is attached to.

The current state is that in case of multiple events definition (in
single '-e' option, separated by ',') all will get modifier of the last
one.

Fixing this by adding separated list for each event definition, so the
modifier is applied only to proper event(s). Added automated test to
catch this, plus some other modifier tests.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1332267341-26338-3-git-send-email-jolsa@redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-test.c            |  116 ++++++-
 tools/perf/util/parse-events-bison.c |  675 +++++++++++++++++++---------------
 tools/perf/util/parse-events-bison.h |   15 +-
 tools/perf/util/parse-events.c       |   27 +-
 tools/perf/util/parse-events.h       |    7 +-
 tools/perf/util/parse-events.y       |   40 ++-
 6 files changed, 543 insertions(+), 337 deletions(-)

diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 8687423..1c5b980 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -877,6 +877,58 @@ static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
 	return test__checkevent_genhw(evlist);
 }
 
+static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint(evlist);
+}
+
+static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_x(evlist);
+}
+
+static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_r(evlist);
+}
+
+static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return test__checkevent_breakpoint_w(evlist);
+}
+
 static int test__checkevent_pmu(struct perf_evlist *evlist)
 {
 
@@ -893,6 +945,47 @@ static int test__checkevent_pmu(struct perf_evlist *evlist)
 	return 0;
 }
 
+static int test__checkevent_list(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* r1 */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* syscalls:sys_enter_open:k */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+		evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+	/* 1:1:hp */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -975,9 +1068,29 @@ static struct test__event_st {
 		.check = test__checkevent_genhw_modifier,
 	},
 	{
+		.name  = "mem:0:u",
+		.check = test__checkevent_breakpoint_modifier,
+	},
+	{
+		.name  = "mem:0:x:k",
+		.check = test__checkevent_breakpoint_x_modifier,
+	},
+	{
+		.name  = "mem:0:r:hp",
+		.check = test__checkevent_breakpoint_r_modifier,
+	},
+	{
+		.name  = "mem:0:w:up",
+		.check = test__checkevent_breakpoint_w_modifier,
+	},
+	{
 		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
 		.check = test__checkevent_pmu,
 	},
+	{
+		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
+		.check = test__checkevent_list,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
@@ -1003,10 +1116,9 @@ static int test__parse_events(void)
 		}
 
 		ret = e->check(evlist);
+		perf_evlist__delete(evlist);
 		if (ret)
 			break;
-
-		perf_evlist__delete(evlist);
 	}
 
 	return ret;
diff --git a/tools/perf/util/parse-events-bison.c b/tools/perf/util/parse-events-bison.c
index 4a0fd6d..4a4e02a 100644
--- a/tools/perf/util/parse-events-bison.c
+++ b/tools/perf/util/parse-events-bison.c
@@ -1,9 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.4.3.  */
+/* A Bison parser, made by GNU Bison 2.5.  */
 
-/* Skeleton implementation for Bison's Yacc-like parsers in C
+/* Bison implementation for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2009, 2010 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2011 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
@@ -45,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.4.3"
+#define YYBISON_VERSION "2.5"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -74,8 +73,8 @@
 
 /* Copy the first part of user declarations.  */
 
-/* Line 189 of yacc.c  */
-#line 6 "util/parse-events.y"
+/* Line 268 of yacc.c  */
+#line 7 "util/parse-events.y"
 
 
 #define YYDEBUG 1
@@ -96,8 +95,8 @@ do { \
 
 
 
-/* Line 189 of yacc.c  */
-#line 101 "util/parse-events-bison.c"
+/* Line 268 of yacc.c  */
+#line 100 "util/parse-events-bison.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -145,8 +144,8 @@ do { \
 typedef union YYSTYPE
 {
 
-/* Line 214 of yacc.c  */
-#line 45 "util/parse-events.y"
+/* Line 293 of yacc.c  */
+#line 46 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
@@ -155,8 +154,8 @@ typedef union YYSTYPE
 
 
 
-/* Line 214 of yacc.c  */
-#line 160 "util/parse-events-bison.c"
+/* Line 293 of yacc.c  */
+#line 159 "util/parse-events-bison.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -167,8 +166,8 @@ typedef union YYSTYPE
 /* Copy the second part of user declarations.  */
 
 
-/* Line 264 of yacc.c  */
-#line 172 "util/parse-events-bison.c"
+/* Line 343 of yacc.c  */
+#line 171 "util/parse-events-bison.c"
 
 #ifdef short
 # undef short
@@ -271,11 +270,11 @@ YYID (yyi)
 #    define alloca _alloca
 #   else
 #    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (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
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
 #     endif
 #    endif
 #   endif
@@ -298,24 +297,24 @@ YYID (yyi)
 #  ifndef YYSTACK_ALLOC_MAXIMUM
 #   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
 #  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
        && ! ((defined YYMALLOC || defined malloc) \
 	     && (defined YYFREE || defined free)))
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
 #   endif
 #  endif
 #  ifndef YYMALLOC
 #   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+#   if ! defined malloc && ! defined EXIT_SUCCESS && (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__ \
+#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
@@ -344,23 +343,7 @@ union yyalloc
      ((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
+# define YYCOPY_NEEDED 1
 
 /* Relocate STACK from its old location to the new one.  The
    local variables YYSIZE and YYSTACKSIZE give the old and new number of
@@ -380,6 +363,26 @@ union yyalloc
 
 #endif
 
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* 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
+#endif /* !YYCOPY_NEEDED */
+
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  25
 /* YYLAST -- Last index in YYTABLE.  */
@@ -463,10 +466,10 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    54,    54,    54,    57,    62,    64,    65,    66,    67,
-      68,    69,    70,    73,    80,    89,    98,   103,   108,   114,
-     119,   125,   131,   137,   143,   153,   165,   174,   183,   192,
-     200,   208,   208,   210,   210,   210
+       0,    55,    55,    55,    58,    69,    74,    75,    76,    77,
+      78,    79,    80,    83,    90,    99,   108,   113,   118,   124,
+     129,   135,   141,   147,   153,   163,   175,   184,   193,   202,
+     210,   218,   218,   220,   220,   220
 };
 #endif
 
@@ -514,8 +517,8 @@ static const yytype_uint8 yyr2[] =
        1,     1,     0,     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
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE doesn't specify something else to do.  Zero
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
@@ -556,8 +559,7 @@ static const yytype_int8 yypgoto[] =
 
 /* 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.  */
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
@@ -568,6 +570,12 @@ static const yytype_uint8 yytable[] =
       38,    54,     0,    43
 };
 
+#define yypact_value_is_default(yystate) \
+  ((yystate) == (-15))
+
+#define yytable_value_is_error(yytable_value) \
+  YYID (0)
+
 static const yytype_int8 yycheck[] =
 {
       14,    15,    16,     0,     3,     4,     5,    16,     7,    18,
@@ -622,13 +630,12 @@ do								\
     {								\
       yychar = (Token);						\
       yylval = (Value);						\
-      yytoken = YYTRANSLATE (yychar);				\
       YYPOPSTACK (1);						\
       goto yybackup;						\
     }								\
   else								\
     {								\
-      yyerror (list, idx, YY_("syntax error: cannot back up")); \
+      yyerror (list_all, list_event, idx, YY_("syntax error: cannot back up")); \
       YYERROR;							\
     }								\
 while (YYID (0))
@@ -664,19 +671,10 @@ 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.  */
+/* This macro is provided for backward compatibility. */
 
 #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
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 #endif
 
 
@@ -708,7 +706,7 @@ do {									  \
     {									  \
       YYFPRINTF (stderr, "%s ", Title);					  \
       yy_symbol_print (stderr,						  \
-		  Type, Value, list, idx); \
+		  Type, Value, list_all, list_event, idx); \
       YYFPRINTF (stderr, "\n");						  \
     }									  \
 } while (YYID (0))
@@ -722,20 +720,22 @@ do {									  \
 #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)
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx)
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, list_all, list_event, idx)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
   if (!yyvaluep)
     return;
-  YYUSE (list);
+  YYUSE (list_all);
+  YYUSE (list_event);
   YYUSE (idx);
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
@@ -758,14 +758,15 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx)
 #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)
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, list, idx)
+yy_symbol_print (yyoutput, yytype, yyvaluep, list_all, list_event, idx)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
@@ -774,7 +775,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, list, idx)
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep, list, idx);
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, list_all, list_event, idx);
   YYFPRINTF (yyoutput, ")");
 }
 
@@ -817,13 +818,14 @@ do {								\
 #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)
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yy_reduce_print (yyvsp, yyrule, list, idx)
+yy_reduce_print (yyvsp, yyrule, list_all, list_event, idx)
     YYSTYPE *yyvsp;
     int yyrule;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
@@ -838,7 +840,7 @@ yy_reduce_print (yyvsp, yyrule, list, idx)
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
 		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       , list, idx);
+		       		       , list_all, list_event, idx);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -846,7 +848,7 @@ yy_reduce_print (yyvsp, yyrule, list, idx)
 # define YY_REDUCE_PRINT(Rule)		\
 do {					\
   if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule, list, idx); \
+    yy_reduce_print (yyvsp, Rule, list_all, list_event, idx); \
 } while (YYID (0))
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
@@ -876,7 +878,6 @@ int yydebug;
 # define YYMAXDEPTH 10000
 #endif
 
-\f
 
 #if YYERROR_VERBOSE
 
@@ -979,115 +980,142 @@ yytnamerr (char *yyres, const char *yystr)
 }
 # 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];
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
 
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  YYSIZE_T yysize1;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = 0;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - Assume YYFAIL is not used.  It's too flawed to consider.  See
+       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+       for details.  YYERROR is fine as it does not invoke this
+       function.
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
     {
-      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;
-	  }
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          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 yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+                if (! (yysize <= yysize1
+                       && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                  return 2;
+                yysize = yysize1;
+              }
+        }
+    }
 
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
 
-      if (yysize_overflow)
-	return YYSIZE_MAXIMUM;
+  yysize1 = yysize + yystrlen (yyformat);
+  if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+    return 2;
+  yysize = yysize1;
 
-      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;
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
     }
+
+  /* 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 = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
 }
 #endif /* YYERROR_VERBOSE */
-\f
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
@@ -1097,19 +1125,21 @@ yysyntax_error (char *yyresult, int yystate, int yychar)
 #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)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 static void
-yydestruct (yymsg, yytype, yyvaluep, list, idx)
+yydestruct (yymsg, yytype, yyvaluep, list_all, list_event, idx)
     const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
-    struct list_head *list;
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 {
   YYUSE (yyvaluep);
-  YYUSE (list);
+  YYUSE (list_all);
+  YYUSE (list_event);
   YYUSE (idx);
 
   if (!yymsg)
@@ -1124,6 +1154,7 @@ yydestruct (yymsg, yytype, yyvaluep, list, idx)
     }
 }
 
+
 /* Prevent warnings from -Wmissing-prototypes.  */
 #ifdef YYPARSE_PARAM
 #if defined __STDC__ || defined __cplusplus
@@ -1133,7 +1164,7 @@ int yyparse ();
 #endif
 #else /* ! YYPARSE_PARAM */
 #if defined __STDC__ || defined __cplusplus
-int yyparse (struct list_head *list, int *idx);
+int yyparse (struct list_head *list_all, struct list_head *list_event, int *idx);
 #else
 int yyparse ();
 #endif
@@ -1150,10 +1181,9 @@ YYSTYPE yylval;
 int yynerrs;
 
 
-
-/*-------------------------.
-| yyparse or yypush_parse.  |
-`-------------------------*/
+/*----------.
+| yyparse.  |
+`----------*/
 
 #ifdef YYPARSE_PARAM
 #if (defined __STDC__ || defined __C99__FUNC__ \
@@ -1169,17 +1199,16 @@ yyparse (YYPARSE_PARAM)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 int
-yyparse (struct list_head *list, int *idx)
+yyparse (struct list_head *list_all, struct list_head *list_event, int *idx)
 #else
 int
-yyparse (list, idx)
-    struct list_head *list;
+yyparse (list_all, list_event, idx)
+    struct list_head *list_all;
+    struct list_head *list_event;
     int *idx;
 #endif
 #endif
 {
-
-
     int yystate;
     /* Number of tokens to shift before error messages enabled.  */
     int yyerrstatus;
@@ -1334,7 +1363,7 @@ yybackup:
 
   /* First try to decide what to do without reference to lookahead token.  */
   yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
+  if (yypact_value_is_default (yyn))
     goto yydefault;
 
   /* Not known => get a lookahead token if don't already have one.  */
@@ -1365,8 +1394,8 @@ yybackup:
   yyn = yytable[yyn];
   if (yyn <= 0)
     {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-	goto yyerrlab;
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1421,124 +1450,139 @@ yyreduce:
     {
         case 4:
 
-/* Line 1464 of yacc.c  */
-#line 58 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 59 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_modifier(list, (yyvsp[(2) - (2)].str)));
-;}
+	/*
+	 * Apply modifier on all events added by single event definition
+	 * (there could be more events added for multiple tracepoint
+	 * definitions via '*?'.
+	 */
+	ABORT_ON(parse_events_modifier(list_event, (yyvsp[(2) - (2)].str)));
+	parse_events_update_lists(list_event, list_all);
+}
+    break;
+
+  case 5:
+
+/* Line 1806 of yacc.c  */
+#line 70 "util/parse-events.y"
+    {
+	parse_events_update_lists(list_event, list_all);
+}
     break;
 
   case 13:
 
-/* Line 1464 of yacc.c  */
-#line 74 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 84 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_pmu(list, idx, (yyvsp[(1) - (4)].str), (yyvsp[(3) - (4)].head)));
+	ABORT_ON(parse_events_add_pmu(list_event, 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 81 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 91 "util/parse-events.y"
     {
 	int type = (yyvsp[(1) - (4)].num) >> 16;
 	int config = (yyvsp[(1) - (4)].num) & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config, (yyvsp[(3) - (4)].head)));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, (yyvsp[(3) - (4)].head)));
 	parse_events__free_terms((yyvsp[(3) - (4)].head));
-;}
+}
     break;
 
   case 15:
 
-/* Line 1464 of yacc.c  */
-#line 90 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 100 "util/parse-events.y"
     {
 	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));
-;}
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
+}
     break;
 
   case 16:
 
-/* Line 1464 of yacc.c  */
-#line 99 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 109 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_cache(list, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
-;}
+	ABORT_ON(parse_events_add_cache(list_event, idx, (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)));
+}
     break;
 
   case 17:
 
-/* Line 1464 of yacc.c  */
-#line 104 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 114 "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_event, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL));
+}
     break;
 
   case 18:
 
-/* Line 1464 of yacc.c  */
-#line 109 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 119 "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_event, idx, (yyvsp[(1) - (1)].str), NULL, NULL));
+}
     break;
 
   case 19:
 
-/* Line 1464 of yacc.c  */
-#line 115 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 125 "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_breakpoint(list_event, idx, (void *) (yyvsp[(2) - (5)].num), (yyvsp[(4) - (5)].str)));
+}
     break;
 
   case 20:
 
-/* Line 1464 of yacc.c  */
-#line 120 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 130 "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_event, idx, (void *) (yyvsp[(2) - (3)].num), NULL));
+}
     break;
 
   case 21:
 
-/* Line 1464 of yacc.c  */
-#line 126 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 136 "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_tracepoint(list_event, idx, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)));
+}
     break;
 
   case 22:
 
-/* Line 1464 of yacc.c  */
-#line 132 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 142 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
-;}
+	ABORT_ON(parse_events_add_numeric(list_event, idx, (yyvsp[(1) - (3)].num), (yyvsp[(3) - (3)].num), NULL));
+}
     break;
 
   case 23:
 
-/* Line 1464 of yacc.c  */
-#line 138 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 148 "util/parse-events.y"
     {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
-;}
+	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, (yyvsp[(1) - (1)].num), NULL));
+}
     break;
 
   case 24:
 
-/* Line 1464 of yacc.c  */
-#line 144 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 154 "util/parse-events.y"
     {
 	struct list_head *head = (yyvsp[(1) - (3)].head);
 	struct parse_events__term *term = (yyvsp[(3) - (3)].term);
@@ -1546,13 +1590,13 @@ yyreduce:
 	ABORT_ON(!head);
 	list_add_tail(&term->list, head);
 	(yyval.head) = (yyvsp[(1) - (3)].head);
-;}
+}
     break;
 
   case 25:
 
-/* Line 1464 of yacc.c  */
-#line 154 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 164 "util/parse-events.y"
     {
 	struct list_head *head = malloc(sizeof(*head));
 	struct parse_events__term *term = (yyvsp[(1) - (1)].term);
@@ -1561,78 +1605,89 @@ yyreduce:
 	INIT_LIST_HEAD(head);
 	list_add_tail(&term->list, head);
 	(yyval.head) = head;
-;}
+}
     break;
 
   case 26:
 
-/* Line 1464 of yacc.c  */
-#line 166 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 176 "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 27:
 
-/* Line 1464 of yacc.c  */
-#line 175 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 185 "util/parse-events.y"
     {
 	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;
 
   case 28:
 
-/* Line 1464 of yacc.c  */
-#line 184 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 194 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
 	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
 		 (yyvsp[(1) - (1)].str), NULL, 1));
 	(yyval.term) = term;
-;}
+}
     break;
 
   case 29:
 
-/* Line 1464 of yacc.c  */
-#line 193 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 203 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
 	ABORT_ON(parse_events__new_term(&term, (yyvsp[(1) - (3)].num), NULL, NULL, (yyvsp[(3) - (3)].num)));
 	(yyval.term) = term;
-;}
+}
     break;
 
   case 30:
 
-/* Line 1464 of yacc.c  */
-#line 201 "util/parse-events.y"
+/* Line 1806 of yacc.c  */
+#line 211 "util/parse-events.y"
     {
 	struct parse_events__term *term;
 
 	ABORT_ON(parse_events__new_term(&term, (yyvsp[(1) - (1)].num), NULL, NULL, 1));
 	(yyval.term) = term;
-;}
+}
     break;
 
 
 
-/* Line 1464 of yacc.c  */
-#line 1634 "util/parse-events-bison.c"
+/* Line 1806 of yacc.c  */
+#line 1678 "util/parse-events-bison.c"
       default: break;
     }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
@@ -1660,44 +1715,47 @@ yyreduce:
 | yyerrlab -- here on detecting error |
 `------------------------------------*/
 yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
       ++yynerrs;
 #if ! YYERROR_VERBOSE
-      yyerror (list, idx, YY_("syntax error"));
+      yyerror (list_all, list_event, idx, YY_("syntax error"));
 #else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
       {
-	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;
-	  }
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (list_all, list_event, idx, yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
       }
+# undef YYSYNTAX_ERROR
 #endif
     }
 
@@ -1717,7 +1775,7 @@ yyerrlab:
       else
 	{
 	  yydestruct ("Error: discarding",
-		      yytoken, &yylval, list, idx);
+		      yytoken, &yylval, list_all, list_event, idx);
 	  yychar = YYEMPTY;
 	}
     }
@@ -1756,7 +1814,7 @@ yyerrlab1:
   for (;;)
     {
       yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
+      if (!yypact_value_is_default (yyn))
 	{
 	  yyn += YYTERROR;
 	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -1773,7 +1831,7 @@ yyerrlab1:
 
 
       yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp, list, idx);
+		  yystos[yystate], yyvsp, list_all, list_event, idx);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -1808,15 +1866,20 @@ yyabortlab:
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
-  yyerror (list, idx, YY_("memory exhausted"));
+  yyerror (list_all, list_event, idx, YY_("memory exhausted"));
   yyresult = 2;
   /* Fall through.  */
 #endif
 
 yyreturn:
   if (yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-		 yytoken, &yylval, list, idx);
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval, list_all, list_event, idx);
+    }
   /* Do not reclaim the symbols of the rule which action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
@@ -1824,7 +1887,7 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp, list, idx);
+		  yystos[*yyssp], yyvsp, list_all, list_event, idx);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
@@ -1841,11 +1904,13 @@ yyreturn:
 
 
 
-/* Line 1684 of yacc.c  */
-#line 212 "util/parse-events.y"
+/* Line 2067 of yacc.c  */
+#line 222 "util/parse-events.y"
 
 
-void parse_events_error(struct list_head *list __used, int *idx __used,
+void parse_events_error(struct list_head *list_all __used,
+			struct list_head *list_event __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
index c58b765..0be3e5a 100644
--- a/tools/perf/util/parse-events-bison.h
+++ b/tools/perf/util/parse-events-bison.h
@@ -1,9 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.4.3.  */
+/* A Bison parser, made by GNU Bison 2.5.  */
 
-/* Skeleton interface for Bison's Yacc-like parsers in C
+/* Bison interface for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2009, 2010 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2011 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
@@ -59,8 +58,8 @@
 typedef union YYSTYPE
 {
 
-/* Line 1685 of yacc.c  */
-#line 45 "util/parse-events.y"
+/* Line 2068 of yacc.c  */
+#line 46 "util/parse-events.y"
 
 	char *str;
 	unsigned long num;
@@ -69,8 +68,8 @@ typedef union YYSTYPE
 
 
 
-/* Line 1685 of yacc.c  */
-#line 74 "util/parse-events-bison.h"
+/* Line 2068 of yacc.c  */
+#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 f542a63..5b3a0ef 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,7 +23,8 @@ struct event_symbol {
 	const char	*alias;
 };
 
-int parse_events_parse(struct list_head *list, int *idx);
+int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
+		       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
@@ -671,6 +672,18 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
 	return add_event(list, idx, &attr, (char *) "pmu");
 }
 
+void parse_events_update_lists(struct list_head *list_event,
+			       struct list_head *list_all)
+{
+	/*
+	 * Called for single event definition. Update the
+	 * 'all event' list, and reinit the 'signle event'
+	 * list, for next event definition.
+	 */
+	list_splice_tail(list_event, list_all);
+	INIT_LIST_HEAD(list_event);
+}
+
 int parse_events_modifier(struct list_head *list, char *str)
 {
 	struct perf_evsel *evsel;
@@ -736,14 +749,14 @@ int parse_events_modifier(struct list_head *list, char *str)
 
 int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
-	struct perf_evsel *evsel, *h;
 	LIST_HEAD(list);
+	LIST_HEAD(list_tmp);
 	YY_BUFFER_STATE buffer;
 	int ret, idx = evlist->nr_entries;
 
 	buffer = parse_events__scan_string(str);
 
-	ret = parse_events_parse(&list, &idx);
+	ret = parse_events_parse(&list, &list_tmp, &idx);
 
 	parse_events__flush_buffer(buffer);
 	parse_events__delete_buffer(buffer);
@@ -754,9 +767,11 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 		return 0;
 	}
 
-	list_for_each_entry_safe(evsel, h, &list, node)
-		perf_evsel__delete(evsel);
-
+	/*
+	 * There are 2 users - builtin-record and builtin-test objects.
+	 * Both call perf_evlist__delete in case of error, so we dont
+	 * need to bother.
+	 */
 	fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
 	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
 	return ret;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 6d7c74b..ca069f8 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -76,8 +76,11 @@ 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);
+void parse_events_update_lists(struct list_head *list_event,
+			       struct list_head *list_all);
+void parse_events_error(struct list_head *list_all,
+			struct list_head *list_event,
+			int *idx, char const *msg);
 
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 3a53019..d9637da 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,6 +1,7 @@
 
 %name-prefix "parse_events_"
-%parse-param {struct list_head *list}
+%parse-param {struct list_head *list_all}
+%parse-param {struct list_head *list_event}
 %parse-param {int *idx}
 
 %{
@@ -56,10 +57,19 @@ events ',' event | event
 event:
 event_def PE_MODIFIER_EVENT
 {
-	ABORT_ON(parse_events_modifier(list, $2));
+	/*
+	 * Apply modifier on all events added by single event definition
+	 * (there could be more events added for multiple tracepoint
+	 * definitions via '*?'.
+	 */
+	ABORT_ON(parse_events_modifier(list_event, $2));
+	parse_events_update_lists(list_event, list_all);
 }
 |
 event_def
+{
+	parse_events_update_lists(list_event, list_all);
+}
 
 event_def: event_pmu |
 	   event_legacy_symbol |
@@ -72,7 +82,7 @@ event_def: event_pmu |
 event_pmu:
 PE_NAME '/' event_config '/'
 {
-	ABORT_ON(parse_events_add_pmu(list, idx, $1, $3));
+	ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
 	parse_events__free_terms($3);
 }
 
@@ -82,7 +92,7 @@ PE_VALUE_SYM '/' event_config '/'
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(list, idx, type, config, $3));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
 	parse_events__free_terms($3);
 }
 |
@@ -91,52 +101,52 @@ 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));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
 }
 
 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));
+	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
-	ABORT_ON(parse_events_add_cache(list, idx, $1, $3, NULL));
+	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
 }
 |
 PE_NAME_CACHE_TYPE
 {
-	ABORT_ON(parse_events_add_cache(list, idx, $1, NULL, NULL));
+	ABORT_ON(parse_events_add_cache(list_event, 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));
+	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
 }
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
-	ABORT_ON(parse_events_add_breakpoint(list, idx, (void *) $2, NULL));
+	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
 }
 
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
-	ABORT_ON(parse_events_add_tracepoint(list, idx, $1, $3));
+	ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
 }
 
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, $1, $3, NULL));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
 }
 
 event_legacy_raw:
 PE_RAW
 {
-	ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1, NULL));
+	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
 }
 
 event_config:
@@ -211,7 +221,9 @@ sep_slash_dc: '/' | ':' |
 
 %%
 
-void parse_events_error(struct list_head *list __used, int *idx __used,
+void parse_events_error(struct list_head *list_all __used,
+			struct list_head *list_event __used,
+			int *idx __used,
 			char const *msg __used)
 {
 }

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

* Re: [PATCH 3/3] perf, tool: Add new event group management
  2012-03-20 18:44   ` Peter Zijlstra
                       ` (2 preceding siblings ...)
  2012-03-21 10:42     ` Jiri Olsa
@ 2012-04-10 13:19     ` Jiri Olsa
  3 siblings, 0 replies; 28+ messages in thread
From: Jiri Olsa @ 2012-04-10 13:19 UTC (permalink / raw)
  To: Peter Zijlstra, Thomas Gleixner
  Cc: acme, mingo, paulus, cjashfor, fweisbec, linux-kernel

On Tue, Mar 20, 2012 at 07:44:41PM +0100, Peter Zijlstra wrote:
> On Tue, 2012-03-20 at 19:15 +0100, Jiri Olsa wrote:
> > 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 
> 
> I can't help but dislike the --group/--group parsed thing...
> 
> How about something like:
> 
>   event_group = "{", events, "}" , [ ":", event_group_mod ]
> 
> Such that you can write things like:
> 
>   perf record -e "{cpu-clock,cache-misses,cache-references}"
> 
>   perf stat -e "{cpu-clock,cycles},{cpu-clock,cache-misses,cache-references}"
>   perf stat -e "{cpu-clock,cycles}" -e "{cpu-clock,cache-misses,cache-references}"
> 
> I'm not sure what the current behaviour of --group is, if you create a
> group like this, do they all sample?
> 
> If so, we need some option like:
> 
>   perf record -e "{cpu-clock,cache-misses,cache-references}:1"
> 
> to mean, only sample on cpu-clock but use PERF_SAMPLE_READ and
> PERF_FORMAT_GROUP to read all siblings on every cpu-clock sample.
hi,

I'm looking on how to present this data in perf and it seems we need
to reset all siblings once we read/store them (in kernel) to the leader
sample.

My current thinking is to store siblings' sum values for each
hists entry of the sample (perf report count unit) .. and display
them in similar way we display callchains: for each hists entry
display the sum value for each sibling.

Could you provide more of your world examples? Your expectations about
presenting this..

Maybe we want to make the reset optional, and do some do some other
math with siblings' values..?

Thoughts? ;)

thanks,
jirka

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

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

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-20 18:15 [RFC 0/3] perf tool: Add new event group management Jiri Olsa
2012-03-20 18:15 ` [PATCH 1/3] perf, tool: Fix various casting issues for 32 bits Jiri Olsa
2012-03-23  8:29   ` [tip:perf/urgent] perf tools: " tip-bot for Jiri Olsa
2012-03-20 18:15 ` [PATCH 2/3] perf, tool: Fix modifier to be applied on correct events Jiri Olsa
2012-03-23  8:30   ` [tip:perf/urgent] perf tools: " tip-bot for Jiri Olsa
2012-03-20 18:15 ` [PATCH 3/3] perf, tool: Add new event group management Jiri Olsa
2012-03-20 18:44   ` Peter Zijlstra
2012-03-20 20:46     ` Ingo Molnar
2012-03-20 22:18       ` Arnaldo Carvalho de Melo
2012-03-21  9:15       ` Peter Zijlstra
2012-03-21  9:52         ` Ingo Molnar
2012-03-21 11:54           ` Peter Zijlstra
2012-03-21 12:15             ` Ingo Molnar
2012-03-21 15:13               ` Arnaldo Carvalho de Melo
2012-03-22  7:56                 ` Ingo Molnar
2012-03-22 12:41                   ` Arnaldo Carvalho de Melo
2012-03-22 13:54                     ` Ingo Molnar
2012-03-22 14:07                       ` Jiri Olsa
2012-03-20 22:36     ` Jiri Olsa
2012-03-21 11:54       ` Peter Zijlstra
2012-03-21 10:42     ` Jiri Olsa
2012-03-21 15:11       ` Arnaldo Carvalho de Melo
2012-03-21 22:27         ` Jiri Olsa
2012-03-22 12:40           ` Arnaldo Carvalho de Melo
2012-04-10 13:19     ` Jiri Olsa
2012-03-20 20:08   ` Arnaldo Carvalho de Melo
2012-03-20 22:16     ` Jiri Olsa
2012-03-21  2:12   ` Namhyung Kim

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