Adding parsing support for 'on' and 'off' terms within the
event syntax. We can now specify on/off terms like:

  -e 'cycles,irq_entry/on=cycles/,irq_exit/off=cycles/'

Only string value is accepted for both terms. The name
will be used in a search for toggled event.

Signed-off-by: Jiri Olsa <jo...@redhat.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Corey Ashford <cjash...@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweis...@gmail.com>
Cc: Ingo Molnar <mi...@elte.hu>
Cc: Paul Mackerras <pau...@samba.org>
Cc: Peter Zijlstra <a.p.zijls...@chello.nl>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
---
 tools/perf/util/evsel.c        |  1 +
 tools/perf/util/evsel.h        |  3 ++
 tools/perf/util/parse-events.c | 69 +++++++++++++++++++++++++++++++++++-------
 tools/perf/util/parse-events.h |  5 ++-
 tools/perf/util/parse-events.l |  2 ++
 tools/perf/util/parse-events.y |  6 ++--
 6 files changed, 71 insertions(+), 15 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 95590fe..3ed7947 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -820,6 +820,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)
        free(evsel->group_name);
        if (evsel->tp_format)
                pevent_free_format(evsel->tp_format);
+       free(evsel->toggle_name);
        free(evsel->name);
        free(evsel);
 }
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 4a7bdc7..e70415b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -90,6 +90,9 @@ struct perf_evsel {
        int                     sample_read;
        struct perf_evsel       *leader;
        char                    *group_name;
+       /* toggle event config */
+       char                    toggle_flag;
+       char                    *toggle_name;
 };
 
 #define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 899c59e..4e8243f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -267,7 +267,42 @@ const char *event_type(int type)
        return "unknown";
 }
 
+static int config_evsel_term(struct perf_evsel *evsel,
+                            struct parse_events_term *term)
+{
+       if (evsel->toggle_name)
+               return -EINVAL;
 
+       switch (term->type_term) {
+       case PARSE_EVENTS__TERM_TYPE_TOGGLE_ON:
+               evsel->toggle_flag = PERF_FLAG_TOGGLE_ON;
+               break;
+       case PARSE_EVENTS__TERM_TYPE_TOGGLE_OFF:
+               evsel->toggle_flag = PERF_FLAG_TOGGLE_OFF;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       evsel->toggle_name = strdup(term->val.str);
+       return 0;
+}
+
+static int config_evsel(struct perf_evsel *evsel,
+                       struct list_head *head)
+{
+       struct parse_events_term *term;
+
+       list_for_each_entry(term, head, list) {
+               int ret;
+
+               ret = config_evsel_term(evsel, term);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
 
 static int __add_event(struct list_head *list, int *idx,
                       struct perf_event_attr *attr,
@@ -374,7 +409,8 @@ int parse_events_add_cache(struct list_head *list, int *idx,
 }
 
 static int add_tracepoint(struct list_head *list, int *idx,
-                         char *sys_name, char *evt_name)
+                         char *sys_name, char *evt_name,
+                         struct list_head *terms)
 {
        struct perf_evsel *evsel;
 
@@ -382,13 +418,20 @@ static int add_tracepoint(struct list_head *list, int 
*idx,
        if (!evsel)
                return -ENOMEM;
 
+       if (terms && config_evsel(evsel, terms)) {
+               perf_evsel__delete(evsel);
+               free(list);
+               return -EINVAL;
+       }
+
        list_add_tail(&evsel->node, list);
 
        return 0;
 }
 
 static int add_tracepoint_multi_event(struct list_head *list, int *idx,
-                                     char *sys_name, char *evt_name)
+                                     char *sys_name, char *evt_name,
+                                     struct list_head *terms)
 {
        char evt_path[MAXPATHLEN];
        struct dirent *evt_ent;
@@ -412,7 +455,8 @@ static int add_tracepoint_multi_event(struct list_head 
*list, int *idx,
                if (!strglobmatch(evt_ent->d_name, evt_name))
                        continue;
 
-               ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
+               ret = add_tracepoint(list, idx, sys_name,
+                                    evt_ent->d_name, terms);
        }
 
        closedir(evt_dir);
@@ -420,15 +464,17 @@ static int add_tracepoint_multi_event(struct list_head 
*list, int *idx,
 }
 
 static int add_tracepoint_event(struct list_head *list, int *idx,
-                               char *sys_name, char *evt_name)
+                               char *sys_name, char *evt_name,
+                               struct list_head *terms)
 {
        return strpbrk(evt_name, "*?") ?
-              add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
-              add_tracepoint(list, idx, sys_name, evt_name);
+              add_tracepoint_multi_event(list, idx, sys_name, evt_name, terms) 
:
+              add_tracepoint(list, idx, sys_name, evt_name, terms);
 }
 
 static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
-                                   char *sys_name, char *evt_name)
+                                   char *sys_name, char *evt_name,
+                                   struct list_head *terms)
 {
        struct dirent *events_ent;
        DIR *events_dir;
@@ -452,7 +498,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, 
int *idx,
                        continue;
 
                ret = add_tracepoint_event(list, idx, events_ent->d_name,
-                                          evt_name);
+                                          evt_name, terms);
        }
 
        closedir(events_dir);
@@ -460,7 +506,8 @@ static int add_tracepoint_multi_sys(struct list_head *list, 
int *idx,
 }
 
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
-                               char *sys, char *event)
+                               char *sys, char *event,
+                               struct list_head *terms)
 {
        int ret;
 
@@ -469,9 +516,9 @@ int parse_events_add_tracepoint(struct list_head *list, int 
*idx,
                return ret;
 
        if (strpbrk(sys, "*?"))
-               return add_tracepoint_multi_sys(list, idx, sys, event);
+               return add_tracepoint_multi_sys(list, idx, sys, event, terms);
        else
-               return add_tracepoint_event(list, idx, sys, event);
+               return add_tracepoint_event(list, idx, sys, event, terms);
 }
 
 static int
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index a9db24f..8bd5995 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -49,6 +49,8 @@ enum {
        PARSE_EVENTS__TERM_TYPE_NAME,
        PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
        PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
+       PARSE_EVENTS__TERM_TYPE_TOGGLE_ON,
+       PARSE_EVENTS__TERM_TYPE_TOGGLE_OFF,
 };
 
 struct parse_events_term {
@@ -86,7 +88,8 @@ int parse_events__modifier_event(struct list_head *list, char 
*str, bool add);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events_name(struct list_head *list, char *name);
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
-                               char *sys, char *event);
+                               char *sys, char *event,
+                               struct list_head *terms);
 int parse_events_add_numeric(struct list_head *list, int *idx,
                             u32 type, u64 config,
                             struct list_head *terms);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 560ca86..afcc0d0 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -171,6 +171,8 @@ config2                     { return term(yyscanner, 
PARSE_EVENTS__TERM_TYPE_CONFIG2); }
 name                   { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); 
}
 period                 { return term(yyscanner, 
PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
 branch_type            { return term(yyscanner, 
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+on                     { return term(yyscanner, 
PARSE_EVENTS__TERM_TYPE_TOGGLE_ON); }
+off                    { return term(yyscanner, 
PARSE_EVENTS__TERM_TYPE_TOGGLE_OFF); }
 ,                      { return ','; }
 "/"                    { BEGIN(INITIAL); return '/'; }
 {name_minus}           { return str(yyscanner, PE_NAME); }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index ca93b72..7692562 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -200,7 +200,7 @@ event_def: event_pmu |
           event_legacy_symbol |
           event_legacy_cache sep_dc |
           event_legacy_mem |
-          event_legacy_tracepoint sep_dc |
+          event_legacy_tracepoint |
           event_legacy_numeric sep_dc |
           event_legacy_raw sep_dc
 
@@ -305,13 +305,13 @@ PE_PREFIX_MEM PE_VALUE sep_dc
 }
 
 event_legacy_tracepoint:
-PE_NAME ':' PE_NAME
+PE_NAME ':' PE_NAME event_config_optional
 {
        struct parse_events_evlist *data = _data;
        struct list_head *list;
 
        ALLOC_LIST(list);
-       ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3));
+       ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3, $4));
        $$ = list;
 }
 
-- 
1.7.11.7

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

Reply via email to