perf intel-pt: Better 7-byte timestamp wraparound logic
[linux-2.6-microblaze.git] / tools / perf / util / parse-events.c
index c0c0fab..4dad142 100644 (file)
@@ -37,6 +37,8 @@
 #include "util/evsel_config.h"
 #include "util/event.h"
 #include "util/pfm.h"
+#include "util/parse-events-hybrid.h"
+#include "util/pmu-hybrid.h"
 #include "perf.h"
 
 #define MAX_NAME_LEN 100
@@ -47,6 +49,9 @@ extern int parse_events_debug;
 int parse_events_parse(void *parse_state, void *scanner);
 static int get_config_terms(struct list_head *head_config,
                            struct list_head *head_terms __maybe_unused);
+static int parse_events__with_hybrid_pmu(struct parse_events_state *parse_state,
+                                        const char *str, char *pmu_name,
+                                        struct list_head *list);
 
 static struct perf_pmu_event_symbol *perf_pmu_events_list;
 /*
@@ -452,14 +457,16 @@ static int config_attr(struct perf_event_attr *attr,
 int parse_events_add_cache(struct list_head *list, int *idx,
                           char *type, char *op_result1, char *op_result2,
                           struct parse_events_error *err,
-                          struct list_head *head_config)
+                          struct list_head *head_config,
+                          struct parse_events_state *parse_state)
 {
        struct perf_event_attr attr;
        LIST_HEAD(config_terms);
        char name[MAX_NAME_LEN], *config_name;
        int cache_type = -1, cache_op = -1, cache_result = -1;
        char *op_result[2] = { op_result1, op_result2 };
-       int i, n;
+       int i, n, ret;
+       bool hybrid;
 
        /*
         * No fallback - if we cannot get a clear cache type
@@ -519,6 +526,13 @@ int parse_events_add_cache(struct list_head *list, int *idx,
                if (get_config_terms(head_config, &config_terms))
                        return -ENOMEM;
        }
+
+       ret = parse_events__add_cache_hybrid(list, idx, &attr,
+                                            config_name ? : name, &config_terms,
+                                            &hybrid, parse_state);
+       if (hybrid)
+               return ret;
+
        return add_event(list, idx, &attr, config_name ? : name, &config_terms);
 }
 
@@ -846,9 +860,9 @@ split_bpf_config_terms(struct list_head *evt_head_config,
        struct parse_events_term *term, *temp;
 
        /*
-        * Currectly, all possible user config term
+        * Currently, all possible user config term
         * belong to bpf object. parse_events__is_hardcoded_term()
-        * happends to be a good flag.
+        * happens to be a good flag.
         *
         * See parse_events_config_bpf() and
         * config_term_tracepoint().
@@ -898,7 +912,7 @@ int parse_events_load_bpf(struct parse_events_state *parse_state,
 
        /*
         * Caller doesn't know anything about obj_head_config,
-        * so combine them together again before returnning.
+        * so combine them together again before returning.
         */
        if (head_config)
                list_splice_tail(&obj_head_config, head_config);
@@ -1185,10 +1199,10 @@ do {                                                                       \
        }
 
        /*
-        * Check term availbility after basic checking so
+        * Check term availability after basic checking so
         * PARSE_EVENTS__TERM_TYPE_USER can be found and filtered.
         *
-        * If check availbility at the entry of this function,
+        * If check availability at the entry of this function,
         * user will see "'<sysfs term>' is not usable in 'perf stat'"
         * if an invalid config term is provided for legacy events
         * (for example, instructions/badterm/...), which is confusing.
@@ -1419,6 +1433,8 @@ int parse_events_add_numeric(struct parse_events_state *parse_state,
 {
        struct perf_event_attr attr;
        LIST_HEAD(config_terms);
+       bool hybrid;
+       int ret;
 
        memset(&attr, 0, sizeof(attr));
        attr.type = type;
@@ -1433,6 +1449,12 @@ int parse_events_add_numeric(struct parse_events_state *parse_state,
                        return -ENOMEM;
        }
 
+       ret = parse_events__add_numeric_hybrid(parse_state, list, &attr,
+                                              get_config_name(head_config),
+                                              &config_terms, &hybrid);
+       if (hybrid)
+               return ret;
+
        return add_event(list, &parse_state->idx, &attr,
                         get_config_name(head_config), &config_terms);
 }
@@ -1456,6 +1478,33 @@ static bool config_term_percore(struct list_head *config_terms)
        return false;
 }
 
+static int parse_events__inside_hybrid_pmu(struct parse_events_state *parse_state,
+                                          struct list_head *list, char *name,
+                                          struct list_head *head_config)
+{
+       struct parse_events_term *term;
+       int ret = -1;
+
+       if (parse_state->fake_pmu || !head_config || list_empty(head_config) ||
+           !perf_pmu__is_hybrid(name)) {
+               return -1;
+       }
+
+       /*
+        * More than one term in list.
+        */
+       if (head_config->next && head_config->next->next != head_config)
+               return -1;
+
+       term = list_first_entry(head_config, struct parse_events_term, list);
+       if (term && term->config && strcmp(term->config, "event")) {
+               ret = parse_events__with_hybrid_pmu(parse_state, term->config,
+                                                   name, list);
+       }
+
+       return ret;
+}
+
 int parse_events_add_pmu(struct parse_events_state *parse_state,
                         struct list_head *list, char *name,
                         struct list_head *head_config,
@@ -1549,6 +1598,11 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
        if (pmu->default_config && get_config_chgs(pmu, head_config, &config_terms))
                return -ENOMEM;
 
+       if (!parse_events__inside_hybrid_pmu(parse_state, list, name,
+                                            head_config)) {
+               return 0;
+       }
+
        if (!parse_state->fake_pmu && perf_pmu__config(pmu, &attr, head_config, parse_state->error)) {
                struct evsel_config_term *pos, *tmp;
 
@@ -1567,6 +1621,9 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
        if (!evsel)
                return -ENOMEM;
 
+       if (evsel->name)
+               evsel->use_config_name = true;
+
        evsel->pmu_name = name ? strdup(name) : NULL;
        evsel->use_uncore_alias = use_uncore_alias;
        evsel->percore = config_term_percore(&evsel->config_terms);
@@ -1804,6 +1861,7 @@ struct event_modifier {
        int pinned;
        int weak;
        int exclusive;
+       int bpf_counter;
 };
 
 static int get_event_modifier(struct event_modifier *mod, char *str,
@@ -1824,6 +1882,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
        int exclude = eu | ek | eh;
        int exclude_GH = evsel ? evsel->exclude_GH : 0;
        int weak = 0;
+       int bpf_counter = 0;
 
        memset(mod, 0, sizeof(*mod));
 
@@ -1867,6 +1926,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
                        exclusive = 1;
                } else if (*str == 'W') {
                        weak = 1;
+               } else if (*str == 'b') {
+                       bpf_counter = 1;
                } else
                        break;
 
@@ -1898,6 +1959,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
        mod->sample_read = sample_read;
        mod->pinned = pinned;
        mod->weak = weak;
+       mod->bpf_counter = bpf_counter;
        mod->exclusive = exclusive;
 
        return 0;
@@ -1912,7 +1974,7 @@ static int check_modifier(char *str)
        char *p = str;
 
        /* The sizeof includes 0 byte as well. */
-       if (strlen(str) > (sizeof("ukhGHpppPSDIWe") - 1))
+       if (strlen(str) > (sizeof("ukhGHpppPSDIWeb") - 1))
                return -1;
 
        while (*p) {
@@ -1953,6 +2015,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
                evsel->sample_read         = mod.sample_read;
                evsel->precise_max         = mod.precise_max;
                evsel->weak_group          = mod.weak;
+               evsel->bpf_counter         = mod.bpf_counter;
 
                if (evsel__is_group_leader(evsel)) {
                        evsel->core.attr.pinned = mod.pinned;
@@ -2162,6 +2225,33 @@ int parse_events_terms(struct list_head *terms, const char *str)
        return ret;
 }
 
+static int parse_events__with_hybrid_pmu(struct parse_events_state *parse_state,
+                                        const char *str, char *pmu_name,
+                                        struct list_head *list)
+{
+       struct parse_events_state ps = {
+               .list            = LIST_HEAD_INIT(ps.list),
+               .stoken          = PE_START_EVENTS,
+               .hybrid_pmu_name = pmu_name,
+               .idx             = parse_state->idx,
+       };
+       int ret;
+
+       ret = parse_events__scanner(str, &ps);
+       perf_pmu__parse_cleanup();
+
+       if (!ret) {
+               if (!list_empty(&ps.list)) {
+                       list_splice(&ps.list, list);
+                       parse_state->idx = ps.idx;
+                       return 0;
+               } else
+                       return -1;
+       }
+
+       return ret;
+}
+
 int __parse_events(struct evlist *evlist, const char *str,
                   struct parse_events_error *err, struct perf_pmu *fake_pmu)
 {
@@ -3185,3 +3275,12 @@ char *parse_events_formats_error_string(char *additional_terms)
 fail:
        return NULL;
 }
+
+struct evsel *parse_events__add_event_hybrid(struct list_head *list, int *idx,
+                                            struct perf_event_attr *attr,
+                                            char *name, struct perf_pmu *pmu,
+                                            struct list_head *config_terms)
+{
+       return __add_event(list, idx, attr, true, name, pmu,
+                          config_terms, false, NULL);
+}