Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2017, Intel Corporation.
0004  */
0005 
0006 /* Manage metrics and groups of metrics from JSON files */
0007 
0008 #include "metricgroup.h"
0009 #include "debug.h"
0010 #include "evlist.h"
0011 #include "evsel.h"
0012 #include "strbuf.h"
0013 #include "pmu.h"
0014 #include "pmu-hybrid.h"
0015 #include "expr.h"
0016 #include "rblist.h"
0017 #include <string.h>
0018 #include <errno.h>
0019 #include "strlist.h"
0020 #include <assert.h>
0021 #include <linux/ctype.h>
0022 #include <linux/list_sort.h>
0023 #include <linux/string.h>
0024 #include <linux/zalloc.h>
0025 #include <subcmd/parse-options.h>
0026 #include <api/fs/fs.h>
0027 #include "util.h"
0028 #include <asm/bug.h>
0029 #include "cgroup.h"
0030 
0031 struct metric_event *metricgroup__lookup(struct rblist *metric_events,
0032                      struct evsel *evsel,
0033                      bool create)
0034 {
0035     struct rb_node *nd;
0036     struct metric_event me = {
0037         .evsel = evsel
0038     };
0039 
0040     if (!metric_events)
0041         return NULL;
0042 
0043     nd = rblist__find(metric_events, &me);
0044     if (nd)
0045         return container_of(nd, struct metric_event, nd);
0046     if (create) {
0047         rblist__add_node(metric_events, &me);
0048         nd = rblist__find(metric_events, &me);
0049         if (nd)
0050             return container_of(nd, struct metric_event, nd);
0051     }
0052     return NULL;
0053 }
0054 
0055 static int metric_event_cmp(struct rb_node *rb_node, const void *entry)
0056 {
0057     struct metric_event *a = container_of(rb_node,
0058                           struct metric_event,
0059                           nd);
0060     const struct metric_event *b = entry;
0061 
0062     if (a->evsel == b->evsel)
0063         return 0;
0064     if ((char *)a->evsel < (char *)b->evsel)
0065         return -1;
0066     return +1;
0067 }
0068 
0069 static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused,
0070                     const void *entry)
0071 {
0072     struct metric_event *me = malloc(sizeof(struct metric_event));
0073 
0074     if (!me)
0075         return NULL;
0076     memcpy(me, entry, sizeof(struct metric_event));
0077     me->evsel = ((struct metric_event *)entry)->evsel;
0078     INIT_LIST_HEAD(&me->head);
0079     return &me->nd;
0080 }
0081 
0082 static void metric_event_delete(struct rblist *rblist __maybe_unused,
0083                 struct rb_node *rb_node)
0084 {
0085     struct metric_event *me = container_of(rb_node, struct metric_event, nd);
0086     struct metric_expr *expr, *tmp;
0087 
0088     list_for_each_entry_safe(expr, tmp, &me->head, nd) {
0089         free((char *)expr->metric_name);
0090         free(expr->metric_refs);
0091         free(expr->metric_events);
0092         free(expr);
0093     }
0094 
0095     free(me);
0096 }
0097 
0098 static void metricgroup__rblist_init(struct rblist *metric_events)
0099 {
0100     rblist__init(metric_events);
0101     metric_events->node_cmp = metric_event_cmp;
0102     metric_events->node_new = metric_event_new;
0103     metric_events->node_delete = metric_event_delete;
0104 }
0105 
0106 void metricgroup__rblist_exit(struct rblist *metric_events)
0107 {
0108     rblist__exit(metric_events);
0109 }
0110 
0111 /*
0112  * A node in the list of referenced metrics. metric_expr
0113  * is held as a convenience to avoid a search through the
0114  * metric list.
0115  */
0116 struct metric_ref_node {
0117     const char *metric_name;
0118     const char *metric_expr;
0119     struct list_head list;
0120 };
0121 
0122 /**
0123  * The metric under construction. The data held here will be placed in a
0124  * metric_expr.
0125  */
0126 struct metric {
0127     struct list_head nd;
0128     /**
0129      * The expression parse context importantly holding the IDs contained
0130      * within the expression.
0131      */
0132     struct expr_parse_ctx *pctx;
0133     /** The name of the metric such as "IPC". */
0134     const char *metric_name;
0135     /** Modifier on the metric such as "u" or NULL for none. */
0136     const char *modifier;
0137     /** The expression to parse, for example, "instructions/cycles". */
0138     const char *metric_expr;
0139     /**
0140      * The "ScaleUnit" that scales and adds a unit to the metric during
0141      * output.
0142      */
0143     const char *metric_unit;
0144     /** Optional null terminated array of referenced metrics. */
0145     struct metric_ref *metric_refs;
0146     /**
0147      * Is there a constraint on the group of events? In which case the
0148      * events won't be grouped.
0149      */
0150     bool has_constraint;
0151     /**
0152      * Parsed events for the metric. Optional as events may be taken from a
0153      * different metric whose group contains all the IDs necessary for this
0154      * one.
0155      */
0156     struct evlist *evlist;
0157 };
0158 
0159 static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
0160 {
0161     static bool violate_nmi_constraint;
0162 
0163     if (!foot) {
0164         pr_warning("Splitting metric group %s into standalone metrics.\n", name);
0165         violate_nmi_constraint = true;
0166         return;
0167     }
0168 
0169     if (!violate_nmi_constraint)
0170         return;
0171 
0172     pr_warning("Try disabling the NMI watchdog to comply NO_NMI_WATCHDOG metric constraint:\n"
0173            "    echo 0 > /proc/sys/kernel/nmi_watchdog\n"
0174            "    perf stat ...\n"
0175            "    echo 1 > /proc/sys/kernel/nmi_watchdog\n");
0176 }
0177 
0178 static bool metricgroup__has_constraint(const struct pmu_event *pe)
0179 {
0180     if (!pe->metric_constraint)
0181         return false;
0182 
0183     if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") &&
0184         sysctl__nmi_watchdog_enabled()) {
0185         metricgroup___watchdog_constraint_hint(pe->metric_name, false);
0186         return true;
0187     }
0188 
0189     return false;
0190 }
0191 
0192 static struct metric *metric__new(const struct pmu_event *pe,
0193                   const char *modifier,
0194                   bool metric_no_group,
0195                   int runtime)
0196 {
0197     struct metric *m;
0198 
0199     m = zalloc(sizeof(*m));
0200     if (!m)
0201         return NULL;
0202 
0203     m->pctx = expr__ctx_new();
0204     if (!m->pctx) {
0205         free(m);
0206         return NULL;
0207     }
0208 
0209     m->metric_name = pe->metric_name;
0210     m->modifier = modifier ? strdup(modifier) : NULL;
0211     if (modifier && !m->modifier) {
0212         expr__ctx_free(m->pctx);
0213         free(m);
0214         return NULL;
0215     }
0216     m->metric_expr = pe->metric_expr;
0217     m->metric_unit = pe->unit;
0218     m->pctx->runtime = runtime;
0219     m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
0220     m->metric_refs = NULL;
0221     m->evlist = NULL;
0222 
0223     return m;
0224 }
0225 
0226 static void metric__free(struct metric *m)
0227 {
0228     free(m->metric_refs);
0229     expr__ctx_free(m->pctx);
0230     free((char *)m->modifier);
0231     evlist__delete(m->evlist);
0232     free(m);
0233 }
0234 
0235 static bool contains_metric_id(struct evsel **metric_events, int num_events,
0236                    const char *metric_id)
0237 {
0238     int i;
0239 
0240     for (i = 0; i < num_events; i++) {
0241         if (!strcmp(evsel__metric_id(metric_events[i]), metric_id))
0242             return true;
0243     }
0244     return false;
0245 }
0246 
0247 /**
0248  * setup_metric_events - Find a group of events in metric_evlist that correspond
0249  *                       to the IDs from a parsed metric expression.
0250  * @ids: the metric IDs to match.
0251  * @metric_evlist: the list of perf events.
0252  * @out_metric_events: holds the created metric events array.
0253  */
0254 static int setup_metric_events(struct hashmap *ids,
0255                    struct evlist *metric_evlist,
0256                    struct evsel ***out_metric_events)
0257 {
0258     struct evsel **metric_events;
0259     const char *metric_id;
0260     struct evsel *ev;
0261     size_t ids_size, matched_events, i;
0262 
0263     *out_metric_events = NULL;
0264     ids_size = hashmap__size(ids);
0265 
0266     metric_events = calloc(sizeof(void *), ids_size + 1);
0267     if (!metric_events)
0268         return -ENOMEM;
0269 
0270     matched_events = 0;
0271     evlist__for_each_entry(metric_evlist, ev) {
0272         struct expr_id_data *val_ptr;
0273 
0274         /*
0275          * Check for duplicate events with the same name. For
0276          * example, uncore_imc/cas_count_read/ will turn into 6
0277          * events per socket on skylakex. Only the first such
0278          * event is placed in metric_events.
0279          */
0280         metric_id = evsel__metric_id(ev);
0281         if (contains_metric_id(metric_events, matched_events, metric_id))
0282             continue;
0283         /*
0284          * Does this event belong to the parse context? For
0285          * combined or shared groups, this metric may not care
0286          * about this event.
0287          */
0288         if (hashmap__find(ids, metric_id, (void **)&val_ptr)) {
0289             metric_events[matched_events++] = ev;
0290 
0291             if (matched_events >= ids_size)
0292                 break;
0293         }
0294     }
0295     if (matched_events < ids_size) {
0296         free(metric_events);
0297         return -EINVAL;
0298     }
0299     for (i = 0; i < ids_size; i++) {
0300         ev = metric_events[i];
0301         ev->collect_stat = true;
0302 
0303         /*
0304          * The metric leader points to the identically named
0305          * event in metric_events.
0306          */
0307         ev->metric_leader = ev;
0308         /*
0309          * Mark two events with identical names in the same
0310          * group (or globally) as being in use as uncore events
0311          * may be duplicated for each pmu. Set the metric leader
0312          * of such events to be the event that appears in
0313          * metric_events.
0314          */
0315         metric_id = evsel__metric_id(ev);
0316         evlist__for_each_entry_continue(metric_evlist, ev) {
0317             if (!strcmp(evsel__metric_id(ev), metric_id))
0318                 ev->metric_leader = metric_events[i];
0319         }
0320     }
0321     *out_metric_events = metric_events;
0322     return 0;
0323 }
0324 
0325 static bool match_metric(const char *n, const char *list)
0326 {
0327     int len;
0328     char *m;
0329 
0330     if (!list)
0331         return false;
0332     if (!strcmp(list, "all"))
0333         return true;
0334     if (!n)
0335         return !strcasecmp(list, "No_group");
0336     len = strlen(list);
0337     m = strcasestr(n, list);
0338     if (!m)
0339         return false;
0340     if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
0341         (m[len] == 0 || m[len] == ';'))
0342         return true;
0343     return false;
0344 }
0345 
0346 static bool match_pe_metric(const struct pmu_event *pe, const char *metric)
0347 {
0348     return match_metric(pe->metric_group, metric) ||
0349            match_metric(pe->metric_name, metric);
0350 }
0351 
0352 struct mep {
0353     struct rb_node nd;
0354     const char *name;
0355     struct strlist *metrics;
0356 };
0357 
0358 static int mep_cmp(struct rb_node *rb_node, const void *entry)
0359 {
0360     struct mep *a = container_of(rb_node, struct mep, nd);
0361     struct mep *b = (struct mep *)entry;
0362 
0363     return strcmp(a->name, b->name);
0364 }
0365 
0366 static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
0367                     const void *entry)
0368 {
0369     struct mep *me = malloc(sizeof(struct mep));
0370 
0371     if (!me)
0372         return NULL;
0373     memcpy(me, entry, sizeof(struct mep));
0374     me->name = strdup(me->name);
0375     if (!me->name)
0376         goto out_me;
0377     me->metrics = strlist__new(NULL, NULL);
0378     if (!me->metrics)
0379         goto out_name;
0380     return &me->nd;
0381 out_name:
0382     zfree(&me->name);
0383 out_me:
0384     free(me);
0385     return NULL;
0386 }
0387 
0388 static struct mep *mep_lookup(struct rblist *groups, const char *name)
0389 {
0390     struct rb_node *nd;
0391     struct mep me = {
0392         .name = name
0393     };
0394     nd = rblist__find(groups, &me);
0395     if (nd)
0396         return container_of(nd, struct mep, nd);
0397     rblist__add_node(groups, &me);
0398     nd = rblist__find(groups, &me);
0399     if (nd)
0400         return container_of(nd, struct mep, nd);
0401     return NULL;
0402 }
0403 
0404 static void mep_delete(struct rblist *rl __maybe_unused,
0405                struct rb_node *nd)
0406 {
0407     struct mep *me = container_of(nd, struct mep, nd);
0408 
0409     strlist__delete(me->metrics);
0410     zfree(&me->name);
0411     free(me);
0412 }
0413 
0414 static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
0415 {
0416     struct str_node *sn;
0417     int n = 0;
0418 
0419     strlist__for_each_entry (sn, metrics) {
0420         if (raw)
0421             printf("%s%s", n > 0 ? " " : "", sn->s);
0422         else
0423             printf("  %s\n", sn->s);
0424         n++;
0425     }
0426     if (raw)
0427         putchar('\n');
0428 }
0429 
0430 static int metricgroup__print_pmu_event(const struct pmu_event *pe,
0431                     bool metricgroups, char *filter,
0432                     bool raw, bool details,
0433                     struct rblist *groups,
0434                     struct strlist *metriclist)
0435 {
0436     const char *g;
0437     char *omg, *mg;
0438 
0439     g = pe->metric_group;
0440     if (!g && pe->metric_name) {
0441         if (pe->name)
0442             return 0;
0443         g = "No_group";
0444     }
0445 
0446     if (!g)
0447         return 0;
0448 
0449     mg = strdup(g);
0450 
0451     if (!mg)
0452         return -ENOMEM;
0453     omg = mg;
0454     while ((g = strsep(&mg, ";")) != NULL) {
0455         struct mep *me;
0456         char *s;
0457 
0458         g = skip_spaces(g);
0459         if (*g == 0)
0460             g = "No_group";
0461         if (filter && !strstr(g, filter))
0462             continue;
0463         if (raw)
0464             s = (char *)pe->metric_name;
0465         else {
0466             if (asprintf(&s, "%s\n%*s%s]",
0467                      pe->metric_name, 8, "[", pe->desc) < 0)
0468                 return -1;
0469             if (details) {
0470                 if (asprintf(&s, "%s\n%*s%s]",
0471                          s, 8, "[", pe->metric_expr) < 0)
0472                     return -1;
0473             }
0474         }
0475 
0476         if (!s)
0477             continue;
0478 
0479         if (!metricgroups) {
0480             strlist__add(metriclist, s);
0481         } else {
0482             me = mep_lookup(groups, g);
0483             if (!me)
0484                 continue;
0485             strlist__add(me->metrics, s);
0486         }
0487 
0488         if (!raw)
0489             free(s);
0490     }
0491     free(omg);
0492 
0493     return 0;
0494 }
0495 
0496 struct metricgroup_print_sys_idata {
0497     struct strlist *metriclist;
0498     char *filter;
0499     struct rblist *groups;
0500     bool metricgroups;
0501     bool raw;
0502     bool details;
0503 };
0504 
0505 struct metricgroup_iter_data {
0506     pmu_event_iter_fn fn;
0507     void *data;
0508 };
0509 
0510 static int metricgroup__sys_event_iter(const struct pmu_event *pe,
0511                        const struct pmu_events_table *table,
0512                        void *data)
0513 {
0514     struct metricgroup_iter_data *d = data;
0515     struct perf_pmu *pmu = NULL;
0516 
0517     if (!pe->metric_expr || !pe->compat)
0518         return 0;
0519 
0520     while ((pmu = perf_pmu__scan(pmu))) {
0521 
0522         if (!pmu->id || strcmp(pmu->id, pe->compat))
0523             continue;
0524 
0525         return d->fn(pe, table, d->data);
0526     }
0527 
0528     return 0;
0529 }
0530 
0531 static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
0532                          const struct pmu_events_table *table __maybe_unused,
0533                          void *data)
0534 {
0535     struct metricgroup_print_sys_idata *d = data;
0536 
0537     return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw,
0538                      d->details, d->groups, d->metriclist);
0539 }
0540 
0541 struct metricgroup_print_data {
0542     const char *pmu_name;
0543     struct strlist *metriclist;
0544     char *filter;
0545     struct rblist *groups;
0546     bool metricgroups;
0547     bool raw;
0548     bool details;
0549 };
0550 
0551 static int metricgroup__print_callback(const struct pmu_event *pe,
0552                        const struct pmu_events_table *table __maybe_unused,
0553                        void *vdata)
0554 {
0555     struct metricgroup_print_data *data = vdata;
0556 
0557     if (!pe->metric_expr)
0558         return 0;
0559 
0560     if (data->pmu_name && perf_pmu__is_hybrid(pe->pmu) && strcmp(data->pmu_name, pe->pmu))
0561         return 0;
0562 
0563     return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter,
0564                         data->raw, data->details, data->groups,
0565                         data->metriclist);
0566 }
0567 
0568 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
0569             bool raw, bool details, const char *pmu_name)
0570 {
0571     struct rblist groups;
0572     struct rb_node *node, *next;
0573     struct strlist *metriclist = NULL;
0574     const struct pmu_events_table *table;
0575 
0576     if (!metricgroups) {
0577         metriclist = strlist__new(NULL, NULL);
0578         if (!metriclist)
0579             return;
0580     }
0581 
0582     rblist__init(&groups);
0583     groups.node_new = mep_new;
0584     groups.node_cmp = mep_cmp;
0585     groups.node_delete = mep_delete;
0586     table = pmu_events_table__find();
0587     if (table) {
0588         struct metricgroup_print_data data = {
0589             .pmu_name = pmu_name,
0590             .metriclist = metriclist,
0591             .metricgroups = metricgroups,
0592             .filter = filter,
0593             .raw = raw,
0594             .details = details,
0595             .groups = &groups,
0596         };
0597 
0598         pmu_events_table_for_each_event(table,
0599                         metricgroup__print_callback,
0600                         &data);
0601     }
0602     {
0603         struct metricgroup_iter_data data = {
0604             .fn = metricgroup__print_sys_event_iter,
0605             .data = (void *) &(struct metricgroup_print_sys_idata){
0606                 .metriclist = metriclist,
0607                 .metricgroups = metricgroups,
0608                 .filter = filter,
0609                 .raw = raw,
0610                 .details = details,
0611                 .groups = &groups,
0612             },
0613         };
0614 
0615         pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
0616     }
0617 
0618     if (!filter || !rblist__empty(&groups)) {
0619         if (metricgroups && !raw)
0620             printf("\nMetric Groups:\n\n");
0621         else if (metrics && !raw)
0622             printf("\nMetrics:\n\n");
0623     }
0624 
0625     for (node = rb_first_cached(&groups.entries); node; node = next) {
0626         struct mep *me = container_of(node, struct mep, nd);
0627 
0628         if (metricgroups)
0629             printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n");
0630         if (metrics)
0631             metricgroup__print_strlist(me->metrics, raw);
0632         next = rb_next(node);
0633         rblist__remove_node(&groups, node);
0634     }
0635     if (!metricgroups)
0636         metricgroup__print_strlist(metriclist, raw);
0637     strlist__delete(metriclist);
0638 }
0639 
0640 static const char *code_characters = ",-=@";
0641 
0642 static int encode_metric_id(struct strbuf *sb, const char *x)
0643 {
0644     char *c;
0645     int ret = 0;
0646 
0647     for (; *x; x++) {
0648         c = strchr(code_characters, *x);
0649         if (c) {
0650             ret = strbuf_addch(sb, '!');
0651             if (ret)
0652                 break;
0653 
0654             ret = strbuf_addch(sb, '0' + (c - code_characters));
0655             if (ret)
0656                 break;
0657         } else {
0658             ret = strbuf_addch(sb, *x);
0659             if (ret)
0660                 break;
0661         }
0662     }
0663     return ret;
0664 }
0665 
0666 static int decode_metric_id(struct strbuf *sb, const char *x)
0667 {
0668     const char *orig = x;
0669     size_t i;
0670     char c;
0671     int ret;
0672 
0673     for (; *x; x++) {
0674         c = *x;
0675         if (*x == '!') {
0676             x++;
0677             i = *x - '0';
0678             if (i > strlen(code_characters)) {
0679                 pr_err("Bad metric-id encoding in: '%s'", orig);
0680                 return -1;
0681             }
0682             c = code_characters[i];
0683         }
0684         ret = strbuf_addch(sb, c);
0685         if (ret)
0686             return ret;
0687     }
0688     return 0;
0689 }
0690 
0691 static int decode_all_metric_ids(struct evlist *perf_evlist, const char *modifier)
0692 {
0693     struct evsel *ev;
0694     struct strbuf sb = STRBUF_INIT;
0695     char *cur;
0696     int ret = 0;
0697 
0698     evlist__for_each_entry(perf_evlist, ev) {
0699         if (!ev->metric_id)
0700             continue;
0701 
0702         ret = strbuf_setlen(&sb, 0);
0703         if (ret)
0704             break;
0705 
0706         ret = decode_metric_id(&sb, ev->metric_id);
0707         if (ret)
0708             break;
0709 
0710         free((char *)ev->metric_id);
0711         ev->metric_id = strdup(sb.buf);
0712         if (!ev->metric_id) {
0713             ret = -ENOMEM;
0714             break;
0715         }
0716         /*
0717          * If the name is just the parsed event, use the metric-id to
0718          * give a more friendly display version.
0719          */
0720         if (strstr(ev->name, "metric-id=")) {
0721             bool has_slash = false;
0722 
0723             free(ev->name);
0724             for (cur = strchr(sb.buf, '@') ; cur; cur = strchr(++cur, '@')) {
0725                 *cur = '/';
0726                 has_slash = true;
0727             }
0728 
0729             if (modifier) {
0730                 if (!has_slash && !strchr(sb.buf, ':')) {
0731                     ret = strbuf_addch(&sb, ':');
0732                     if (ret)
0733                         break;
0734                 }
0735                 ret = strbuf_addstr(&sb, modifier);
0736                 if (ret)
0737                     break;
0738             }
0739             ev->name = strdup(sb.buf);
0740             if (!ev->name) {
0741                 ret = -ENOMEM;
0742                 break;
0743             }
0744         }
0745     }
0746     strbuf_release(&sb);
0747     return ret;
0748 }
0749 
0750 static int metricgroup__build_event_string(struct strbuf *events,
0751                        const struct expr_parse_ctx *ctx,
0752                        const char *modifier,
0753                        bool has_constraint)
0754 {
0755     struct hashmap_entry *cur;
0756     size_t bkt;
0757     bool no_group = true, has_tool_events = false;
0758     bool tool_events[PERF_TOOL_MAX] = {false};
0759     int ret = 0;
0760 
0761 #define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0)
0762 
0763     hashmap__for_each_entry(ctx->ids, cur, bkt) {
0764         const char *sep, *rsep, *id = cur->key;
0765         enum perf_tool_event ev;
0766 
0767         pr_debug("found event %s\n", id);
0768 
0769         /* Always move tool events outside of the group. */
0770         ev = perf_tool_event__from_str(id);
0771         if (ev != PERF_TOOL_NONE) {
0772             has_tool_events = true;
0773             tool_events[ev] = true;
0774             continue;
0775         }
0776         /* Separate events with commas and open the group if necessary. */
0777         if (no_group) {
0778             if (!has_constraint) {
0779                 ret = strbuf_addch(events, '{');
0780                 RETURN_IF_NON_ZERO(ret);
0781             }
0782 
0783             no_group = false;
0784         } else {
0785             ret = strbuf_addch(events, ',');
0786             RETURN_IF_NON_ZERO(ret);
0787         }
0788         /*
0789          * Encode the ID as an event string. Add a qualifier for
0790          * metric_id that is the original name except with characters
0791          * that parse-events can't parse replaced. For example,
0792          * 'msr@tsc@' gets added as msr/tsc,metric-id=msr!3tsc!3/
0793          */
0794         sep = strchr(id, '@');
0795         if (sep != NULL) {
0796             ret = strbuf_add(events, id, sep - id);
0797             RETURN_IF_NON_ZERO(ret);
0798             ret = strbuf_addch(events, '/');
0799             RETURN_IF_NON_ZERO(ret);
0800             rsep = strrchr(sep, '@');
0801             ret = strbuf_add(events, sep + 1, rsep - sep - 1);
0802             RETURN_IF_NON_ZERO(ret);
0803             ret = strbuf_addstr(events, ",metric-id=");
0804             RETURN_IF_NON_ZERO(ret);
0805             sep = rsep;
0806         } else {
0807             sep = strchr(id, ':');
0808             if (sep != NULL) {
0809                 ret = strbuf_add(events, id, sep - id);
0810                 RETURN_IF_NON_ZERO(ret);
0811             } else {
0812                 ret = strbuf_addstr(events, id);
0813                 RETURN_IF_NON_ZERO(ret);
0814             }
0815             ret = strbuf_addstr(events, "/metric-id=");
0816             RETURN_IF_NON_ZERO(ret);
0817         }
0818         ret = encode_metric_id(events, id);
0819         RETURN_IF_NON_ZERO(ret);
0820         ret = strbuf_addstr(events, "/");
0821         RETURN_IF_NON_ZERO(ret);
0822 
0823         if (sep != NULL) {
0824             ret = strbuf_addstr(events, sep + 1);
0825             RETURN_IF_NON_ZERO(ret);
0826         }
0827         if (modifier) {
0828             ret = strbuf_addstr(events, modifier);
0829             RETURN_IF_NON_ZERO(ret);
0830         }
0831     }
0832     if (!no_group && !has_constraint) {
0833         ret = strbuf_addf(events, "}:W");
0834         RETURN_IF_NON_ZERO(ret);
0835     }
0836     if (has_tool_events) {
0837         int i;
0838 
0839         perf_tool_event__for_each_event(i) {
0840             if (tool_events[i]) {
0841                 if (!no_group) {
0842                     ret = strbuf_addch(events, ',');
0843                     RETURN_IF_NON_ZERO(ret);
0844                 }
0845                 no_group = false;
0846                 ret = strbuf_addstr(events, perf_tool_event__to_str(i));
0847                 RETURN_IF_NON_ZERO(ret);
0848             }
0849         }
0850     }
0851 
0852     return ret;
0853 #undef RETURN_IF_NON_ZERO
0854 }
0855 
0856 int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused)
0857 {
0858     return 1;
0859 }
0860 
0861 /*
0862  * A singly linked list on the stack of the names of metrics being
0863  * processed. Used to identify recursion.
0864  */
0865 struct visited_metric {
0866     const char *name;
0867     const struct visited_metric *parent;
0868 };
0869 
0870 struct metricgroup_add_iter_data {
0871     struct list_head *metric_list;
0872     const char *metric_name;
0873     const char *modifier;
0874     int *ret;
0875     bool *has_match;
0876     bool metric_no_group;
0877     struct metric *root_metric;
0878     const struct visited_metric *visited;
0879     const struct pmu_events_table *table;
0880 };
0881 
0882 static bool metricgroup__find_metric(const char *metric,
0883                      const struct pmu_events_table *table,
0884                      struct pmu_event *pe);
0885 
0886 static int add_metric(struct list_head *metric_list,
0887               const struct pmu_event *pe,
0888               const char *modifier,
0889               bool metric_no_group,
0890               struct metric *root_metric,
0891               const struct visited_metric *visited,
0892               const struct pmu_events_table *table);
0893 
0894 /**
0895  * resolve_metric - Locate metrics within the root metric and recursively add
0896  *                    references to them.
0897  * @metric_list: The list the metric is added to.
0898  * @modifier: if non-null event modifiers like "u".
0899  * @metric_no_group: Should events written to events be grouped "{}" or
0900  *                   global. Grouping is the default but due to multiplexing the
0901  *                   user may override.
0902  * @root_metric: Metrics may reference other metrics to form a tree. In this
0903  *               case the root_metric holds all the IDs and a list of referenced
0904  *               metrics. When adding a root this argument is NULL.
0905  * @visited: A singly linked list of metric names being added that is used to
0906  *           detect recursion.
0907  * @table: The table that is searched for metrics, most commonly the table for the
0908  *       architecture perf is running upon.
0909  */
0910 static int resolve_metric(struct list_head *metric_list,
0911               const char *modifier,
0912               bool metric_no_group,
0913               struct metric *root_metric,
0914               const struct visited_metric *visited,
0915               const struct pmu_events_table *table)
0916 {
0917     struct hashmap_entry *cur;
0918     size_t bkt;
0919     struct to_resolve {
0920         /* The metric to resolve. */
0921         struct pmu_event pe;
0922         /*
0923          * The key in the IDs map, this may differ from in case,
0924          * etc. from pe->metric_name.
0925          */
0926         const char *key;
0927     } *pending = NULL;
0928     int i, ret = 0, pending_cnt = 0;
0929 
0930     /*
0931      * Iterate all the parsed IDs and if there's a matching metric and it to
0932      * the pending array.
0933      */
0934     hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
0935         struct pmu_event pe;
0936 
0937         if (metricgroup__find_metric(cur->key, table, &pe)) {
0938             pending = realloc(pending,
0939                     (pending_cnt + 1) * sizeof(struct to_resolve));
0940             if (!pending)
0941                 return -ENOMEM;
0942 
0943             memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
0944             pending[pending_cnt].key = cur->key;
0945             pending_cnt++;
0946         }
0947     }
0948 
0949     /* Remove the metric IDs from the context. */
0950     for (i = 0; i < pending_cnt; i++)
0951         expr__del_id(root_metric->pctx, pending[i].key);
0952 
0953     /*
0954      * Recursively add all the metrics, IDs are added to the root metric's
0955      * context.
0956      */
0957     for (i = 0; i < pending_cnt; i++) {
0958         ret = add_metric(metric_list, &pending[i].pe, modifier, metric_no_group,
0959                 root_metric, visited, table);
0960         if (ret)
0961             break;
0962     }
0963 
0964     free(pending);
0965     return ret;
0966 }
0967 
0968 /**
0969  * __add_metric - Add a metric to metric_list.
0970  * @metric_list: The list the metric is added to.
0971  * @pe: The pmu_event containing the metric to be added.
0972  * @modifier: if non-null event modifiers like "u".
0973  * @metric_no_group: Should events written to events be grouped "{}" or
0974  *                   global. Grouping is the default but due to multiplexing the
0975  *                   user may override.
0976  * @runtime: A special argument for the parser only known at runtime.
0977  * @root_metric: Metrics may reference other metrics to form a tree. In this
0978  *               case the root_metric holds all the IDs and a list of referenced
0979  *               metrics. When adding a root this argument is NULL.
0980  * @visited: A singly linked list of metric names being added that is used to
0981  *           detect recursion.
0982  * @table: The table that is searched for metrics, most commonly the table for the
0983  *       architecture perf is running upon.
0984  */
0985 static int __add_metric(struct list_head *metric_list,
0986             const struct pmu_event *pe,
0987             const char *modifier,
0988             bool metric_no_group,
0989             int runtime,
0990             struct metric *root_metric,
0991             const struct visited_metric *visited,
0992             const struct pmu_events_table *table)
0993 {
0994     const struct visited_metric *vm;
0995     int ret;
0996     bool is_root = !root_metric;
0997     struct visited_metric visited_node = {
0998         .name = pe->metric_name,
0999         .parent = visited,
1000     };
1001 
1002     for (vm = visited; vm; vm = vm->parent) {
1003         if (!strcmp(pe->metric_name, vm->name)) {
1004             pr_err("failed: recursion detected for %s\n", pe->metric_name);
1005             return -1;
1006         }
1007     }
1008 
1009     if (is_root) {
1010         /*
1011          * This metric is the root of a tree and may reference other
1012          * metrics that are added recursively.
1013          */
1014         root_metric = metric__new(pe, modifier, metric_no_group, runtime);
1015         if (!root_metric)
1016             return -ENOMEM;
1017 
1018     } else {
1019         int cnt = 0;
1020 
1021         /*
1022          * This metric was referenced in a metric higher in the
1023          * tree. Check if the same metric is already resolved in the
1024          * metric_refs list.
1025          */
1026         if (root_metric->metric_refs) {
1027             for (; root_metric->metric_refs[cnt].metric_name; cnt++) {
1028                 if (!strcmp(pe->metric_name,
1029                         root_metric->metric_refs[cnt].metric_name))
1030                     return 0;
1031             }
1032         }
1033 
1034         /* Create reference. Need space for the entry and the terminator. */
1035         root_metric->metric_refs = realloc(root_metric->metric_refs,
1036                         (cnt + 2) * sizeof(struct metric_ref));
1037         if (!root_metric->metric_refs)
1038             return -ENOMEM;
1039 
1040         /*
1041          * Intentionally passing just const char pointers,
1042          * from 'pe' object, so they never go away. We don't
1043          * need to change them, so there's no need to create
1044          * our own copy.
1045          */
1046         root_metric->metric_refs[cnt].metric_name = pe->metric_name;
1047         root_metric->metric_refs[cnt].metric_expr = pe->metric_expr;
1048 
1049         /* Null terminate array. */
1050         root_metric->metric_refs[cnt+1].metric_name = NULL;
1051         root_metric->metric_refs[cnt+1].metric_expr = NULL;
1052     }
1053 
1054     /*
1055      * For both the parent and referenced metrics, we parse
1056      * all the metric's IDs and add it to the root context.
1057      */
1058     if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) {
1059         /* Broken metric. */
1060         ret = -EINVAL;
1061     } else {
1062         /* Resolve referenced metrics. */
1063         ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
1064                      &visited_node, table);
1065     }
1066 
1067     if (ret) {
1068         if (is_root)
1069             metric__free(root_metric);
1070 
1071     } else if (is_root)
1072         list_add(&root_metric->nd, metric_list);
1073 
1074     return ret;
1075 }
1076 
1077 struct metricgroup__find_metric_data {
1078     const char *metric;
1079     struct pmu_event *pe;
1080 };
1081 
1082 static int metricgroup__find_metric_callback(const struct pmu_event *pe,
1083                          const struct pmu_events_table *table  __maybe_unused,
1084                          void *vdata)
1085 {
1086     struct metricgroup__find_metric_data *data = vdata;
1087 
1088     if (!match_metric(pe->metric_name, data->metric))
1089         return 0;
1090 
1091     memcpy(data->pe, pe, sizeof(*pe));
1092     return 1;
1093 }
1094 
1095 static bool metricgroup__find_metric(const char *metric,
1096                      const struct pmu_events_table *table,
1097                      struct pmu_event *pe)
1098 {
1099     struct metricgroup__find_metric_data data = {
1100         .metric = metric,
1101         .pe = pe,
1102     };
1103 
1104     return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
1105         ? true : false;
1106 }
1107 
1108 static int add_metric(struct list_head *metric_list,
1109               const struct pmu_event *pe,
1110               const char *modifier,
1111               bool metric_no_group,
1112               struct metric *root_metric,
1113               const struct visited_metric *visited,
1114               const struct pmu_events_table *table)
1115 {
1116     int ret = 0;
1117 
1118     pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
1119 
1120     if (!strstr(pe->metric_expr, "?")) {
1121         ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
1122                    root_metric, visited, table);
1123     } else {
1124         int j, count;
1125 
1126         count = arch_get_runtimeparam(pe);
1127 
1128         /* This loop is added to create multiple
1129          * events depend on count value and add
1130          * those events to metric_list.
1131          */
1132 
1133         for (j = 0; j < count && !ret; j++)
1134             ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
1135                     root_metric, visited, table);
1136     }
1137 
1138     return ret;
1139 }
1140 
1141 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
1142                         const struct pmu_events_table *table __maybe_unused,
1143                         void *data)
1144 {
1145     struct metricgroup_add_iter_data *d = data;
1146     int ret;
1147 
1148     if (!match_pe_metric(pe, d->metric_name))
1149         return 0;
1150 
1151     ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
1152              d->root_metric, d->visited, d->table);
1153     if (ret)
1154         goto out;
1155 
1156     *(d->has_match) = true;
1157 
1158 out:
1159     *(d->ret) = ret;
1160     return ret;
1161 }
1162 
1163 /**
1164  * metric_list_cmp - list_sort comparator that sorts metrics with more events to
1165  *                   the front. tool events are excluded from the count.
1166  */
1167 static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
1168                const struct list_head *r)
1169 {
1170     const struct metric *left = container_of(l, struct metric, nd);
1171     const struct metric *right = container_of(r, struct metric, nd);
1172     struct expr_id_data *data;
1173     int i, left_count, right_count;
1174 
1175     left_count = hashmap__size(left->pctx->ids);
1176     perf_tool_event__for_each_event(i) {
1177         if (!expr__get_id(left->pctx, perf_tool_event__to_str(i), &data))
1178             left_count--;
1179     }
1180 
1181     right_count = hashmap__size(right->pctx->ids);
1182     perf_tool_event__for_each_event(i) {
1183         if (!expr__get_id(right->pctx, perf_tool_event__to_str(i), &data))
1184             right_count--;
1185     }
1186 
1187     return right_count - left_count;
1188 }
1189 
1190 struct metricgroup__add_metric_data {
1191     struct list_head *list;
1192     const char *metric_name;
1193     const char *modifier;
1194     bool metric_no_group;
1195     bool has_match;
1196 };
1197 
1198 static int metricgroup__add_metric_callback(const struct pmu_event *pe,
1199                         const struct pmu_events_table *table,
1200                         void *vdata)
1201 {
1202     struct metricgroup__add_metric_data *data = vdata;
1203     int ret = 0;
1204 
1205     if (pe->metric_expr &&
1206         (match_metric(pe->metric_group, data->metric_name) ||
1207          match_metric(pe->metric_name, data->metric_name))) {
1208 
1209         data->has_match = true;
1210         ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
1211                  /*root_metric=*/NULL,
1212                  /*visited_metrics=*/NULL, table);
1213     }
1214     return ret;
1215 }
1216 
1217 /**
1218  * metricgroup__add_metric - Find and add a metric, or a metric group.
1219  * @metric_name: The name of the metric or metric group. For example, "IPC"
1220  *               could be the name of a metric and "TopDownL1" the name of a
1221  *               metric group.
1222  * @modifier: if non-null event modifiers like "u".
1223  * @metric_no_group: Should events written to events be grouped "{}" or
1224  *                   global. Grouping is the default but due to multiplexing the
1225  *                   user may override.
1226  * @metric_list: The list that the metric or metric group are added to.
1227  * @table: The table that is searched for metrics, most commonly the table for the
1228  *       architecture perf is running upon.
1229  */
1230 static int metricgroup__add_metric(const char *metric_name, const char *modifier,
1231                    bool metric_no_group,
1232                    struct list_head *metric_list,
1233                    const struct pmu_events_table *table)
1234 {
1235     LIST_HEAD(list);
1236     int ret;
1237     bool has_match = false;
1238 
1239     {
1240         struct metricgroup__add_metric_data data = {
1241             .list = &list,
1242             .metric_name = metric_name,
1243             .modifier = modifier,
1244             .metric_no_group = metric_no_group,
1245             .has_match = false,
1246         };
1247         /*
1248          * Iterate over all metrics seeing if metric matches either the
1249          * name or group. When it does add the metric to the list.
1250          */
1251         ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
1252                               &data);
1253         if (ret)
1254             goto out;
1255 
1256         has_match = data.has_match;
1257     }
1258     {
1259         struct metricgroup_iter_data data = {
1260             .fn = metricgroup__add_metric_sys_event_iter,
1261             .data = (void *) &(struct metricgroup_add_iter_data) {
1262                 .metric_list = &list,
1263                 .metric_name = metric_name,
1264                 .modifier = modifier,
1265                 .metric_no_group = metric_no_group,
1266                 .has_match = &has_match,
1267                 .ret = &ret,
1268                 .table = table,
1269             },
1270         };
1271 
1272         pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
1273     }
1274     /* End of pmu events. */
1275     if (!has_match)
1276         ret = -EINVAL;
1277 
1278 out:
1279     /*
1280      * add to metric_list so that they can be released
1281      * even if it's failed
1282      */
1283     list_splice(&list, metric_list);
1284     return ret;
1285 }
1286 
1287 /**
1288  * metricgroup__add_metric_list - Find and add metrics, or metric groups,
1289  *                                specified in a list.
1290  * @list: the list of metrics or metric groups. For example, "IPC,CPI,TopDownL1"
1291  *        would match the IPC and CPI metrics, and TopDownL1 would match all
1292  *        the metrics in the TopDownL1 group.
1293  * @metric_no_group: Should events written to events be grouped "{}" or
1294  *                   global. Grouping is the default but due to multiplexing the
1295  *                   user may override.
1296  * @metric_list: The list that metrics are added to.
1297  * @table: The table that is searched for metrics, most commonly the table for the
1298  *       architecture perf is running upon.
1299  */
1300 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
1301                     struct list_head *metric_list,
1302                     const struct pmu_events_table *table)
1303 {
1304     char *list_itr, *list_copy, *metric_name, *modifier;
1305     int ret, count = 0;
1306 
1307     list_copy = strdup(list);
1308     if (!list_copy)
1309         return -ENOMEM;
1310     list_itr = list_copy;
1311 
1312     while ((metric_name = strsep(&list_itr, ",")) != NULL) {
1313         modifier = strchr(metric_name, ':');
1314         if (modifier)
1315             *modifier++ = '\0';
1316 
1317         ret = metricgroup__add_metric(metric_name, modifier,
1318                           metric_no_group, metric_list,
1319                           table);
1320         if (ret == -EINVAL)
1321             pr_err("Cannot find metric or group `%s'\n", metric_name);
1322 
1323         if (ret)
1324             break;
1325 
1326         count++;
1327     }
1328     free(list_copy);
1329 
1330     if (!ret) {
1331         /*
1332          * Warn about nmi_watchdog if any parsed metrics had the
1333          * NO_NMI_WATCHDOG constraint.
1334          */
1335         metricgroup___watchdog_constraint_hint(NULL, true);
1336         /* No metrics. */
1337         if (count == 0)
1338             return -EINVAL;
1339     }
1340     return ret;
1341 }
1342 
1343 static void metricgroup__free_metrics(struct list_head *metric_list)
1344 {
1345     struct metric *m, *tmp;
1346 
1347     list_for_each_entry_safe (m, tmp, metric_list, nd) {
1348         list_del_init(&m->nd);
1349         metric__free(m);
1350     }
1351 }
1352 
1353 /**
1354  * find_tool_events - Search for the pressence of tool events in metric_list.
1355  * @metric_list: List to take metrics from.
1356  * @tool_events: Array of false values, indices corresponding to tool events set
1357  *               to true if tool event is found.
1358  */
1359 static void find_tool_events(const struct list_head *metric_list,
1360                  bool tool_events[PERF_TOOL_MAX])
1361 {
1362     struct metric *m;
1363 
1364     list_for_each_entry(m, metric_list, nd) {
1365         int i;
1366 
1367         perf_tool_event__for_each_event(i) {
1368             struct expr_id_data *data;
1369 
1370             if (!tool_events[i] &&
1371                 !expr__get_id(m->pctx, perf_tool_event__to_str(i), &data))
1372                 tool_events[i] = true;
1373         }
1374     }
1375 }
1376 
1377 /**
1378  * build_combined_expr_ctx - Make an expr_parse_ctx with all has_constraint
1379  *                           metric IDs, as the IDs are held in a set,
1380  *                           duplicates will be removed.
1381  * @metric_list: List to take metrics from.
1382  * @combined: Out argument for result.
1383  */
1384 static int build_combined_expr_ctx(const struct list_head *metric_list,
1385                    struct expr_parse_ctx **combined)
1386 {
1387     struct hashmap_entry *cur;
1388     size_t bkt;
1389     struct metric *m;
1390     char *dup;
1391     int ret;
1392 
1393     *combined = expr__ctx_new();
1394     if (!*combined)
1395         return -ENOMEM;
1396 
1397     list_for_each_entry(m, metric_list, nd) {
1398         if (m->has_constraint && !m->modifier) {
1399             hashmap__for_each_entry(m->pctx->ids, cur, bkt) {
1400                 dup = strdup(cur->key);
1401                 if (!dup) {
1402                     ret = -ENOMEM;
1403                     goto err_out;
1404                 }
1405                 ret = expr__add_id(*combined, dup);
1406                 if (ret)
1407                     goto err_out;
1408             }
1409         }
1410     }
1411     return 0;
1412 err_out:
1413     expr__ctx_free(*combined);
1414     *combined = NULL;
1415     return ret;
1416 }
1417 
1418 /**
1419  * parse_ids - Build the event string for the ids and parse them creating an
1420  *             evlist. The encoded metric_ids are decoded.
1421  * @metric_no_merge: is metric sharing explicitly disabled.
1422  * @fake_pmu: used when testing metrics not supported by the current CPU.
1423  * @ids: the event identifiers parsed from a metric.
1424  * @modifier: any modifiers added to the events.
1425  * @has_constraint: false if events should be placed in a weak group.
1426  * @tool_events: entries set true if the tool event of index could be present in
1427  *               the overall list of metrics.
1428  * @out_evlist: the created list of events.
1429  */
1430 static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu,
1431              struct expr_parse_ctx *ids, const char *modifier,
1432              bool has_constraint, const bool tool_events[PERF_TOOL_MAX],
1433              struct evlist **out_evlist)
1434 {
1435     struct parse_events_error parse_error;
1436     struct evlist *parsed_evlist;
1437     struct strbuf events = STRBUF_INIT;
1438     int ret;
1439 
1440     *out_evlist = NULL;
1441     if (!metric_no_merge || hashmap__size(ids->ids) == 0) {
1442         bool added_event = false;
1443         int i;
1444         /*
1445          * We may fail to share events between metrics because a tool
1446          * event isn't present in one metric. For example, a ratio of
1447          * cache misses doesn't need duration_time but the same events
1448          * may be used for a misses per second. Events without sharing
1449          * implies multiplexing, that is best avoided, so place
1450          * all tool events in every group.
1451          *
1452          * Also, there may be no ids/events in the expression parsing
1453          * context because of constant evaluation, e.g.:
1454          *    event1 if #smt_on else 0
1455          * Add a tool event to avoid a parse error on an empty string.
1456          */
1457         perf_tool_event__for_each_event(i) {
1458             if (tool_events[i]) {
1459                 char *tmp = strdup(perf_tool_event__to_str(i));
1460 
1461                 if (!tmp)
1462                     return -ENOMEM;
1463                 ids__insert(ids->ids, tmp);
1464                 added_event = true;
1465             }
1466         }
1467         if (!added_event && hashmap__size(ids->ids) == 0) {
1468             char *tmp = strdup("duration_time");
1469 
1470             if (!tmp)
1471                 return -ENOMEM;
1472             ids__insert(ids->ids, tmp);
1473         }
1474     }
1475     ret = metricgroup__build_event_string(&events, ids, modifier,
1476                           has_constraint);
1477     if (ret)
1478         return ret;
1479 
1480     parsed_evlist = evlist__new();
1481     if (!parsed_evlist) {
1482         ret = -ENOMEM;
1483         goto err_out;
1484     }
1485     pr_debug("Parsing metric events '%s'\n", events.buf);
1486     parse_events_error__init(&parse_error);
1487     ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu);
1488     if (ret) {
1489         parse_events_error__print(&parse_error, events.buf);
1490         goto err_out;
1491     }
1492     ret = decode_all_metric_ids(parsed_evlist, modifier);
1493     if (ret)
1494         goto err_out;
1495 
1496     *out_evlist = parsed_evlist;
1497     parsed_evlist = NULL;
1498 err_out:
1499     parse_events_error__exit(&parse_error);
1500     evlist__delete(parsed_evlist);
1501     strbuf_release(&events);
1502     return ret;
1503 }
1504 
1505 static int parse_groups(struct evlist *perf_evlist, const char *str,
1506             bool metric_no_group,
1507             bool metric_no_merge,
1508             struct perf_pmu *fake_pmu,
1509             struct rblist *metric_events_list,
1510             const struct pmu_events_table *table)
1511 {
1512     struct evlist *combined_evlist = NULL;
1513     LIST_HEAD(metric_list);
1514     struct metric *m;
1515     bool tool_events[PERF_TOOL_MAX] = {false};
1516     int ret;
1517 
1518     if (metric_events_list->nr_entries == 0)
1519         metricgroup__rblist_init(metric_events_list);
1520     ret = metricgroup__add_metric_list(str, metric_no_group,
1521                        &metric_list, table);
1522     if (ret)
1523         goto out;
1524 
1525     /* Sort metrics from largest to smallest. */
1526     list_sort(NULL, &metric_list, metric_list_cmp);
1527 
1528     if (!metric_no_merge) {
1529         struct expr_parse_ctx *combined = NULL;
1530 
1531         find_tool_events(&metric_list, tool_events);
1532 
1533         ret = build_combined_expr_ctx(&metric_list, &combined);
1534 
1535         if (!ret && combined && hashmap__size(combined->ids)) {
1536             ret = parse_ids(metric_no_merge, fake_pmu, combined,
1537                     /*modifier=*/NULL,
1538                     /*has_constraint=*/true,
1539                     tool_events,
1540                     &combined_evlist);
1541         }
1542         if (combined)
1543             expr__ctx_free(combined);
1544 
1545         if (ret)
1546             goto out;
1547     }
1548 
1549     list_for_each_entry(m, &metric_list, nd) {
1550         struct metric_event *me;
1551         struct evsel **metric_events;
1552         struct evlist *metric_evlist = NULL;
1553         struct metric *n;
1554         struct metric_expr *expr;
1555 
1556         if (combined_evlist && m->has_constraint) {
1557             metric_evlist = combined_evlist;
1558         } else if (!metric_no_merge) {
1559             /*
1560              * See if the IDs for this metric are a subset of an
1561              * earlier metric.
1562              */
1563             list_for_each_entry(n, &metric_list, nd) {
1564                 if (m == n)
1565                     break;
1566 
1567                 if (n->evlist == NULL)
1568                     continue;
1569 
1570                 if ((!m->modifier && n->modifier) ||
1571                     (m->modifier && !n->modifier) ||
1572                     (m->modifier && n->modifier &&
1573                         strcmp(m->modifier, n->modifier)))
1574                     continue;
1575 
1576                 if (expr__subset_of_ids(n->pctx, m->pctx)) {
1577                     pr_debug("Events in '%s' fully contained within '%s'\n",
1578                          m->metric_name, n->metric_name);
1579                     metric_evlist = n->evlist;
1580                     break;
1581                 }
1582 
1583             }
1584         }
1585         if (!metric_evlist) {
1586             ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier,
1587                     m->has_constraint, tool_events, &m->evlist);
1588             if (ret)
1589                 goto out;
1590 
1591             metric_evlist = m->evlist;
1592         }
1593         ret = setup_metric_events(m->pctx->ids, metric_evlist, &metric_events);
1594         if (ret) {
1595             pr_debug("Cannot resolve IDs for %s: %s\n",
1596                 m->metric_name, m->metric_expr);
1597             goto out;
1598         }
1599 
1600         me = metricgroup__lookup(metric_events_list, metric_events[0], true);
1601 
1602         expr = malloc(sizeof(struct metric_expr));
1603         if (!expr) {
1604             ret = -ENOMEM;
1605             free(metric_events);
1606             goto out;
1607         }
1608 
1609         expr->metric_refs = m->metric_refs;
1610         m->metric_refs = NULL;
1611         expr->metric_expr = m->metric_expr;
1612         if (m->modifier) {
1613             char *tmp;
1614 
1615             if (asprintf(&tmp, "%s:%s", m->metric_name, m->modifier) < 0)
1616                 expr->metric_name = NULL;
1617             else
1618                 expr->metric_name = tmp;
1619         } else
1620             expr->metric_name = strdup(m->metric_name);
1621 
1622         if (!expr->metric_name) {
1623             ret = -ENOMEM;
1624             free(metric_events);
1625             goto out;
1626         }
1627         expr->metric_unit = m->metric_unit;
1628         expr->metric_events = metric_events;
1629         expr->runtime = m->pctx->runtime;
1630         list_add(&expr->nd, &me->head);
1631     }
1632 
1633 
1634     if (combined_evlist) {
1635         evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
1636         evlist__delete(combined_evlist);
1637     }
1638 
1639     list_for_each_entry(m, &metric_list, nd) {
1640         if (m->evlist)
1641             evlist__splice_list_tail(perf_evlist, &m->evlist->core.entries);
1642     }
1643 
1644 out:
1645     metricgroup__free_metrics(&metric_list);
1646     return ret;
1647 }
1648 
1649 int metricgroup__parse_groups(const struct option *opt,
1650                   const char *str,
1651                   bool metric_no_group,
1652                   bool metric_no_merge,
1653                   struct rblist *metric_events)
1654 {
1655     struct evlist *perf_evlist = *(struct evlist **)opt->value;
1656     const struct pmu_events_table *table = pmu_events_table__find();
1657 
1658     if (!table)
1659         return -EINVAL;
1660 
1661     return parse_groups(perf_evlist, str, metric_no_group,
1662                 metric_no_merge, NULL, metric_events, table);
1663 }
1664 
1665 int metricgroup__parse_groups_test(struct evlist *evlist,
1666                    const struct pmu_events_table *table,
1667                    const char *str,
1668                    bool metric_no_group,
1669                    bool metric_no_merge,
1670                    struct rblist *metric_events)
1671 {
1672     return parse_groups(evlist, str, metric_no_group,
1673                 metric_no_merge, &perf_pmu__fake, metric_events, table);
1674 }
1675 
1676 static int metricgroup__has_metric_callback(const struct pmu_event *pe,
1677                         const struct pmu_events_table *table __maybe_unused,
1678                         void *vdata)
1679 {
1680     const char *metric = vdata;
1681 
1682     if (!pe->metric_expr)
1683         return 0;
1684 
1685     if (match_metric(pe->metric_name, metric))
1686         return 1;
1687 
1688     return 0;
1689 }
1690 
1691 bool metricgroup__has_metric(const char *metric)
1692 {
1693     const struct pmu_events_table *table = pmu_events_table__find();
1694 
1695     if (!table)
1696         return false;
1697 
1698     return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
1699                            (void *)metric) ? true : false;
1700 }
1701 
1702 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
1703                     struct rblist *new_metric_events,
1704                     struct rblist *old_metric_events)
1705 {
1706     unsigned i;
1707 
1708     for (i = 0; i < rblist__nr_entries(old_metric_events); i++) {
1709         struct rb_node *nd;
1710         struct metric_event *old_me, *new_me;
1711         struct metric_expr *old_expr, *new_expr;
1712         struct evsel *evsel;
1713         size_t alloc_size;
1714         int idx, nr;
1715 
1716         nd = rblist__entry(old_metric_events, i);
1717         old_me = container_of(nd, struct metric_event, nd);
1718 
1719         evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx);
1720         if (!evsel)
1721             return -EINVAL;
1722         new_me = metricgroup__lookup(new_metric_events, evsel, true);
1723         if (!new_me)
1724             return -ENOMEM;
1725 
1726         pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n",
1727              cgrp ? cgrp->name : "root", evsel->name, evsel->core.idx);
1728 
1729         list_for_each_entry(old_expr, &old_me->head, nd) {
1730             new_expr = malloc(sizeof(*new_expr));
1731             if (!new_expr)
1732                 return -ENOMEM;
1733 
1734             new_expr->metric_expr = old_expr->metric_expr;
1735             new_expr->metric_name = strdup(old_expr->metric_name);
1736             if (!new_expr->metric_name)
1737                 return -ENOMEM;
1738 
1739             new_expr->metric_unit = old_expr->metric_unit;
1740             new_expr->runtime = old_expr->runtime;
1741 
1742             if (old_expr->metric_refs) {
1743                 /* calculate number of metric_events */
1744                 for (nr = 0; old_expr->metric_refs[nr].metric_name; nr++)
1745                     continue;
1746                 alloc_size = sizeof(*new_expr->metric_refs);
1747                 new_expr->metric_refs = calloc(nr + 1, alloc_size);
1748                 if (!new_expr->metric_refs) {
1749                     free(new_expr);
1750                     return -ENOMEM;
1751                 }
1752 
1753                 memcpy(new_expr->metric_refs, old_expr->metric_refs,
1754                        nr * alloc_size);
1755             } else {
1756                 new_expr->metric_refs = NULL;
1757             }
1758 
1759             /* calculate number of metric_events */
1760             for (nr = 0; old_expr->metric_events[nr]; nr++)
1761                 continue;
1762             alloc_size = sizeof(*new_expr->metric_events);
1763             new_expr->metric_events = calloc(nr + 1, alloc_size);
1764             if (!new_expr->metric_events) {
1765                 free(new_expr->metric_refs);
1766                 free(new_expr);
1767                 return -ENOMEM;
1768             }
1769 
1770             /* copy evsel in the same position */
1771             for (idx = 0; idx < nr; idx++) {
1772                 evsel = old_expr->metric_events[idx];
1773                 evsel = evlist__find_evsel(evlist, evsel->core.idx);
1774                 if (evsel == NULL) {
1775                     free(new_expr->metric_events);
1776                     free(new_expr->metric_refs);
1777                     free(new_expr);
1778                     return -EINVAL;
1779                 }
1780                 new_expr->metric_events[idx] = evsel;
1781             }
1782 
1783             list_add(&new_expr->nd, &new_me->head);
1784         }
1785     }
1786     return 0;
1787 }