perf tools: Use allocated list for each parsed event
[deliverable/linux.git] / tools / perf / util / parse-events.c
index 5b3a0ef4e2321523563c9da1e4c0449e3be4c013..4025e18765c40e6a9e99e7e5b9924b76616191ad 100644 (file)
@@ -23,8 +23,10 @@ struct event_symbol {
        const char      *alias;
 };
 
-int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
-                      int *idx);
+#ifdef PARSER_DEBUG
+extern int parse_events_debug;
+#endif
+int parse_events_parse(struct list_head *list, int *idx);
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -355,20 +357,30 @@ const char *__event_name(int type, u64 config)
        return "unknown";
 }
 
-static int add_event(struct list_head *list, int *idx,
+static int add_event(struct list_head **_list, int *idx,
                     struct perf_event_attr *attr, char *name)
 {
        struct perf_evsel *evsel;
+       struct list_head *list = *_list;
+
+       if (!list) {
+               list = malloc(sizeof(*list));
+               if (!list)
+                       return -ENOMEM;
+               INIT_LIST_HEAD(list);
+       }
 
        event_attr_init(attr);
 
        evsel = perf_evsel__new(attr, (*idx)++);
-       if (!evsel)
+       if (!evsel) {
+               free(list);
                return -ENOMEM;
-
-       list_add_tail(&evsel->node, list);
+       }
 
        evsel->name = strdup(name);
+       list_add_tail(&evsel->node, list);
+       *_list = list;
        return 0;
 }
 
@@ -390,7 +402,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
        return -1;
 }
 
-int parse_events_add_cache(struct list_head *list, int *idx,
+int parse_events_add_cache(struct list_head **list, int *idx,
                           char *type, char *op_result1, char *op_result2)
 {
        struct perf_event_attr attr;
@@ -451,7 +463,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
        return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint(struct list_head *list, int *idx,
+static int add_tracepoint(struct list_head **list, int *idx,
                          char *sys_name, char *evt_name)
 {
        struct perf_event_attr attr;
@@ -488,7 +500,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
        return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint_multi(struct list_head *list, int *idx,
+static int add_tracepoint_multi(struct list_head **list, int *idx,
                                char *sys_name, char *evt_name)
 {
        char evt_path[MAXPATHLEN];
@@ -519,7 +531,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,
        return ret;
 }
 
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
                                char *sys, char *event)
 {
        int ret;
@@ -563,7 +575,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
        return 0;
 }
 
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
                                void *ptr, char *type)
 {
        struct perf_event_attr attr;
@@ -593,17 +605,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
 static int config_term(struct perf_event_attr *attr,
                       struct parse_events__term *term)
 {
-       switch (term->type) {
+#define CHECK_TYPE_VAL(type)                                   \
+do {                                                           \
+       if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \
+               return -EINVAL;                                 \
+} while (0)
+
+       switch (term->type_term) {
        case PARSE_EVENTS__TERM_TYPE_CONFIG:
+               CHECK_TYPE_VAL(NUM);
                attr->config = term->val.num;
                break;
        case PARSE_EVENTS__TERM_TYPE_CONFIG1:
+               CHECK_TYPE_VAL(NUM);
                attr->config1 = term->val.num;
                break;
        case PARSE_EVENTS__TERM_TYPE_CONFIG2:
+               CHECK_TYPE_VAL(NUM);
                attr->config2 = term->val.num;
                break;
        case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
+               CHECK_TYPE_VAL(NUM);
                attr->sample_period = term->val.num;
                break;
        case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
@@ -615,7 +637,9 @@ static int config_term(struct perf_event_attr *attr,
        default:
                return -EINVAL;
        }
+
        return 0;
+#undef CHECK_TYPE_VAL
 }
 
 static int config_attr(struct perf_event_attr *attr,
@@ -630,7 +654,7 @@ static int config_attr(struct perf_event_attr *attr,
        return 0;
 }
 
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
                             unsigned long type, unsigned long config,
                             struct list_head *head_config)
 {
@@ -648,7 +672,7 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
                         (char *) __event_name(type, config));
 }
 
-int parse_events_add_pmu(struct list_head *list, int *idx,
+int parse_events_add_pmu(struct list_head **list, int *idx,
                         char *name, struct list_head *head_config)
 {
        struct perf_event_attr attr;
@@ -681,7 +705,7 @@ void parse_events_update_lists(struct list_head *list_event,
         * list, for next event definition.
         */
        list_splice_tail(list_event, list_all);
-       INIT_LIST_HEAD(list_event);
+       free(list_event);
 }
 
 int parse_events_modifier(struct list_head *list, char *str)
@@ -756,7 +780,10 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 
        buffer = parse_events__scan_string(str);
 
-       ret = parse_events_parse(&list, &list_tmp, &idx);
+#ifdef PARSER_DEBUG
+       parse_events_debug = 1;
+#endif
+       ret = parse_events_parse(&list, &idx);
 
        parse_events__flush_buffer(buffer);
        parse_events__delete_buffer(buffer);
@@ -1015,11 +1042,12 @@ void print_events(const char *event_glob)
 
 int parse_events__is_hardcoded_term(struct parse_events__term *term)
 {
-       return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
+       return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 }
 
-int parse_events__new_term(struct parse_events__term **_term, int type,
-                          char *config, char *str, long num)
+static int new_term(struct parse_events__term **_term, int type_val,
+                   int type_term, char *config,
+                   char *str, long num)
 {
        struct parse_events__term *term;
 
@@ -1028,15 +1056,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
                return -ENOMEM;
 
        INIT_LIST_HEAD(&term->list);
-       term->type = type;
+       term->type_val  = type_val;
+       term->type_term = type_term;
        term->config = config;
 
-       switch (type) {
-       case PARSE_EVENTS__TERM_TYPE_CONFIG:
-       case PARSE_EVENTS__TERM_TYPE_CONFIG1:
-       case PARSE_EVENTS__TERM_TYPE_CONFIG2:
-       case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-       case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+       switch (type_val) {
        case PARSE_EVENTS__TERM_TYPE_NUM:
                term->val.num = num;
                break;
@@ -1051,6 +1075,20 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
        return 0;
 }
 
+int parse_events__term_num(struct parse_events__term **term,
+                          int type_term, char *config, long num)
+{
+       return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
+                       config, NULL, num);
+}
+
+int parse_events__term_str(struct parse_events__term **term,
+                          int type_term, char *config, char *str)
+{
+       return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
+                       config, str, 0);
+}
+
 void parse_events__free_terms(struct list_head *terms)
 {
        struct parse_events__term *term, *h;
This page took 0.036769 seconds and 5 git commands to generate.