perf metricgroup: Delay events string creation
[linux-2.6-microblaze.git] / tools / perf / util / metricgroup.c
index 926449a..6247c9c 100644 (file)
@@ -85,27 +85,30 @@ static void metricgroup__rblist_init(struct rblist *metric_events)
 
 struct egroup {
        struct list_head nd;
-       int idnum;
-       const char **ids;
+       struct expr_parse_ctx pctx;
        const char *metric_name;
        const char *metric_expr;
        const char *metric_unit;
+       int runtime;
+       bool has_constraint;
 };
 
 static struct evsel *find_evsel_group(struct evlist *perf_evlist,
-                                     const char **ids,
-                                     int idnum,
+                                     struct expr_parse_ctx *pctx,
                                      struct evsel **metric_events,
-                                     bool *evlist_used)
+                                     unsigned long *evlist_used)
 {
        struct evsel *ev;
-       int i = 0, j = 0;
        bool leader_found;
+       const size_t idnum = hashmap__size(&pctx->ids);
+       size_t i = 0;
+       int j = 0;
+       double *val_ptr;
 
        evlist__for_each_entry (perf_evlist, ev) {
-               if (evlist_used[j++])
+               if (test_bit(j++, evlist_used))
                        continue;
-               if (!strcmp(ev->name, ids[i])) {
+               if (hashmap__find(&pctx->ids, ev->name, (void **)&val_ptr)) {
                        if (!metric_events[i])
                                metric_events[i] = ev;
                        i++;
@@ -116,14 +119,6 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist,
                        i = 0;
                        memset(metric_events, 0,
                                sizeof(struct evsel *) * idnum);
-
-                       if (!strcmp(ev->name, ids[i])) {
-                               if (!metric_events[i])
-                                       metric_events[i] = ev;
-                               i++;
-                               if (i == idnum)
-                                       break;
-                       }
                }
        }
 
@@ -147,7 +142,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist,
                        j++;
                }
                ev = metric_events[i];
-               evlist_used[ev->idx] = true;
+               set_bit(ev->idx, evlist_used);
        }
 
        return metric_events[0];
@@ -163,49 +158,52 @@ static int metricgroup__setup_events(struct list_head *groups,
        int ret = 0;
        struct egroup *eg;
        struct evsel *evsel;
-       bool *evlist_used;
+       unsigned long *evlist_used;
 
-       evlist_used = calloc(perf_evlist->core.nr_entries, sizeof(bool));
-       if (!evlist_used) {
-               ret = -ENOMEM;
-               return ret;
-       }
+       evlist_used = bitmap_alloc(perf_evlist->core.nr_entries);
+       if (!evlist_used)
+               return -ENOMEM;
 
        list_for_each_entry (eg, groups, nd) {
                struct evsel **metric_events;
 
-               metric_events = calloc(sizeof(void *), eg->idnum + 1);
+               metric_events = calloc(sizeof(void *),
+                               hashmap__size(&eg->pctx.ids) + 1);
                if (!metric_events) {
                        ret = -ENOMEM;
                        break;
                }
-               evsel = find_evsel_group(perf_evlist, eg->ids, eg->idnum,
-                                        metric_events, evlist_used);
+               evsel = find_evsel_group(perf_evlist, &eg->pctx, metric_events,
+                                       evlist_used);
                if (!evsel) {
                        pr_debug("Cannot resolve %s: %s\n",
                                        eg->metric_name, eg->metric_expr);
+                       free(metric_events);
                        continue;
                }
-               for (i = 0; i < eg->idnum; i++)
+               for (i = 0; metric_events[i]; i++)
                        metric_events[i]->collect_stat = true;
                me = metricgroup__lookup(metric_events_list, evsel, true);
                if (!me) {
                        ret = -ENOMEM;
+                       free(metric_events);
                        break;
                }
                expr = malloc(sizeof(struct metric_expr));
                if (!expr) {
                        ret = -ENOMEM;
+                       free(metric_events);
                        break;
                }
                expr->metric_expr = eg->metric_expr;
                expr->metric_name = eg->metric_name;
                expr->metric_unit = eg->metric_unit;
                expr->metric_events = metric_events;
+               expr->runtime = eg->runtime;
                list_add(&expr->nd, &me->head);
        }
 
-       free(evlist_used);
+       bitmap_free(evlist_used);
 
        return ret;
 }
@@ -413,43 +411,44 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
 }
 
 static void metricgroup__add_metric_weak_group(struct strbuf *events,
-                                              const char **ids,
-                                              int idnum)
+                                              struct expr_parse_ctx *ctx)
 {
-       bool no_group = false;
-       int i;
+       struct hashmap_entry *cur;
+       size_t bkt;
+       bool no_group = true, has_duration = false;
 
-       for (i = 0; i < idnum; i++) {
-               pr_debug("found event %s\n", ids[i]);
+       hashmap__for_each_entry((&ctx->ids), cur, bkt) {
+               pr_debug("found event %s\n", (const char *)cur->key);
                /*
                 * Duration time maps to a software event and can make
                 * groups not count. Always use it outside a
                 * group.
                 */
-               if (!strcmp(ids[i], "duration_time")) {
-                       if (i > 0)
-                               strbuf_addf(events, "}:W,");
-                       strbuf_addf(events, "duration_time");
-                       no_group = true;
+               if (!strcmp(cur->key, "duration_time")) {
+                       has_duration = true;
                        continue;
                }
                strbuf_addf(events, "%s%s",
-                       i == 0 || no_group ? "{" : ",",
-                       ids[i]);
+                       no_group ? "{" : ",",
+                       (const char *)cur->key);
                no_group = false;
        }
-       if (!no_group)
+       if (!no_group) {
                strbuf_addf(events, "}:W");
+               if (has_duration)
+                       strbuf_addf(events, ",duration_time");
+       } else if (has_duration)
+               strbuf_addf(events, "duration_time");
 }
 
 static void metricgroup__add_metric_non_group(struct strbuf *events,
-                                             const char **ids,
-                                             int idnum)
+                                             struct expr_parse_ctx *ctx)
 {
-       int i;
+       struct hashmap_entry *cur;
+       size_t bkt;
 
-       for (i = 0; i < idnum; i++)
-               strbuf_addf(events, ",%s", ids[i]);
+       hashmap__for_each_entry((&ctx->ids), cur, bkt)
+               strbuf_addf(events, ",%s", (const char *)cur->key);
 }
 
 static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
@@ -485,12 +484,46 @@ static bool metricgroup__has_constraint(struct pmu_event *pe)
        return false;
 }
 
+int __weak arch_get_runtimeparam(void)
+{
+       return 1;
+}
+
+static int __metricgroup__add_metric(struct list_head *group_list,
+                                    struct pmu_event *pe, int runtime)
+{
+       struct egroup *eg;
+
+       eg = malloc(sizeof(*eg));
+       if (!eg)
+               return -ENOMEM;
+
+       expr__ctx_init(&eg->pctx);
+       eg->metric_name = pe->metric_name;
+       eg->metric_expr = pe->metric_expr;
+       eg->metric_unit = pe->unit;
+       eg->runtime = runtime;
+       eg->has_constraint = metricgroup__has_constraint(pe);
+
+       if (expr__find_other(pe->metric_expr, NULL, &eg->pctx, runtime) < 0) {
+               expr__ctx_clear(&eg->pctx);
+               free(eg);
+               return -EINVAL;
+       }
+
+       list_add_tail(&eg->nd, group_list);
+
+       return 0;
+}
+
 static int metricgroup__add_metric(const char *metric, struct strbuf *events,
                                   struct list_head *group_list)
 {
        struct pmu_events_map *map = perf_pmu__find_map(NULL);
        struct pmu_event *pe;
-       int i, ret = -EINVAL;
+       struct egroup *eg;
+       int i, ret;
+       bool has_match = false;
 
        if (!map)
                return 0;
@@ -498,44 +531,56 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events,
        for (i = 0; ; i++) {
                pe = &map->table[i];
 
-               if (!pe->name && !pe->metric_group && !pe->metric_name)
+               if (!pe->name && !pe->metric_group && !pe->metric_name) {
+                       /* End of pmu events. */
+                       if (!has_match)
+                               return -EINVAL;
                        break;
+               }
                if (!pe->metric_expr)
                        continue;
                if (match_metric(pe->metric_group, metric) ||
                    match_metric(pe->metric_name, metric)) {
-                       const char **ids;
-                       int idnum;
-                       struct egroup *eg;
-
+                       has_match = true;
                        pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
 
-                       if (expr__find_other(pe->metric_expr,
-                                            NULL, &ids, &idnum) < 0)
-                               continue;
-                       if (events->len > 0)
-                               strbuf_addf(events, ",");
-
-                       if (metricgroup__has_constraint(pe))
-                               metricgroup__add_metric_non_group(events, ids, idnum);
-                       else
-                               metricgroup__add_metric_weak_group(events, ids, idnum);
-
-                       eg = malloc(sizeof(struct egroup));
-                       if (!eg) {
-                               ret = -ENOMEM;
-                               break;
+                       if (!strstr(pe->metric_expr, "?")) {
+                               ret = __metricgroup__add_metric(group_list,
+                                                               pe, 1);
+                               if (ret)
+                                       return ret;
+                       } else {
+                               int j, count;
+
+                               count = arch_get_runtimeparam();
+
+                               /* This loop is added to create multiple
+                                * events depend on count value and add
+                                * those events to group_list.
+                                */
+
+                               for (j = 0; j < count; j++) {
+                                       ret = __metricgroup__add_metric(
+                                               group_list, pe, j);
+                                       if (ret)
+                                               return ret;
+                               }
                        }
-                       eg->ids = ids;
-                       eg->idnum = idnum;
-                       eg->metric_name = pe->metric_name;
-                       eg->metric_expr = pe->metric_expr;
-                       eg->metric_unit = pe->unit;
-                       list_add_tail(&eg->nd, group_list);
-                       ret = 0;
                }
        }
-       return ret;
+       list_for_each_entry(eg, group_list, nd) {
+               if (events->len > 0)
+                       strbuf_addf(events, ",");
+
+               if (eg->has_constraint) {
+                       metricgroup__add_metric_non_group(events,
+                                                         &eg->pctx);
+               } else {
+                       metricgroup__add_metric_weak_group(events,
+                                                          &eg->pctx);
+               }
+       }
+       return 0;
 }
 
 static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
@@ -571,12 +616,9 @@ static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
 static void metricgroup__free_egroups(struct list_head *group_list)
 {
        struct egroup *eg, *egtmp;
-       int i;
 
        list_for_each_entry_safe (eg, egtmp, group_list, nd) {
-               for (i = 0; i < eg->idnum; i++)
-                       zfree(&eg->ids[i]);
-               zfree(&eg->ids);
+               expr__ctx_clear(&eg->pctx);
                list_del_init(&eg->nd);
                free(eg);
        }