]> Git Repo - linux.git/blob - tools/perf/util/metricgroup.c
HID: hid-sensor-custom: Fix big on-stack allocation in hid_sensor_custom_get_known()
[linux.git] / tools / perf / util / metricgroup.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2017, Intel Corporation.
4  */
5
6 /* Manage metrics and groups of metrics from JSON files */
7
8 #include "metricgroup.h"
9 #include "debug.h"
10 #include "evlist.h"
11 #include "evsel.h"
12 #include "strbuf.h"
13 #include "pmu.h"
14 #include "pmu-hybrid.h"
15 #include "expr.h"
16 #include "rblist.h"
17 #include <string.h>
18 #include <errno.h>
19 #include "strlist.h"
20 #include <assert.h>
21 #include <linux/ctype.h>
22 #include <linux/list_sort.h>
23 #include <linux/string.h>
24 #include <linux/zalloc.h>
25 #include <perf/cpumap.h>
26 #include <subcmd/parse-options.h>
27 #include <api/fs/fs.h>
28 #include "util.h"
29 #include <asm/bug.h>
30 #include "cgroup.h"
31
32 struct metric_event *metricgroup__lookup(struct rblist *metric_events,
33                                          struct evsel *evsel,
34                                          bool create)
35 {
36         struct rb_node *nd;
37         struct metric_event me = {
38                 .evsel = evsel
39         };
40
41         if (!metric_events)
42                 return NULL;
43
44         nd = rblist__find(metric_events, &me);
45         if (nd)
46                 return container_of(nd, struct metric_event, nd);
47         if (create) {
48                 rblist__add_node(metric_events, &me);
49                 nd = rblist__find(metric_events, &me);
50                 if (nd)
51                         return container_of(nd, struct metric_event, nd);
52         }
53         return NULL;
54 }
55
56 static int metric_event_cmp(struct rb_node *rb_node, const void *entry)
57 {
58         struct metric_event *a = container_of(rb_node,
59                                               struct metric_event,
60                                               nd);
61         const struct metric_event *b = entry;
62
63         if (a->evsel == b->evsel)
64                 return 0;
65         if ((char *)a->evsel < (char *)b->evsel)
66                 return -1;
67         return +1;
68 }
69
70 static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused,
71                                         const void *entry)
72 {
73         struct metric_event *me = malloc(sizeof(struct metric_event));
74
75         if (!me)
76                 return NULL;
77         memcpy(me, entry, sizeof(struct metric_event));
78         me->evsel = ((struct metric_event *)entry)->evsel;
79         INIT_LIST_HEAD(&me->head);
80         return &me->nd;
81 }
82
83 static void metric_event_delete(struct rblist *rblist __maybe_unused,
84                                 struct rb_node *rb_node)
85 {
86         struct metric_event *me = container_of(rb_node, struct metric_event, nd);
87         struct metric_expr *expr, *tmp;
88
89         list_for_each_entry_safe(expr, tmp, &me->head, nd) {
90                 free((char *)expr->metric_name);
91                 free(expr->metric_refs);
92                 free(expr->metric_events);
93                 free(expr);
94         }
95
96         free(me);
97 }
98
99 static void metricgroup__rblist_init(struct rblist *metric_events)
100 {
101         rblist__init(metric_events);
102         metric_events->node_cmp = metric_event_cmp;
103         metric_events->node_new = metric_event_new;
104         metric_events->node_delete = metric_event_delete;
105 }
106
107 void metricgroup__rblist_exit(struct rblist *metric_events)
108 {
109         rblist__exit(metric_events);
110 }
111
112 /**
113  * The metric under construction. The data held here will be placed in a
114  * metric_expr.
115  */
116 struct metric {
117         struct list_head nd;
118         /**
119          * The expression parse context importantly holding the IDs contained
120          * within the expression.
121          */
122         struct expr_parse_ctx *pctx;
123         /** The name of the metric such as "IPC". */
124         const char *metric_name;
125         /** Modifier on the metric such as "u" or NULL for none. */
126         const char *modifier;
127         /** The expression to parse, for example, "instructions/cycles". */
128         const char *metric_expr;
129         /**
130          * The "ScaleUnit" that scales and adds a unit to the metric during
131          * output.
132          */
133         const char *metric_unit;
134         /** Optional null terminated array of referenced metrics. */
135         struct metric_ref *metric_refs;
136         /**
137          * Is there a constraint on the group of events? In which case the
138          * events won't be grouped.
139          */
140         bool has_constraint;
141         /**
142          * Parsed events for the metric. Optional as events may be taken from a
143          * different metric whose group contains all the IDs necessary for this
144          * one.
145          */
146         struct evlist *evlist;
147 };
148
149 static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
150 {
151         static bool violate_nmi_constraint;
152
153         if (!foot) {
154                 pr_warning("Splitting metric group %s into standalone metrics.\n", name);
155                 violate_nmi_constraint = true;
156                 return;
157         }
158
159         if (!violate_nmi_constraint)
160                 return;
161
162         pr_warning("Try disabling the NMI watchdog to comply NO_NMI_WATCHDOG metric constraint:\n"
163                    "    echo 0 > /proc/sys/kernel/nmi_watchdog\n"
164                    "    perf stat ...\n"
165                    "    echo 1 > /proc/sys/kernel/nmi_watchdog\n");
166 }
167
168 static bool metricgroup__has_constraint(const struct pmu_event *pe)
169 {
170         if (!pe->metric_constraint)
171                 return false;
172
173         if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") &&
174             sysctl__nmi_watchdog_enabled()) {
175                 metricgroup___watchdog_constraint_hint(pe->metric_name, false);
176                 return true;
177         }
178
179         return false;
180 }
181
182 static void metric__free(struct metric *m)
183 {
184         if (!m)
185                 return;
186
187         free(m->metric_refs);
188         expr__ctx_free(m->pctx);
189         free((char *)m->modifier);
190         evlist__delete(m->evlist);
191         free(m);
192 }
193
194 static struct metric *metric__new(const struct pmu_event *pe,
195                                   const char *modifier,
196                                   bool metric_no_group,
197                                   int runtime,
198                                   const char *user_requested_cpu_list,
199                                   bool system_wide)
200 {
201         struct metric *m;
202
203         m = zalloc(sizeof(*m));
204         if (!m)
205                 return NULL;
206
207         m->pctx = expr__ctx_new();
208         if (!m->pctx)
209                 goto out_err;
210
211         m->metric_name = pe->metric_name;
212         m->modifier = NULL;
213         if (modifier) {
214                 m->modifier = strdup(modifier);
215                 if (!m->modifier)
216                         goto out_err;
217         }
218         m->metric_expr = pe->metric_expr;
219         m->metric_unit = pe->unit;
220         m->pctx->sctx.user_requested_cpu_list = NULL;
221         if (user_requested_cpu_list) {
222                 m->pctx->sctx.user_requested_cpu_list = strdup(user_requested_cpu_list);
223                 if (!m->pctx->sctx.user_requested_cpu_list)
224                         goto out_err;
225         }
226         m->pctx->sctx.runtime = runtime;
227         m->pctx->sctx.system_wide = system_wide;
228         m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
229         m->metric_refs = NULL;
230         m->evlist = NULL;
231
232         return m;
233 out_err:
234         metric__free(m);
235         return NULL;
236 }
237
238 static bool contains_metric_id(struct evsel **metric_events, int num_events,
239                                const char *metric_id)
240 {
241         int i;
242
243         for (i = 0; i < num_events; i++) {
244                 if (!strcmp(evsel__metric_id(metric_events[i]), metric_id))
245                         return true;
246         }
247         return false;
248 }
249
250 /**
251  * setup_metric_events - Find a group of events in metric_evlist that correspond
252  *                       to the IDs from a parsed metric expression.
253  * @ids: the metric IDs to match.
254  * @metric_evlist: the list of perf events.
255  * @out_metric_events: holds the created metric events array.
256  */
257 static int setup_metric_events(struct hashmap *ids,
258                                struct evlist *metric_evlist,
259                                struct evsel ***out_metric_events)
260 {
261         struct evsel **metric_events;
262         const char *metric_id;
263         struct evsel *ev;
264         size_t ids_size, matched_events, i;
265
266         *out_metric_events = NULL;
267         ids_size = hashmap__size(ids);
268
269         metric_events = calloc(sizeof(void *), ids_size + 1);
270         if (!metric_events)
271                 return -ENOMEM;
272
273         matched_events = 0;
274         evlist__for_each_entry(metric_evlist, ev) {
275                 struct expr_id_data *val_ptr;
276
277                 /*
278                  * Check for duplicate events with the same name. For
279                  * example, uncore_imc/cas_count_read/ will turn into 6
280                  * events per socket on skylakex. Only the first such
281                  * event is placed in metric_events.
282                  */
283                 metric_id = evsel__metric_id(ev);
284                 if (contains_metric_id(metric_events, matched_events, metric_id))
285                         continue;
286                 /*
287                  * Does this event belong to the parse context? For
288                  * combined or shared groups, this metric may not care
289                  * about this event.
290                  */
291                 if (hashmap__find(ids, metric_id, (void **)&val_ptr)) {
292                         metric_events[matched_events++] = ev;
293
294                         if (matched_events >= ids_size)
295                                 break;
296                 }
297         }
298         if (matched_events < ids_size) {
299                 free(metric_events);
300                 return -EINVAL;
301         }
302         for (i = 0; i < ids_size; i++) {
303                 ev = metric_events[i];
304                 ev->collect_stat = true;
305
306                 /*
307                  * The metric leader points to the identically named
308                  * event in metric_events.
309                  */
310                 ev->metric_leader = ev;
311                 /*
312                  * Mark two events with identical names in the same
313                  * group (or globally) as being in use as uncore events
314                  * may be duplicated for each pmu. Set the metric leader
315                  * of such events to be the event that appears in
316                  * metric_events.
317                  */
318                 metric_id = evsel__metric_id(ev);
319                 evlist__for_each_entry_continue(metric_evlist, ev) {
320                         if (!strcmp(evsel__metric_id(ev), metric_id))
321                                 ev->metric_leader = metric_events[i];
322                 }
323         }
324         *out_metric_events = metric_events;
325         return 0;
326 }
327
328 static bool match_metric(const char *n, const char *list)
329 {
330         int len;
331         char *m;
332
333         if (!list)
334                 return false;
335         if (!strcmp(list, "all"))
336                 return true;
337         if (!n)
338                 return !strcasecmp(list, "No_group");
339         len = strlen(list);
340         m = strcasestr(n, list);
341         if (!m)
342                 return false;
343         if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
344             (m[len] == 0 || m[len] == ';'))
345                 return true;
346         return false;
347 }
348
349 static bool match_pe_metric(const struct pmu_event *pe, const char *metric)
350 {
351         return match_metric(pe->metric_group, metric) ||
352                match_metric(pe->metric_name, metric);
353 }
354
355 struct mep {
356         struct rb_node nd;
357         const char *name;
358         struct strlist *metrics;
359 };
360
361 static int mep_cmp(struct rb_node *rb_node, const void *entry)
362 {
363         struct mep *a = container_of(rb_node, struct mep, nd);
364         struct mep *b = (struct mep *)entry;
365
366         return strcmp(a->name, b->name);
367 }
368
369 static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
370                                         const void *entry)
371 {
372         struct mep *me = malloc(sizeof(struct mep));
373
374         if (!me)
375                 return NULL;
376         memcpy(me, entry, sizeof(struct mep));
377         me->name = strdup(me->name);
378         if (!me->name)
379                 goto out_me;
380         me->metrics = strlist__new(NULL, NULL);
381         if (!me->metrics)
382                 goto out_name;
383         return &me->nd;
384 out_name:
385         zfree(&me->name);
386 out_me:
387         free(me);
388         return NULL;
389 }
390
391 static struct mep *mep_lookup(struct rblist *groups, const char *name)
392 {
393         struct rb_node *nd;
394         struct mep me = {
395                 .name = name
396         };
397         nd = rblist__find(groups, &me);
398         if (nd)
399                 return container_of(nd, struct mep, nd);
400         rblist__add_node(groups, &me);
401         nd = rblist__find(groups, &me);
402         if (nd)
403                 return container_of(nd, struct mep, nd);
404         return NULL;
405 }
406
407 static void mep_delete(struct rblist *rl __maybe_unused,
408                        struct rb_node *nd)
409 {
410         struct mep *me = container_of(nd, struct mep, nd);
411
412         strlist__delete(me->metrics);
413         zfree(&me->name);
414         free(me);
415 }
416
417 static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
418 {
419         struct str_node *sn;
420         int n = 0;
421
422         strlist__for_each_entry (sn, metrics) {
423                 if (raw)
424                         printf("%s%s", n > 0 ? " " : "", sn->s);
425                 else
426                         printf("  %s\n", sn->s);
427                 n++;
428         }
429         if (raw)
430                 putchar('\n');
431 }
432
433 static int metricgroup__print_pmu_event(const struct pmu_event *pe,
434                                         bool metricgroups, char *filter,
435                                         bool raw, bool details,
436                                         struct rblist *groups,
437                                         struct strlist *metriclist)
438 {
439         const char *g;
440         char *omg, *mg;
441
442         g = pe->metric_group;
443         if (!g && pe->metric_name) {
444                 if (pe->name)
445                         return 0;
446                 g = "No_group";
447         }
448
449         if (!g)
450                 return 0;
451
452         mg = strdup(g);
453
454         if (!mg)
455                 return -ENOMEM;
456         omg = mg;
457         while ((g = strsep(&mg, ";")) != NULL) {
458                 struct mep *me;
459                 char *s;
460
461                 g = skip_spaces(g);
462                 if (*g == 0)
463                         g = "No_group";
464                 if (filter && !strstr(g, filter))
465                         continue;
466                 if (raw)
467                         s = (char *)pe->metric_name;
468                 else {
469                         if (asprintf(&s, "%s\n%*s%s]",
470                                      pe->metric_name, 8, "[", pe->desc) < 0)
471                                 return -1;
472                         if (details) {
473                                 if (asprintf(&s, "%s\n%*s%s]",
474                                              s, 8, "[", pe->metric_expr) < 0)
475                                         return -1;
476                         }
477                 }
478
479                 if (!s)
480                         continue;
481
482                 if (!metricgroups) {
483                         strlist__add(metriclist, s);
484                 } else {
485                         me = mep_lookup(groups, g);
486                         if (!me)
487                                 continue;
488                         strlist__add(me->metrics, s);
489                 }
490
491                 if (!raw)
492                         free(s);
493         }
494         free(omg);
495
496         return 0;
497 }
498
499 struct metricgroup_print_sys_idata {
500         struct strlist *metriclist;
501         char *filter;
502         struct rblist *groups;
503         bool metricgroups;
504         bool raw;
505         bool details;
506 };
507
508 struct metricgroup_iter_data {
509         pmu_event_iter_fn fn;
510         void *data;
511 };
512
513 static int metricgroup__sys_event_iter(const struct pmu_event *pe,
514                                        const struct pmu_events_table *table,
515                                        void *data)
516 {
517         struct metricgroup_iter_data *d = data;
518         struct perf_pmu *pmu = NULL;
519
520         if (!pe->metric_expr || !pe->compat)
521                 return 0;
522
523         while ((pmu = perf_pmu__scan(pmu))) {
524
525                 if (!pmu->id || strcmp(pmu->id, pe->compat))
526                         continue;
527
528                 return d->fn(pe, table, d->data);
529         }
530
531         return 0;
532 }
533
534 static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
535                                              const struct pmu_events_table *table __maybe_unused,
536                                              void *data)
537 {
538         struct metricgroup_print_sys_idata *d = data;
539
540         return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw,
541                                      d->details, d->groups, d->metriclist);
542 }
543
544 struct metricgroup_print_data {
545         const char *pmu_name;
546         struct strlist *metriclist;
547         char *filter;
548         struct rblist *groups;
549         bool metricgroups;
550         bool raw;
551         bool details;
552 };
553
554 static int metricgroup__print_callback(const struct pmu_event *pe,
555                                        const struct pmu_events_table *table __maybe_unused,
556                                        void *vdata)
557 {
558         struct metricgroup_print_data *data = vdata;
559
560         if (!pe->metric_expr)
561                 return 0;
562
563         if (data->pmu_name && perf_pmu__is_hybrid(pe->pmu) && strcmp(data->pmu_name, pe->pmu))
564                 return 0;
565
566         return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter,
567                                             data->raw, data->details, data->groups,
568                                             data->metriclist);
569 }
570
571 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
572                         bool raw, bool details, const char *pmu_name)
573 {
574         struct rblist groups;
575         struct rb_node *node, *next;
576         struct strlist *metriclist = NULL;
577         const struct pmu_events_table *table;
578
579         if (!metricgroups) {
580                 metriclist = strlist__new(NULL, NULL);
581                 if (!metriclist)
582                         return;
583         }
584
585         rblist__init(&groups);
586         groups.node_new = mep_new;
587         groups.node_cmp = mep_cmp;
588         groups.node_delete = mep_delete;
589         table = pmu_events_table__find();
590         if (table) {
591                 struct metricgroup_print_data data = {
592                         .pmu_name = pmu_name,
593                         .metriclist = metriclist,
594                         .metricgroups = metricgroups,
595                         .filter = filter,
596                         .raw = raw,
597                         .details = details,
598                         .groups = &groups,
599                 };
600
601                 pmu_events_table_for_each_event(table,
602                                                 metricgroup__print_callback,
603                                                 &data);
604         }
605         {
606                 struct metricgroup_iter_data data = {
607                         .fn = metricgroup__print_sys_event_iter,
608                         .data = (void *) &(struct metricgroup_print_sys_idata){
609                                 .metriclist = metriclist,
610                                 .metricgroups = metricgroups,
611                                 .filter = filter,
612                                 .raw = raw,
613                                 .details = details,
614                                 .groups = &groups,
615                         },
616                 };
617
618                 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
619         }
620
621         if (!filter || !rblist__empty(&groups)) {
622                 if (metricgroups && !raw)
623                         printf("\nMetric Groups:\n\n");
624                 else if (metrics && !raw)
625                         printf("\nMetrics:\n\n");
626         }
627
628         for (node = rb_first_cached(&groups.entries); node; node = next) {
629                 struct mep *me = container_of(node, struct mep, nd);
630
631                 if (metricgroups)
632                         printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n");
633                 if (metrics)
634                         metricgroup__print_strlist(me->metrics, raw);
635                 next = rb_next(node);
636                 rblist__remove_node(&groups, node);
637         }
638         if (!metricgroups)
639                 metricgroup__print_strlist(metriclist, raw);
640         strlist__delete(metriclist);
641 }
642
643 static const char *code_characters = ",-=@";
644
645 static int encode_metric_id(struct strbuf *sb, const char *x)
646 {
647         char *c;
648         int ret = 0;
649
650         for (; *x; x++) {
651                 c = strchr(code_characters, *x);
652                 if (c) {
653                         ret = strbuf_addch(sb, '!');
654                         if (ret)
655                                 break;
656
657                         ret = strbuf_addch(sb, '0' + (c - code_characters));
658                         if (ret)
659                                 break;
660                 } else {
661                         ret = strbuf_addch(sb, *x);
662                         if (ret)
663                                 break;
664                 }
665         }
666         return ret;
667 }
668
669 static int decode_metric_id(struct strbuf *sb, const char *x)
670 {
671         const char *orig = x;
672         size_t i;
673         char c;
674         int ret;
675
676         for (; *x; x++) {
677                 c = *x;
678                 if (*x == '!') {
679                         x++;
680                         i = *x - '0';
681                         if (i > strlen(code_characters)) {
682                                 pr_err("Bad metric-id encoding in: '%s'", orig);
683                                 return -1;
684                         }
685                         c = code_characters[i];
686                 }
687                 ret = strbuf_addch(sb, c);
688                 if (ret)
689                         return ret;
690         }
691         return 0;
692 }
693
694 static int decode_all_metric_ids(struct evlist *perf_evlist, const char *modifier)
695 {
696         struct evsel *ev;
697         struct strbuf sb = STRBUF_INIT;
698         char *cur;
699         int ret = 0;
700
701         evlist__for_each_entry(perf_evlist, ev) {
702                 if (!ev->metric_id)
703                         continue;
704
705                 ret = strbuf_setlen(&sb, 0);
706                 if (ret)
707                         break;
708
709                 ret = decode_metric_id(&sb, ev->metric_id);
710                 if (ret)
711                         break;
712
713                 free((char *)ev->metric_id);
714                 ev->metric_id = strdup(sb.buf);
715                 if (!ev->metric_id) {
716                         ret = -ENOMEM;
717                         break;
718                 }
719                 /*
720                  * If the name is just the parsed event, use the metric-id to
721                  * give a more friendly display version.
722                  */
723                 if (strstr(ev->name, "metric-id=")) {
724                         bool has_slash = false;
725
726                         free(ev->name);
727                         for (cur = strchr(sb.buf, '@') ; cur; cur = strchr(++cur, '@')) {
728                                 *cur = '/';
729                                 has_slash = true;
730                         }
731
732                         if (modifier) {
733                                 if (!has_slash && !strchr(sb.buf, ':')) {
734                                         ret = strbuf_addch(&sb, ':');
735                                         if (ret)
736                                                 break;
737                                 }
738                                 ret = strbuf_addstr(&sb, modifier);
739                                 if (ret)
740                                         break;
741                         }
742                         ev->name = strdup(sb.buf);
743                         if (!ev->name) {
744                                 ret = -ENOMEM;
745                                 break;
746                         }
747                 }
748         }
749         strbuf_release(&sb);
750         return ret;
751 }
752
753 static int metricgroup__build_event_string(struct strbuf *events,
754                                            const struct expr_parse_ctx *ctx,
755                                            const char *modifier,
756                                            bool has_constraint)
757 {
758         struct hashmap_entry *cur;
759         size_t bkt;
760         bool no_group = true, has_tool_events = false;
761         bool tool_events[PERF_TOOL_MAX] = {false};
762         int ret = 0;
763
764 #define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0)
765
766         hashmap__for_each_entry(ctx->ids, cur, bkt) {
767                 const char *sep, *rsep, *id = cur->key;
768                 enum perf_tool_event ev;
769
770                 pr_debug("found event %s\n", id);
771
772                 /* Always move tool events outside of the group. */
773                 ev = perf_tool_event__from_str(id);
774                 if (ev != PERF_TOOL_NONE) {
775                         has_tool_events = true;
776                         tool_events[ev] = true;
777                         continue;
778                 }
779                 /* Separate events with commas and open the group if necessary. */
780                 if (no_group) {
781                         if (!has_constraint) {
782                                 ret = strbuf_addch(events, '{');
783                                 RETURN_IF_NON_ZERO(ret);
784                         }
785
786                         no_group = false;
787                 } else {
788                         ret = strbuf_addch(events, ',');
789                         RETURN_IF_NON_ZERO(ret);
790                 }
791                 /*
792                  * Encode the ID as an event string. Add a qualifier for
793                  * metric_id that is the original name except with characters
794                  * that parse-events can't parse replaced. For example,
795                  * 'msr@tsc@' gets added as msr/tsc,metric-id=msr!3tsc!3/
796                  */
797                 sep = strchr(id, '@');
798                 if (sep != NULL) {
799                         ret = strbuf_add(events, id, sep - id);
800                         RETURN_IF_NON_ZERO(ret);
801                         ret = strbuf_addch(events, '/');
802                         RETURN_IF_NON_ZERO(ret);
803                         rsep = strrchr(sep, '@');
804                         ret = strbuf_add(events, sep + 1, rsep - sep - 1);
805                         RETURN_IF_NON_ZERO(ret);
806                         ret = strbuf_addstr(events, ",metric-id=");
807                         RETURN_IF_NON_ZERO(ret);
808                         sep = rsep;
809                 } else {
810                         sep = strchr(id, ':');
811                         if (sep != NULL) {
812                                 ret = strbuf_add(events, id, sep - id);
813                                 RETURN_IF_NON_ZERO(ret);
814                         } else {
815                                 ret = strbuf_addstr(events, id);
816                                 RETURN_IF_NON_ZERO(ret);
817                         }
818                         ret = strbuf_addstr(events, "/metric-id=");
819                         RETURN_IF_NON_ZERO(ret);
820                 }
821                 ret = encode_metric_id(events, id);
822                 RETURN_IF_NON_ZERO(ret);
823                 ret = strbuf_addstr(events, "/");
824                 RETURN_IF_NON_ZERO(ret);
825
826                 if (sep != NULL) {
827                         ret = strbuf_addstr(events, sep + 1);
828                         RETURN_IF_NON_ZERO(ret);
829                 }
830                 if (modifier) {
831                         ret = strbuf_addstr(events, modifier);
832                         RETURN_IF_NON_ZERO(ret);
833                 }
834         }
835         if (!no_group && !has_constraint) {
836                 ret = strbuf_addf(events, "}:W");
837                 RETURN_IF_NON_ZERO(ret);
838         }
839         if (has_tool_events) {
840                 int i;
841
842                 perf_tool_event__for_each_event(i) {
843                         if (tool_events[i]) {
844                                 if (!no_group) {
845                                         ret = strbuf_addch(events, ',');
846                                         RETURN_IF_NON_ZERO(ret);
847                                 }
848                                 no_group = false;
849                                 ret = strbuf_addstr(events, perf_tool_event__to_str(i));
850                                 RETURN_IF_NON_ZERO(ret);
851                         }
852                 }
853         }
854
855         return ret;
856 #undef RETURN_IF_NON_ZERO
857 }
858
859 int __weak arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused)
860 {
861         return 1;
862 }
863
864 /*
865  * A singly linked list on the stack of the names of metrics being
866  * processed. Used to identify recursion.
867  */
868 struct visited_metric {
869         const char *name;
870         const struct visited_metric *parent;
871 };
872
873 struct metricgroup_add_iter_data {
874         struct list_head *metric_list;
875         const char *metric_name;
876         const char *modifier;
877         int *ret;
878         bool *has_match;
879         bool metric_no_group;
880         const char *user_requested_cpu_list;
881         bool system_wide;
882         struct metric *root_metric;
883         const struct visited_metric *visited;
884         const struct pmu_events_table *table;
885 };
886
887 static bool metricgroup__find_metric(const char *metric,
888                                      const struct pmu_events_table *table,
889                                      struct pmu_event *pe);
890
891 static int add_metric(struct list_head *metric_list,
892                       const struct pmu_event *pe,
893                       const char *modifier,
894                       bool metric_no_group,
895                       const char *user_requested_cpu_list,
896                       bool system_wide,
897                       struct metric *root_metric,
898                       const struct visited_metric *visited,
899                       const struct pmu_events_table *table);
900
901 /**
902  * resolve_metric - Locate metrics within the root metric and recursively add
903  *                    references to them.
904  * @metric_list: The list the metric is added to.
905  * @modifier: if non-null event modifiers like "u".
906  * @metric_no_group: Should events written to events be grouped "{}" or
907  *                   global. Grouping is the default but due to multiplexing the
908  *                   user may override.
909  * @user_requested_cpu_list: Command line specified CPUs to record on.
910  * @system_wide: Are events for all processes recorded.
911  * @root_metric: Metrics may reference other metrics to form a tree. In this
912  *               case the root_metric holds all the IDs and a list of referenced
913  *               metrics. When adding a root this argument is NULL.
914  * @visited: A singly linked list of metric names being added that is used to
915  *           detect recursion.
916  * @table: The table that is searched for metrics, most commonly the table for the
917  *       architecture perf is running upon.
918  */
919 static int resolve_metric(struct list_head *metric_list,
920                           const char *modifier,
921                           bool metric_no_group,
922                           const char *user_requested_cpu_list,
923                           bool system_wide,
924                           struct metric *root_metric,
925                           const struct visited_metric *visited,
926                           const struct pmu_events_table *table)
927 {
928         struct hashmap_entry *cur;
929         size_t bkt;
930         struct to_resolve {
931                 /* The metric to resolve. */
932                 struct pmu_event pe;
933                 /*
934                  * The key in the IDs map, this may differ from in case,
935                  * etc. from pe->metric_name.
936                  */
937                 const char *key;
938         } *pending = NULL;
939         int i, ret = 0, pending_cnt = 0;
940
941         /*
942          * Iterate all the parsed IDs and if there's a matching metric and it to
943          * the pending array.
944          */
945         hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
946                 struct pmu_event pe;
947
948                 if (metricgroup__find_metric(cur->key, table, &pe)) {
949                         pending = realloc(pending,
950                                         (pending_cnt + 1) * sizeof(struct to_resolve));
951                         if (!pending)
952                                 return -ENOMEM;
953
954                         memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
955                         pending[pending_cnt].key = cur->key;
956                         pending_cnt++;
957                 }
958         }
959
960         /* Remove the metric IDs from the context. */
961         for (i = 0; i < pending_cnt; i++)
962                 expr__del_id(root_metric->pctx, pending[i].key);
963
964         /*
965          * Recursively add all the metrics, IDs are added to the root metric's
966          * context.
967          */
968         for (i = 0; i < pending_cnt; i++) {
969                 ret = add_metric(metric_list, &pending[i].pe, modifier, metric_no_group,
970                                  user_requested_cpu_list, system_wide, root_metric, visited,
971                                  table);
972                 if (ret)
973                         break;
974         }
975
976         free(pending);
977         return ret;
978 }
979
980 /**
981  * __add_metric - Add a metric to metric_list.
982  * @metric_list: The list the metric is added to.
983  * @pe: The pmu_event containing the metric to be added.
984  * @modifier: if non-null event modifiers like "u".
985  * @metric_no_group: Should events written to events be grouped "{}" or
986  *                   global. Grouping is the default but due to multiplexing the
987  *                   user may override.
988  * @runtime: A special argument for the parser only known at runtime.
989  * @user_requested_cpu_list: Command line specified CPUs to record on.
990  * @system_wide: Are events for all processes recorded.
991  * @root_metric: Metrics may reference other metrics to form a tree. In this
992  *               case the root_metric holds all the IDs and a list of referenced
993  *               metrics. When adding a root this argument is NULL.
994  * @visited: A singly linked list of metric names being added that is used to
995  *           detect recursion.
996  * @table: The table that is searched for metrics, most commonly the table for the
997  *       architecture perf is running upon.
998  */
999 static int __add_metric(struct list_head *metric_list,
1000                         const struct pmu_event *pe,
1001                         const char *modifier,
1002                         bool metric_no_group,
1003                         int runtime,
1004                         const char *user_requested_cpu_list,
1005                         bool system_wide,
1006                         struct metric *root_metric,
1007                         const struct visited_metric *visited,
1008                         const struct pmu_events_table *table)
1009 {
1010         const struct visited_metric *vm;
1011         int ret;
1012         bool is_root = !root_metric;
1013         struct visited_metric visited_node = {
1014                 .name = pe->metric_name,
1015                 .parent = visited,
1016         };
1017
1018         for (vm = visited; vm; vm = vm->parent) {
1019                 if (!strcmp(pe->metric_name, vm->name)) {
1020                         pr_err("failed: recursion detected for %s\n", pe->metric_name);
1021                         return -1;
1022                 }
1023         }
1024
1025         if (is_root) {
1026                 /*
1027                  * This metric is the root of a tree and may reference other
1028                  * metrics that are added recursively.
1029                  */
1030                 root_metric = metric__new(pe, modifier, metric_no_group, runtime,
1031                                           user_requested_cpu_list, system_wide);
1032                 if (!root_metric)
1033                         return -ENOMEM;
1034
1035         } else {
1036                 int cnt = 0;
1037
1038                 /*
1039                  * This metric was referenced in a metric higher in the
1040                  * tree. Check if the same metric is already resolved in the
1041                  * metric_refs list.
1042                  */
1043                 if (root_metric->metric_refs) {
1044                         for (; root_metric->metric_refs[cnt].metric_name; cnt++) {
1045                                 if (!strcmp(pe->metric_name,
1046                                             root_metric->metric_refs[cnt].metric_name))
1047                                         return 0;
1048                         }
1049                 }
1050
1051                 /* Create reference. Need space for the entry and the terminator. */
1052                 root_metric->metric_refs = realloc(root_metric->metric_refs,
1053                                                 (cnt + 2) * sizeof(struct metric_ref));
1054                 if (!root_metric->metric_refs)
1055                         return -ENOMEM;
1056
1057                 /*
1058                  * Intentionally passing just const char pointers,
1059                  * from 'pe' object, so they never go away. We don't
1060                  * need to change them, so there's no need to create
1061                  * our own copy.
1062                  */
1063                 root_metric->metric_refs[cnt].metric_name = pe->metric_name;
1064                 root_metric->metric_refs[cnt].metric_expr = pe->metric_expr;
1065
1066                 /* Null terminate array. */
1067                 root_metric->metric_refs[cnt+1].metric_name = NULL;
1068                 root_metric->metric_refs[cnt+1].metric_expr = NULL;
1069         }
1070
1071         /*
1072          * For both the parent and referenced metrics, we parse
1073          * all the metric's IDs and add it to the root context.
1074          */
1075         if (expr__find_ids(pe->metric_expr, NULL, root_metric->pctx) < 0) {
1076                 /* Broken metric. */
1077                 ret = -EINVAL;
1078         } else {
1079                 /* Resolve referenced metrics. */
1080                 ret = resolve_metric(metric_list, modifier, metric_no_group,
1081                                      user_requested_cpu_list, system_wide,
1082                                      root_metric, &visited_node, table);
1083         }
1084
1085         if (ret) {
1086                 if (is_root)
1087                         metric__free(root_metric);
1088
1089         } else if (is_root)
1090                 list_add(&root_metric->nd, metric_list);
1091
1092         return ret;
1093 }
1094
1095 struct metricgroup__find_metric_data {
1096         const char *metric;
1097         struct pmu_event *pe;
1098 };
1099
1100 static int metricgroup__find_metric_callback(const struct pmu_event *pe,
1101                                              const struct pmu_events_table *table  __maybe_unused,
1102                                              void *vdata)
1103 {
1104         struct metricgroup__find_metric_data *data = vdata;
1105
1106         if (!match_metric(pe->metric_name, data->metric))
1107                 return 0;
1108
1109         memcpy(data->pe, pe, sizeof(*pe));
1110         return 1;
1111 }
1112
1113 static bool metricgroup__find_metric(const char *metric,
1114                                      const struct pmu_events_table *table,
1115                                      struct pmu_event *pe)
1116 {
1117         struct metricgroup__find_metric_data data = {
1118                 .metric = metric,
1119                 .pe = pe,
1120         };
1121
1122         return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
1123                 ? true : false;
1124 }
1125
1126 static int add_metric(struct list_head *metric_list,
1127                       const struct pmu_event *pe,
1128                       const char *modifier,
1129                       bool metric_no_group,
1130                       const char *user_requested_cpu_list,
1131                       bool system_wide,
1132                       struct metric *root_metric,
1133                       const struct visited_metric *visited,
1134                       const struct pmu_events_table *table)
1135 {
1136         int ret = 0;
1137
1138         pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
1139
1140         if (!strstr(pe->metric_expr, "?")) {
1141                 ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
1142                                    user_requested_cpu_list, system_wide, root_metric,
1143                                    visited, table);
1144         } else {
1145                 int j, count;
1146
1147                 count = arch_get_runtimeparam(pe);
1148
1149                 /* This loop is added to create multiple
1150                  * events depend on count value and add
1151                  * those events to metric_list.
1152                  */
1153
1154                 for (j = 0; j < count && !ret; j++)
1155                         ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
1156                                            user_requested_cpu_list, system_wide,
1157                                            root_metric, visited, table);
1158         }
1159
1160         return ret;
1161 }
1162
1163 static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
1164                                                 const struct pmu_events_table *table __maybe_unused,
1165                                                 void *data)
1166 {
1167         struct metricgroup_add_iter_data *d = data;
1168         int ret;
1169
1170         if (!match_pe_metric(pe, d->metric_name))
1171                 return 0;
1172
1173         ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
1174                          d->user_requested_cpu_list, d->system_wide,
1175                          d->root_metric, d->visited, d->table);
1176         if (ret)
1177                 goto out;
1178
1179         *(d->has_match) = true;
1180
1181 out:
1182         *(d->ret) = ret;
1183         return ret;
1184 }
1185
1186 /**
1187  * metric_list_cmp - list_sort comparator that sorts metrics with more events to
1188  *                   the front. tool events are excluded from the count.
1189  */
1190 static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
1191                            const struct list_head *r)
1192 {
1193         const struct metric *left = container_of(l, struct metric, nd);
1194         const struct metric *right = container_of(r, struct metric, nd);
1195         struct expr_id_data *data;
1196         int i, left_count, right_count;
1197
1198         left_count = hashmap__size(left->pctx->ids);
1199         perf_tool_event__for_each_event(i) {
1200                 if (!expr__get_id(left->pctx, perf_tool_event__to_str(i), &data))
1201                         left_count--;
1202         }
1203
1204         right_count = hashmap__size(right->pctx->ids);
1205         perf_tool_event__for_each_event(i) {
1206                 if (!expr__get_id(right->pctx, perf_tool_event__to_str(i), &data))
1207                         right_count--;
1208         }
1209
1210         return right_count - left_count;
1211 }
1212
1213 struct metricgroup__add_metric_data {
1214         struct list_head *list;
1215         const char *metric_name;
1216         const char *modifier;
1217         const char *user_requested_cpu_list;
1218         bool metric_no_group;
1219         bool system_wide;
1220         bool has_match;
1221 };
1222
1223 static int metricgroup__add_metric_callback(const struct pmu_event *pe,
1224                                             const struct pmu_events_table *table,
1225                                             void *vdata)
1226 {
1227         struct metricgroup__add_metric_data *data = vdata;
1228         int ret = 0;
1229
1230         if (pe->metric_expr &&
1231                 (match_metric(pe->metric_group, data->metric_name) ||
1232                  match_metric(pe->metric_name, data->metric_name))) {
1233
1234                 data->has_match = true;
1235                 ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
1236                                  data->user_requested_cpu_list, data->system_wide,
1237                                  /*root_metric=*/NULL, /*visited_metrics=*/NULL, table);
1238         }
1239         return ret;
1240 }
1241
1242 /**
1243  * metricgroup__add_metric - Find and add a metric, or a metric group.
1244  * @metric_name: The name of the metric or metric group. For example, "IPC"
1245  *               could be the name of a metric and "TopDownL1" the name of a
1246  *               metric group.
1247  * @modifier: if non-null event modifiers like "u".
1248  * @metric_no_group: Should events written to events be grouped "{}" or
1249  *                   global. Grouping is the default but due to multiplexing the
1250  *                   user may override.
1251  * @user_requested_cpu_list: Command line specified CPUs to record on.
1252  * @system_wide: Are events for all processes recorded.
1253  * @metric_list: The list that the metric or metric group are added to.
1254  * @table: The table that is searched for metrics, most commonly the table for the
1255  *       architecture perf is running upon.
1256  */
1257 static int metricgroup__add_metric(const char *metric_name, const char *modifier,
1258                                    bool metric_no_group,
1259                                    const char *user_requested_cpu_list,
1260                                    bool system_wide,
1261                                    struct list_head *metric_list,
1262                                    const struct pmu_events_table *table)
1263 {
1264         LIST_HEAD(list);
1265         int ret;
1266         bool has_match = false;
1267
1268         {
1269                 struct metricgroup__add_metric_data data = {
1270                         .list = &list,
1271                         .metric_name = metric_name,
1272                         .modifier = modifier,
1273                         .metric_no_group = metric_no_group,
1274                         .user_requested_cpu_list = user_requested_cpu_list,
1275                         .system_wide = system_wide,
1276                         .has_match = false,
1277                 };
1278                 /*
1279                  * Iterate over all metrics seeing if metric matches either the
1280                  * name or group. When it does add the metric to the list.
1281                  */
1282                 ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
1283                                                       &data);
1284                 if (ret)
1285                         goto out;
1286
1287                 has_match = data.has_match;
1288         }
1289         {
1290                 struct metricgroup_iter_data data = {
1291                         .fn = metricgroup__add_metric_sys_event_iter,
1292                         .data = (void *) &(struct metricgroup_add_iter_data) {
1293                                 .metric_list = &list,
1294                                 .metric_name = metric_name,
1295                                 .modifier = modifier,
1296                                 .metric_no_group = metric_no_group,
1297                                 .user_requested_cpu_list = user_requested_cpu_list,
1298                                 .system_wide = system_wide,
1299                                 .has_match = &has_match,
1300                                 .ret = &ret,
1301                                 .table = table,
1302                         },
1303                 };
1304
1305                 pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
1306         }
1307         /* End of pmu events. */
1308         if (!has_match)
1309                 ret = -EINVAL;
1310
1311 out:
1312         /*
1313          * add to metric_list so that they can be released
1314          * even if it's failed
1315          */
1316         list_splice(&list, metric_list);
1317         return ret;
1318 }
1319
1320 /**
1321  * metricgroup__add_metric_list - Find and add metrics, or metric groups,
1322  *                                specified in a list.
1323  * @list: the list of metrics or metric groups. For example, "IPC,CPI,TopDownL1"
1324  *        would match the IPC and CPI metrics, and TopDownL1 would match all
1325  *        the metrics in the TopDownL1 group.
1326  * @metric_no_group: Should events written to events be grouped "{}" or
1327  *                   global. Grouping is the default but due to multiplexing the
1328  *                   user may override.
1329  * @user_requested_cpu_list: Command line specified CPUs to record on.
1330  * @system_wide: Are events for all processes recorded.
1331  * @metric_list: The list that metrics are added to.
1332  * @table: The table that is searched for metrics, most commonly the table for the
1333  *       architecture perf is running upon.
1334  */
1335 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
1336                                         const char *user_requested_cpu_list,
1337                                         bool system_wide, struct list_head *metric_list,
1338                                         const struct pmu_events_table *table)
1339 {
1340         char *list_itr, *list_copy, *metric_name, *modifier;
1341         int ret, count = 0;
1342
1343         list_copy = strdup(list);
1344         if (!list_copy)
1345                 return -ENOMEM;
1346         list_itr = list_copy;
1347
1348         while ((metric_name = strsep(&list_itr, ",")) != NULL) {
1349                 modifier = strchr(metric_name, ':');
1350                 if (modifier)
1351                         *modifier++ = '\0';
1352
1353                 ret = metricgroup__add_metric(metric_name, modifier,
1354                                               metric_no_group, user_requested_cpu_list,
1355                                               system_wide, metric_list, table);
1356                 if (ret == -EINVAL)
1357                         pr_err("Cannot find metric or group `%s'\n", metric_name);
1358
1359                 if (ret)
1360                         break;
1361
1362                 count++;
1363         }
1364         free(list_copy);
1365
1366         if (!ret) {
1367                 /*
1368                  * Warn about nmi_watchdog if any parsed metrics had the
1369                  * NO_NMI_WATCHDOG constraint.
1370                  */
1371                 metricgroup___watchdog_constraint_hint(NULL, true);
1372                 /* No metrics. */
1373                 if (count == 0)
1374                         return -EINVAL;
1375         }
1376         return ret;
1377 }
1378
1379 static void metricgroup__free_metrics(struct list_head *metric_list)
1380 {
1381         struct metric *m, *tmp;
1382
1383         list_for_each_entry_safe (m, tmp, metric_list, nd) {
1384                 list_del_init(&m->nd);
1385                 metric__free(m);
1386         }
1387 }
1388
1389 /**
1390  * find_tool_events - Search for the pressence of tool events in metric_list.
1391  * @metric_list: List to take metrics from.
1392  * @tool_events: Array of false values, indices corresponding to tool events set
1393  *               to true if tool event is found.
1394  */
1395 static void find_tool_events(const struct list_head *metric_list,
1396                              bool tool_events[PERF_TOOL_MAX])
1397 {
1398         struct metric *m;
1399
1400         list_for_each_entry(m, metric_list, nd) {
1401                 int i;
1402
1403                 perf_tool_event__for_each_event(i) {
1404                         struct expr_id_data *data;
1405
1406                         if (!tool_events[i] &&
1407                             !expr__get_id(m->pctx, perf_tool_event__to_str(i), &data))
1408                                 tool_events[i] = true;
1409                 }
1410         }
1411 }
1412
1413 /**
1414  * build_combined_expr_ctx - Make an expr_parse_ctx with all has_constraint
1415  *                           metric IDs, as the IDs are held in a set,
1416  *                           duplicates will be removed.
1417  * @metric_list: List to take metrics from.
1418  * @combined: Out argument for result.
1419  */
1420 static int build_combined_expr_ctx(const struct list_head *metric_list,
1421                                    struct expr_parse_ctx **combined)
1422 {
1423         struct hashmap_entry *cur;
1424         size_t bkt;
1425         struct metric *m;
1426         char *dup;
1427         int ret;
1428
1429         *combined = expr__ctx_new();
1430         if (!*combined)
1431                 return -ENOMEM;
1432
1433         list_for_each_entry(m, metric_list, nd) {
1434                 if (m->has_constraint && !m->modifier) {
1435                         hashmap__for_each_entry(m->pctx->ids, cur, bkt) {
1436                                 dup = strdup(cur->key);
1437                                 if (!dup) {
1438                                         ret = -ENOMEM;
1439                                         goto err_out;
1440                                 }
1441                                 ret = expr__add_id(*combined, dup);
1442                                 if (ret)
1443                                         goto err_out;
1444                         }
1445                 }
1446         }
1447         return 0;
1448 err_out:
1449         expr__ctx_free(*combined);
1450         *combined = NULL;
1451         return ret;
1452 }
1453
1454 /**
1455  * parse_ids - Build the event string for the ids and parse them creating an
1456  *             evlist. The encoded metric_ids are decoded.
1457  * @metric_no_merge: is metric sharing explicitly disabled.
1458  * @fake_pmu: used when testing metrics not supported by the current CPU.
1459  * @ids: the event identifiers parsed from a metric.
1460  * @modifier: any modifiers added to the events.
1461  * @has_constraint: false if events should be placed in a weak group.
1462  * @tool_events: entries set true if the tool event of index could be present in
1463  *               the overall list of metrics.
1464  * @out_evlist: the created list of events.
1465  */
1466 static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu,
1467                      struct expr_parse_ctx *ids, const char *modifier,
1468                      bool has_constraint, const bool tool_events[PERF_TOOL_MAX],
1469                      struct evlist **out_evlist)
1470 {
1471         struct parse_events_error parse_error;
1472         struct evlist *parsed_evlist;
1473         struct strbuf events = STRBUF_INIT;
1474         int ret;
1475
1476         *out_evlist = NULL;
1477         if (!metric_no_merge || hashmap__size(ids->ids) == 0) {
1478                 bool added_event = false;
1479                 int i;
1480                 /*
1481                  * We may fail to share events between metrics because a tool
1482                  * event isn't present in one metric. For example, a ratio of
1483                  * cache misses doesn't need duration_time but the same events
1484                  * may be used for a misses per second. Events without sharing
1485                  * implies multiplexing, that is best avoided, so place
1486                  * all tool events in every group.
1487                  *
1488                  * Also, there may be no ids/events in the expression parsing
1489                  * context because of constant evaluation, e.g.:
1490                  *    event1 if #smt_on else 0
1491                  * Add a tool event to avoid a parse error on an empty string.
1492                  */
1493                 perf_tool_event__for_each_event(i) {
1494                         if (tool_events[i]) {
1495                                 char *tmp = strdup(perf_tool_event__to_str(i));
1496
1497                                 if (!tmp)
1498                                         return -ENOMEM;
1499                                 ids__insert(ids->ids, tmp);
1500                                 added_event = true;
1501                         }
1502                 }
1503                 if (!added_event && hashmap__size(ids->ids) == 0) {
1504                         char *tmp = strdup("duration_time");
1505
1506                         if (!tmp)
1507                                 return -ENOMEM;
1508                         ids__insert(ids->ids, tmp);
1509                 }
1510         }
1511         ret = metricgroup__build_event_string(&events, ids, modifier,
1512                                               has_constraint);
1513         if (ret)
1514                 return ret;
1515
1516         parsed_evlist = evlist__new();
1517         if (!parsed_evlist) {
1518                 ret = -ENOMEM;
1519                 goto err_out;
1520         }
1521         pr_debug("Parsing metric events '%s'\n", events.buf);
1522         parse_events_error__init(&parse_error);
1523         ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu);
1524         if (ret) {
1525                 parse_events_error__print(&parse_error, events.buf);
1526                 goto err_out;
1527         }
1528         ret = decode_all_metric_ids(parsed_evlist, modifier);
1529         if (ret)
1530                 goto err_out;
1531
1532         *out_evlist = parsed_evlist;
1533         parsed_evlist = NULL;
1534 err_out:
1535         parse_events_error__exit(&parse_error);
1536         evlist__delete(parsed_evlist);
1537         strbuf_release(&events);
1538         return ret;
1539 }
1540
1541 static int parse_groups(struct evlist *perf_evlist, const char *str,
1542                         bool metric_no_group,
1543                         bool metric_no_merge,
1544                         const char *user_requested_cpu_list,
1545                         bool system_wide,
1546                         struct perf_pmu *fake_pmu,
1547                         struct rblist *metric_events_list,
1548                         const struct pmu_events_table *table)
1549 {
1550         struct evlist *combined_evlist = NULL;
1551         LIST_HEAD(metric_list);
1552         struct metric *m;
1553         bool tool_events[PERF_TOOL_MAX] = {false};
1554         int ret;
1555
1556         if (metric_events_list->nr_entries == 0)
1557                 metricgroup__rblist_init(metric_events_list);
1558         ret = metricgroup__add_metric_list(str, metric_no_group,
1559                                            user_requested_cpu_list,
1560                                            system_wide, &metric_list, table);
1561         if (ret)
1562                 goto out;
1563
1564         /* Sort metrics from largest to smallest. */
1565         list_sort(NULL, &metric_list, metric_list_cmp);
1566
1567         if (!metric_no_merge) {
1568                 struct expr_parse_ctx *combined = NULL;
1569
1570                 find_tool_events(&metric_list, tool_events);
1571
1572                 ret = build_combined_expr_ctx(&metric_list, &combined);
1573
1574                 if (!ret && combined && hashmap__size(combined->ids)) {
1575                         ret = parse_ids(metric_no_merge, fake_pmu, combined,
1576                                         /*modifier=*/NULL,
1577                                         /*has_constraint=*/true,
1578                                         tool_events,
1579                                         &combined_evlist);
1580                 }
1581                 if (combined)
1582                         expr__ctx_free(combined);
1583
1584                 if (ret)
1585                         goto out;
1586         }
1587
1588         list_for_each_entry(m, &metric_list, nd) {
1589                 struct metric_event *me;
1590                 struct evsel **metric_events;
1591                 struct evlist *metric_evlist = NULL;
1592                 struct metric *n;
1593                 struct metric_expr *expr;
1594
1595                 if (combined_evlist && m->has_constraint) {
1596                         metric_evlist = combined_evlist;
1597                 } else if (!metric_no_merge) {
1598                         /*
1599                          * See if the IDs for this metric are a subset of an
1600                          * earlier metric.
1601                          */
1602                         list_for_each_entry(n, &metric_list, nd) {
1603                                 if (m == n)
1604                                         break;
1605
1606                                 if (n->evlist == NULL)
1607                                         continue;
1608
1609                                 if ((!m->modifier && n->modifier) ||
1610                                     (m->modifier && !n->modifier) ||
1611                                     (m->modifier && n->modifier &&
1612                                             strcmp(m->modifier, n->modifier)))
1613                                         continue;
1614
1615                                 if (expr__subset_of_ids(n->pctx, m->pctx)) {
1616                                         pr_debug("Events in '%s' fully contained within '%s'\n",
1617                                                  m->metric_name, n->metric_name);
1618                                         metric_evlist = n->evlist;
1619                                         break;
1620                                 }
1621
1622                         }
1623                 }
1624                 if (!metric_evlist) {
1625                         ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier,
1626                                         m->has_constraint, tool_events, &m->evlist);
1627                         if (ret)
1628                                 goto out;
1629
1630                         metric_evlist = m->evlist;
1631                 }
1632                 ret = setup_metric_events(m->pctx->ids, metric_evlist, &metric_events);
1633                 if (ret) {
1634                         pr_debug("Cannot resolve IDs for %s: %s\n",
1635                                 m->metric_name, m->metric_expr);
1636                         goto out;
1637                 }
1638
1639                 me = metricgroup__lookup(metric_events_list, metric_events[0], true);
1640
1641                 expr = malloc(sizeof(struct metric_expr));
1642                 if (!expr) {
1643                         ret = -ENOMEM;
1644                         free(metric_events);
1645                         goto out;
1646                 }
1647
1648                 expr->metric_refs = m->metric_refs;
1649                 m->metric_refs = NULL;
1650                 expr->metric_expr = m->metric_expr;
1651                 if (m->modifier) {
1652                         char *tmp;
1653
1654                         if (asprintf(&tmp, "%s:%s", m->metric_name, m->modifier) < 0)
1655                                 expr->metric_name = NULL;
1656                         else
1657                                 expr->metric_name = tmp;
1658                 } else
1659                         expr->metric_name = strdup(m->metric_name);
1660
1661                 if (!expr->metric_name) {
1662                         ret = -ENOMEM;
1663                         free(metric_events);
1664                         goto out;
1665                 }
1666                 expr->metric_unit = m->metric_unit;
1667                 expr->metric_events = metric_events;
1668                 expr->runtime = m->pctx->sctx.runtime;
1669                 list_add(&expr->nd, &me->head);
1670         }
1671
1672
1673         if (combined_evlist) {
1674                 evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
1675                 evlist__delete(combined_evlist);
1676         }
1677
1678         list_for_each_entry(m, &metric_list, nd) {
1679                 if (m->evlist)
1680                         evlist__splice_list_tail(perf_evlist, &m->evlist->core.entries);
1681         }
1682
1683 out:
1684         metricgroup__free_metrics(&metric_list);
1685         return ret;
1686 }
1687
1688 int metricgroup__parse_groups(struct evlist *perf_evlist,
1689                               const char *str,
1690                               bool metric_no_group,
1691                               bool metric_no_merge,
1692                               const char *user_requested_cpu_list,
1693                               bool system_wide,
1694                               struct rblist *metric_events)
1695 {
1696         const struct pmu_events_table *table = pmu_events_table__find();
1697
1698         if (!table)
1699                 return -EINVAL;
1700
1701         return parse_groups(perf_evlist, str, metric_no_group, metric_no_merge,
1702                             user_requested_cpu_list, system_wide,
1703                             /*fake_pmu=*/NULL, metric_events, table);
1704 }
1705
1706 int metricgroup__parse_groups_test(struct evlist *evlist,
1707                                    const struct pmu_events_table *table,
1708                                    const char *str,
1709                                    bool metric_no_group,
1710                                    bool metric_no_merge,
1711                                    struct rblist *metric_events)
1712 {
1713         return parse_groups(evlist, str, metric_no_group, metric_no_merge,
1714                             /*user_requested_cpu_list=*/NULL,
1715                             /*system_wide=*/false,
1716                             &perf_pmu__fake, metric_events, table);
1717 }
1718
1719 static int metricgroup__has_metric_callback(const struct pmu_event *pe,
1720                                             const struct pmu_events_table *table __maybe_unused,
1721                                             void *vdata)
1722 {
1723         const char *metric = vdata;
1724
1725         if (!pe->metric_expr)
1726                 return 0;
1727
1728         if (match_metric(pe->metric_name, metric))
1729                 return 1;
1730
1731         return 0;
1732 }
1733
1734 bool metricgroup__has_metric(const char *metric)
1735 {
1736         const struct pmu_events_table *table = pmu_events_table__find();
1737
1738         if (!table)
1739                 return false;
1740
1741         return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
1742                                                (void *)metric) ? true : false;
1743 }
1744
1745 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
1746                                     struct rblist *new_metric_events,
1747                                     struct rblist *old_metric_events)
1748 {
1749         unsigned int i;
1750
1751         for (i = 0; i < rblist__nr_entries(old_metric_events); i++) {
1752                 struct rb_node *nd;
1753                 struct metric_event *old_me, *new_me;
1754                 struct metric_expr *old_expr, *new_expr;
1755                 struct evsel *evsel;
1756                 size_t alloc_size;
1757                 int idx, nr;
1758
1759                 nd = rblist__entry(old_metric_events, i);
1760                 old_me = container_of(nd, struct metric_event, nd);
1761
1762                 evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx);
1763                 if (!evsel)
1764                         return -EINVAL;
1765                 new_me = metricgroup__lookup(new_metric_events, evsel, true);
1766                 if (!new_me)
1767                         return -ENOMEM;
1768
1769                 pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n",
1770                          cgrp ? cgrp->name : "root", evsel->name, evsel->core.idx);
1771
1772                 list_for_each_entry(old_expr, &old_me->head, nd) {
1773                         new_expr = malloc(sizeof(*new_expr));
1774                         if (!new_expr)
1775                                 return -ENOMEM;
1776
1777                         new_expr->metric_expr = old_expr->metric_expr;
1778                         new_expr->metric_name = strdup(old_expr->metric_name);
1779                         if (!new_expr->metric_name)
1780                                 return -ENOMEM;
1781
1782                         new_expr->metric_unit = old_expr->metric_unit;
1783                         new_expr->runtime = old_expr->runtime;
1784
1785                         if (old_expr->metric_refs) {
1786                                 /* calculate number of metric_events */
1787                                 for (nr = 0; old_expr->metric_refs[nr].metric_name; nr++)
1788                                         continue;
1789                                 alloc_size = sizeof(*new_expr->metric_refs);
1790                                 new_expr->metric_refs = calloc(nr + 1, alloc_size);
1791                                 if (!new_expr->metric_refs) {
1792                                         free(new_expr);
1793                                         return -ENOMEM;
1794                                 }
1795
1796                                 memcpy(new_expr->metric_refs, old_expr->metric_refs,
1797                                        nr * alloc_size);
1798                         } else {
1799                                 new_expr->metric_refs = NULL;
1800                         }
1801
1802                         /* calculate number of metric_events */
1803                         for (nr = 0; old_expr->metric_events[nr]; nr++)
1804                                 continue;
1805                         alloc_size = sizeof(*new_expr->metric_events);
1806                         new_expr->metric_events = calloc(nr + 1, alloc_size);
1807                         if (!new_expr->metric_events) {
1808                                 free(new_expr->metric_refs);
1809                                 free(new_expr);
1810                                 return -ENOMEM;
1811                         }
1812
1813                         /* copy evsel in the same position */
1814                         for (idx = 0; idx < nr; idx++) {
1815                                 evsel = old_expr->metric_events[idx];
1816                                 evsel = evlist__find_evsel(evlist, evsel->core.idx);
1817                                 if (evsel == NULL) {
1818                                         free(new_expr->metric_events);
1819                                         free(new_expr->metric_refs);
1820                                         free(new_expr);
1821                                         return -EINVAL;
1822                                 }
1823                                 new_expr->metric_events[idx] = evsel;
1824                         }
1825
1826                         list_add(&new_expr->nd, &new_me->head);
1827                 }
1828         }
1829         return 0;
1830 }
This page took 0.14967 seconds and 4 git commands to generate.