1b18f3e36SAndi Kleen /* 2b18f3e36SAndi Kleen * Copyright (c) 2017, Intel Corporation. 3b18f3e36SAndi Kleen * 4b18f3e36SAndi Kleen * This program is free software; you can redistribute it and/or modify it 5b18f3e36SAndi Kleen * under the terms and conditions of the GNU General Public License, 6b18f3e36SAndi Kleen * version 2, as published by the Free Software Foundation. 7b18f3e36SAndi Kleen * 8b18f3e36SAndi Kleen * This program is distributed in the hope it will be useful, but WITHOUT 9b18f3e36SAndi Kleen * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10b18f3e36SAndi Kleen * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11b18f3e36SAndi Kleen * more details. 12b18f3e36SAndi Kleen * 13b18f3e36SAndi Kleen */ 14b18f3e36SAndi Kleen 15b18f3e36SAndi Kleen /* Manage metrics and groups of metrics from JSON files */ 16b18f3e36SAndi Kleen 17b18f3e36SAndi Kleen #include "metricgroup.h" 18b18f3e36SAndi Kleen #include "evlist.h" 19b18f3e36SAndi Kleen #include "strbuf.h" 20b18f3e36SAndi Kleen #include "pmu.h" 21b18f3e36SAndi Kleen #include "expr.h" 22b18f3e36SAndi Kleen #include "rblist.h" 23b18f3e36SAndi Kleen #include <string.h> 24b18f3e36SAndi Kleen #include <stdbool.h> 25b18f3e36SAndi Kleen #include <errno.h> 26b18f3e36SAndi Kleen #include "pmu-events/pmu-events.h" 27b18f3e36SAndi Kleen #include "strlist.h" 28b18f3e36SAndi Kleen #include <assert.h> 29b18f3e36SAndi Kleen #include <ctype.h> 30b18f3e36SAndi Kleen 31b18f3e36SAndi Kleen struct metric_event *metricgroup__lookup(struct rblist *metric_events, 32b18f3e36SAndi Kleen struct perf_evsel *evsel, 33b18f3e36SAndi Kleen bool create) 34b18f3e36SAndi Kleen { 35b18f3e36SAndi Kleen struct rb_node *nd; 36b18f3e36SAndi Kleen struct metric_event me = { 37b18f3e36SAndi Kleen .evsel = evsel 38b18f3e36SAndi Kleen }; 394bd1bef8SAndi Kleen 404bd1bef8SAndi Kleen if (!metric_events) 414bd1bef8SAndi Kleen return NULL; 424bd1bef8SAndi Kleen 43b18f3e36SAndi Kleen nd = rblist__find(metric_events, &me); 44b18f3e36SAndi Kleen if (nd) 45b18f3e36SAndi Kleen return container_of(nd, struct metric_event, nd); 46b18f3e36SAndi Kleen if (create) { 47b18f3e36SAndi Kleen rblist__add_node(metric_events, &me); 48b18f3e36SAndi Kleen nd = rblist__find(metric_events, &me); 49b18f3e36SAndi Kleen if (nd) 50b18f3e36SAndi Kleen return container_of(nd, struct metric_event, nd); 51b18f3e36SAndi Kleen } 52b18f3e36SAndi Kleen return NULL; 53b18f3e36SAndi Kleen } 54b18f3e36SAndi Kleen 55b18f3e36SAndi Kleen static int metric_event_cmp(struct rb_node *rb_node, const void *entry) 56b18f3e36SAndi Kleen { 57b18f3e36SAndi Kleen struct metric_event *a = container_of(rb_node, 58b18f3e36SAndi Kleen struct metric_event, 59b18f3e36SAndi Kleen nd); 60b18f3e36SAndi Kleen const struct metric_event *b = entry; 61b18f3e36SAndi Kleen 62b18f3e36SAndi Kleen if (a->evsel == b->evsel) 63b18f3e36SAndi Kleen return 0; 64b18f3e36SAndi Kleen if ((char *)a->evsel < (char *)b->evsel) 65b18f3e36SAndi Kleen return -1; 66b18f3e36SAndi Kleen return +1; 67b18f3e36SAndi Kleen } 68b18f3e36SAndi Kleen 69b18f3e36SAndi Kleen static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused, 70b18f3e36SAndi Kleen const void *entry) 71b18f3e36SAndi Kleen { 72b18f3e36SAndi Kleen struct metric_event *me = malloc(sizeof(struct metric_event)); 73b18f3e36SAndi Kleen 74b18f3e36SAndi Kleen if (!me) 75b18f3e36SAndi Kleen return NULL; 76b18f3e36SAndi Kleen memcpy(me, entry, sizeof(struct metric_event)); 77b18f3e36SAndi Kleen me->evsel = ((struct metric_event *)entry)->evsel; 78b18f3e36SAndi Kleen INIT_LIST_HEAD(&me->head); 79b18f3e36SAndi Kleen return &me->nd; 80b18f3e36SAndi Kleen } 81b18f3e36SAndi Kleen 82b18f3e36SAndi Kleen static void metricgroup__rblist_init(struct rblist *metric_events) 83b18f3e36SAndi Kleen { 84b18f3e36SAndi Kleen rblist__init(metric_events); 85b18f3e36SAndi Kleen metric_events->node_cmp = metric_event_cmp; 86b18f3e36SAndi Kleen metric_events->node_new = metric_event_new; 87b18f3e36SAndi Kleen } 88b18f3e36SAndi Kleen 89b18f3e36SAndi Kleen struct egroup { 90b18f3e36SAndi Kleen struct list_head nd; 91b18f3e36SAndi Kleen int idnum; 92b18f3e36SAndi Kleen const char **ids; 93b18f3e36SAndi Kleen const char *metric_name; 94b18f3e36SAndi Kleen const char *metric_expr; 95b18f3e36SAndi Kleen }; 96b18f3e36SAndi Kleen 97b18f3e36SAndi Kleen static struct perf_evsel *find_evsel(struct perf_evlist *perf_evlist, 98b18f3e36SAndi Kleen const char **ids, 99b18f3e36SAndi Kleen int idnum, 100b18f3e36SAndi Kleen struct perf_evsel **metric_events) 101b18f3e36SAndi Kleen { 102b18f3e36SAndi Kleen struct perf_evsel *ev, *start = NULL; 103b18f3e36SAndi Kleen int ind = 0; 104b18f3e36SAndi Kleen 105b18f3e36SAndi Kleen evlist__for_each_entry (perf_evlist, ev) { 106b18f3e36SAndi Kleen if (!strcmp(ev->name, ids[ind])) { 107b18f3e36SAndi Kleen metric_events[ind] = ev; 108b18f3e36SAndi Kleen if (ind == 0) 109b18f3e36SAndi Kleen start = ev; 110b18f3e36SAndi Kleen if (++ind == idnum) { 111b18f3e36SAndi Kleen metric_events[ind] = NULL; 112b18f3e36SAndi Kleen return start; 113b18f3e36SAndi Kleen } 114b18f3e36SAndi Kleen } else { 115b18f3e36SAndi Kleen ind = 0; 116b18f3e36SAndi Kleen start = NULL; 117b18f3e36SAndi Kleen } 118b18f3e36SAndi Kleen } 119b18f3e36SAndi Kleen /* 120b18f3e36SAndi Kleen * This can happen when an alias expands to multiple 121b18f3e36SAndi Kleen * events, like for uncore events. 122b18f3e36SAndi Kleen * We don't support this case for now. 123b18f3e36SAndi Kleen */ 124b18f3e36SAndi Kleen return NULL; 125b18f3e36SAndi Kleen } 126b18f3e36SAndi Kleen 127b18f3e36SAndi Kleen static int metricgroup__setup_events(struct list_head *groups, 128b18f3e36SAndi Kleen struct perf_evlist *perf_evlist, 129b18f3e36SAndi Kleen struct rblist *metric_events_list) 130b18f3e36SAndi Kleen { 131b18f3e36SAndi Kleen struct metric_event *me; 132b18f3e36SAndi Kleen struct metric_expr *expr; 133b18f3e36SAndi Kleen int i = 0; 134b18f3e36SAndi Kleen int ret = 0; 135b18f3e36SAndi Kleen struct egroup *eg; 136b18f3e36SAndi Kleen struct perf_evsel *evsel; 137b18f3e36SAndi Kleen 138b18f3e36SAndi Kleen list_for_each_entry (eg, groups, nd) { 139b18f3e36SAndi Kleen struct perf_evsel **metric_events; 140b18f3e36SAndi Kleen 141b18f3e36SAndi Kleen metric_events = calloc(sizeof(void *), eg->idnum + 1); 142b18f3e36SAndi Kleen if (!metric_events) { 143b18f3e36SAndi Kleen ret = -ENOMEM; 144b18f3e36SAndi Kleen break; 145b18f3e36SAndi Kleen } 146b18f3e36SAndi Kleen evsel = find_evsel(perf_evlist, eg->ids, eg->idnum, 147b18f3e36SAndi Kleen metric_events); 148b18f3e36SAndi Kleen if (!evsel) { 149b18f3e36SAndi Kleen pr_debug("Cannot resolve %s: %s\n", 150b18f3e36SAndi Kleen eg->metric_name, eg->metric_expr); 151b18f3e36SAndi Kleen continue; 152b18f3e36SAndi Kleen } 153b18f3e36SAndi Kleen for (i = 0; i < eg->idnum; i++) 154b18f3e36SAndi Kleen metric_events[i]->collect_stat = true; 155b18f3e36SAndi Kleen me = metricgroup__lookup(metric_events_list, evsel, true); 156b18f3e36SAndi Kleen if (!me) { 157b18f3e36SAndi Kleen ret = -ENOMEM; 158b18f3e36SAndi Kleen break; 159b18f3e36SAndi Kleen } 160b18f3e36SAndi Kleen expr = malloc(sizeof(struct metric_expr)); 161b18f3e36SAndi Kleen if (!expr) { 162b18f3e36SAndi Kleen ret = -ENOMEM; 163b18f3e36SAndi Kleen break; 164b18f3e36SAndi Kleen } 165b18f3e36SAndi Kleen expr->metric_expr = eg->metric_expr; 166b18f3e36SAndi Kleen expr->metric_name = eg->metric_name; 167b18f3e36SAndi Kleen expr->metric_events = metric_events; 168b18f3e36SAndi Kleen list_add(&expr->nd, &me->head); 169b18f3e36SAndi Kleen } 170b18f3e36SAndi Kleen return ret; 171b18f3e36SAndi Kleen } 172b18f3e36SAndi Kleen 173b18f3e36SAndi Kleen static bool match_metric(const char *n, const char *list) 174b18f3e36SAndi Kleen { 175b18f3e36SAndi Kleen int len; 176b18f3e36SAndi Kleen char *m; 177b18f3e36SAndi Kleen 178b18f3e36SAndi Kleen if (!list) 179b18f3e36SAndi Kleen return false; 180b18f3e36SAndi Kleen if (!strcmp(list, "all")) 181b18f3e36SAndi Kleen return true; 182b18f3e36SAndi Kleen if (!n) 183b18f3e36SAndi Kleen return !strcasecmp(list, "No_group"); 184b18f3e36SAndi Kleen len = strlen(list); 185b18f3e36SAndi Kleen m = strcasestr(n, list); 186b18f3e36SAndi Kleen if (!m) 187b18f3e36SAndi Kleen return false; 188b18f3e36SAndi Kleen if ((m == n || m[-1] == ';' || m[-1] == ' ') && 189b18f3e36SAndi Kleen (m[len] == 0 || m[len] == ';')) 190b18f3e36SAndi Kleen return true; 191b18f3e36SAndi Kleen return false; 192b18f3e36SAndi Kleen } 193b18f3e36SAndi Kleen 19471b0acceSAndi Kleen struct mep { 19571b0acceSAndi Kleen struct rb_node nd; 19671b0acceSAndi Kleen const char *name; 19771b0acceSAndi Kleen struct strlist *metrics; 19871b0acceSAndi Kleen }; 19971b0acceSAndi Kleen 20071b0acceSAndi Kleen static int mep_cmp(struct rb_node *rb_node, const void *entry) 20171b0acceSAndi Kleen { 20271b0acceSAndi Kleen struct mep *a = container_of(rb_node, struct mep, nd); 20371b0acceSAndi Kleen struct mep *b = (struct mep *)entry; 20471b0acceSAndi Kleen 20571b0acceSAndi Kleen return strcmp(a->name, b->name); 20671b0acceSAndi Kleen } 20771b0acceSAndi Kleen 20871b0acceSAndi Kleen static struct rb_node *mep_new(struct rblist *rl __maybe_unused, 20971b0acceSAndi Kleen const void *entry) 21071b0acceSAndi Kleen { 21171b0acceSAndi Kleen struct mep *me = malloc(sizeof(struct mep)); 21271b0acceSAndi Kleen 21371b0acceSAndi Kleen if (!me) 21471b0acceSAndi Kleen return NULL; 21571b0acceSAndi Kleen memcpy(me, entry, sizeof(struct mep)); 21671b0acceSAndi Kleen me->name = strdup(me->name); 21771b0acceSAndi Kleen if (!me->name) 21871b0acceSAndi Kleen goto out_me; 21971b0acceSAndi Kleen me->metrics = strlist__new(NULL, NULL); 22071b0acceSAndi Kleen if (!me->metrics) 22171b0acceSAndi Kleen goto out_name; 22271b0acceSAndi Kleen return &me->nd; 22371b0acceSAndi Kleen out_name: 22471b0acceSAndi Kleen free((char *)me->name); 22571b0acceSAndi Kleen out_me: 22671b0acceSAndi Kleen free(me); 22771b0acceSAndi Kleen return NULL; 22871b0acceSAndi Kleen } 22971b0acceSAndi Kleen 23071b0acceSAndi Kleen static struct mep *mep_lookup(struct rblist *groups, const char *name) 23171b0acceSAndi Kleen { 23271b0acceSAndi Kleen struct rb_node *nd; 23371b0acceSAndi Kleen struct mep me = { 23471b0acceSAndi Kleen .name = name 23571b0acceSAndi Kleen }; 23671b0acceSAndi Kleen nd = rblist__find(groups, &me); 23771b0acceSAndi Kleen if (nd) 23871b0acceSAndi Kleen return container_of(nd, struct mep, nd); 23971b0acceSAndi Kleen rblist__add_node(groups, &me); 24071b0acceSAndi Kleen nd = rblist__find(groups, &me); 24171b0acceSAndi Kleen if (nd) 24271b0acceSAndi Kleen return container_of(nd, struct mep, nd); 24371b0acceSAndi Kleen return NULL; 24471b0acceSAndi Kleen } 24571b0acceSAndi Kleen 24671b0acceSAndi Kleen static void mep_delete(struct rblist *rl __maybe_unused, 24771b0acceSAndi Kleen struct rb_node *nd) 24871b0acceSAndi Kleen { 24971b0acceSAndi Kleen struct mep *me = container_of(nd, struct mep, nd); 25071b0acceSAndi Kleen 25171b0acceSAndi Kleen strlist__delete(me->metrics); 25271b0acceSAndi Kleen free((void *)me->name); 25371b0acceSAndi Kleen free(me); 25471b0acceSAndi Kleen } 25571b0acceSAndi Kleen 25671b0acceSAndi Kleen static void metricgroup__print_strlist(struct strlist *metrics, bool raw) 25771b0acceSAndi Kleen { 25871b0acceSAndi Kleen struct str_node *sn; 25971b0acceSAndi Kleen int n = 0; 26071b0acceSAndi Kleen 26171b0acceSAndi Kleen strlist__for_each_entry (sn, metrics) { 26271b0acceSAndi Kleen if (raw) 26371b0acceSAndi Kleen printf("%s%s", n > 0 ? " " : "", sn->s); 26471b0acceSAndi Kleen else 26571b0acceSAndi Kleen printf(" %s\n", sn->s); 26671b0acceSAndi Kleen n++; 26771b0acceSAndi Kleen } 26871b0acceSAndi Kleen if (raw) 26971b0acceSAndi Kleen putchar('\n'); 27071b0acceSAndi Kleen } 27171b0acceSAndi Kleen 27271b0acceSAndi Kleen void metricgroup__print(bool metrics, bool metricgroups, char *filter, 27371b0acceSAndi Kleen bool raw) 27471b0acceSAndi Kleen { 27554e32dc0SGanapatrao Kulkarni struct pmu_events_map *map = perf_pmu__find_map(NULL); 27671b0acceSAndi Kleen struct pmu_event *pe; 27771b0acceSAndi Kleen int i; 27871b0acceSAndi Kleen struct rblist groups; 27971b0acceSAndi Kleen struct rb_node *node, *next; 28071b0acceSAndi Kleen struct strlist *metriclist = NULL; 28171b0acceSAndi Kleen 28271b0acceSAndi Kleen if (!map) 28371b0acceSAndi Kleen return; 28471b0acceSAndi Kleen 28571b0acceSAndi Kleen if (!metricgroups) { 28671b0acceSAndi Kleen metriclist = strlist__new(NULL, NULL); 28771b0acceSAndi Kleen if (!metriclist) 28871b0acceSAndi Kleen return; 28971b0acceSAndi Kleen } 29071b0acceSAndi Kleen 29171b0acceSAndi Kleen rblist__init(&groups); 29271b0acceSAndi Kleen groups.node_new = mep_new; 29371b0acceSAndi Kleen groups.node_cmp = mep_cmp; 29471b0acceSAndi Kleen groups.node_delete = mep_delete; 29571b0acceSAndi Kleen for (i = 0; ; i++) { 29671b0acceSAndi Kleen const char *g; 29771b0acceSAndi Kleen pe = &map->table[i]; 29871b0acceSAndi Kleen 29971b0acceSAndi Kleen if (!pe->name && !pe->metric_group && !pe->metric_name) 30071b0acceSAndi Kleen break; 30171b0acceSAndi Kleen if (!pe->metric_expr) 30271b0acceSAndi Kleen continue; 30371b0acceSAndi Kleen g = pe->metric_group; 30471b0acceSAndi Kleen if (!g && pe->metric_name) { 30571b0acceSAndi Kleen if (pe->name) 30671b0acceSAndi Kleen continue; 30771b0acceSAndi Kleen g = "No_group"; 30871b0acceSAndi Kleen } 30971b0acceSAndi Kleen if (g) { 31071b0acceSAndi Kleen char *omg; 31171b0acceSAndi Kleen char *mg = strdup(g); 31271b0acceSAndi Kleen 31371b0acceSAndi Kleen if (!mg) 31471b0acceSAndi Kleen return; 31571b0acceSAndi Kleen omg = mg; 31671b0acceSAndi Kleen while ((g = strsep(&mg, ";")) != NULL) { 31771b0acceSAndi Kleen struct mep *me; 31871b0acceSAndi Kleen char *s; 31971b0acceSAndi Kleen 32071b0acceSAndi Kleen if (*g == 0) 32171b0acceSAndi Kleen g = "No_group"; 32271b0acceSAndi Kleen while (isspace(*g)) 32371b0acceSAndi Kleen g++; 32471b0acceSAndi Kleen if (filter && !strstr(g, filter)) 32571b0acceSAndi Kleen continue; 32671b0acceSAndi Kleen if (raw) 32771b0acceSAndi Kleen s = (char *)pe->metric_name; 32871b0acceSAndi Kleen else { 329*95f04328SMichael Petlan if (asprintf(&s, "%s\n%*s%s]", 330*95f04328SMichael Petlan pe->metric_name, 8, "[", pe->desc) < 0) 33171b0acceSAndi Kleen return; 33271b0acceSAndi Kleen } 33371b0acceSAndi Kleen 33471b0acceSAndi Kleen if (!s) 33571b0acceSAndi Kleen continue; 33671b0acceSAndi Kleen 33771b0acceSAndi Kleen if (!metricgroups) { 33871b0acceSAndi Kleen strlist__add(metriclist, s); 33971b0acceSAndi Kleen } else { 34071b0acceSAndi Kleen me = mep_lookup(&groups, g); 34171b0acceSAndi Kleen if (!me) 34271b0acceSAndi Kleen continue; 34371b0acceSAndi Kleen strlist__add(me->metrics, s); 34471b0acceSAndi Kleen } 34571b0acceSAndi Kleen } 34671b0acceSAndi Kleen free(omg); 34771b0acceSAndi Kleen } 34871b0acceSAndi Kleen } 34971b0acceSAndi Kleen 35071b0acceSAndi Kleen if (metricgroups && !raw) 35171b0acceSAndi Kleen printf("\nMetric Groups:\n\n"); 35271b0acceSAndi Kleen else if (metrics && !raw) 35371b0acceSAndi Kleen printf("\nMetrics:\n\n"); 35471b0acceSAndi Kleen 35571b0acceSAndi Kleen for (node = rb_first(&groups.entries); node; node = next) { 35671b0acceSAndi Kleen struct mep *me = container_of(node, struct mep, nd); 35771b0acceSAndi Kleen 35871b0acceSAndi Kleen if (metricgroups) 35971b0acceSAndi Kleen printf("%s%s%s", me->name, metrics ? ":" : "", raw ? " " : "\n"); 36071b0acceSAndi Kleen if (metrics) 36171b0acceSAndi Kleen metricgroup__print_strlist(me->metrics, raw); 36271b0acceSAndi Kleen next = rb_next(node); 36371b0acceSAndi Kleen rblist__remove_node(&groups, node); 36471b0acceSAndi Kleen } 36571b0acceSAndi Kleen if (!metricgroups) 36671b0acceSAndi Kleen metricgroup__print_strlist(metriclist, raw); 36771b0acceSAndi Kleen strlist__delete(metriclist); 36871b0acceSAndi Kleen } 36971b0acceSAndi Kleen 370b18f3e36SAndi Kleen static int metricgroup__add_metric(const char *metric, struct strbuf *events, 371b18f3e36SAndi Kleen struct list_head *group_list) 372b18f3e36SAndi Kleen { 37354e32dc0SGanapatrao Kulkarni struct pmu_events_map *map = perf_pmu__find_map(NULL); 374b18f3e36SAndi Kleen struct pmu_event *pe; 375b18f3e36SAndi Kleen int ret = -EINVAL; 376b18f3e36SAndi Kleen int i, j; 377b18f3e36SAndi Kleen 378b18f3e36SAndi Kleen if (!map) 379b18f3e36SAndi Kleen return 0; 380b18f3e36SAndi Kleen 381b18f3e36SAndi Kleen for (i = 0; ; i++) { 382b18f3e36SAndi Kleen pe = &map->table[i]; 383b18f3e36SAndi Kleen 384b18f3e36SAndi Kleen if (!pe->name && !pe->metric_group && !pe->metric_name) 385b18f3e36SAndi Kleen break; 386b18f3e36SAndi Kleen if (!pe->metric_expr) 387b18f3e36SAndi Kleen continue; 388b18f3e36SAndi Kleen if (match_metric(pe->metric_group, metric) || 389b18f3e36SAndi Kleen match_metric(pe->metric_name, metric)) { 390b18f3e36SAndi Kleen const char **ids; 391b18f3e36SAndi Kleen int idnum; 392b18f3e36SAndi Kleen struct egroup *eg; 393b18f3e36SAndi Kleen 394b18f3e36SAndi Kleen pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name); 395b18f3e36SAndi Kleen 396b18f3e36SAndi Kleen if (expr__find_other(pe->metric_expr, 397b18f3e36SAndi Kleen NULL, &ids, &idnum) < 0) 398b18f3e36SAndi Kleen continue; 399b18f3e36SAndi Kleen if (events->len > 0) 400b18f3e36SAndi Kleen strbuf_addf(events, ","); 401b18f3e36SAndi Kleen for (j = 0; j < idnum; j++) { 402b18f3e36SAndi Kleen pr_debug("found event %s\n", ids[j]); 403b18f3e36SAndi Kleen strbuf_addf(events, "%s%s", 404b18f3e36SAndi Kleen j == 0 ? "{" : ",", 405b18f3e36SAndi Kleen ids[j]); 406b18f3e36SAndi Kleen } 407b18f3e36SAndi Kleen strbuf_addf(events, "}:W"); 408b18f3e36SAndi Kleen 409b18f3e36SAndi Kleen eg = malloc(sizeof(struct egroup)); 410b18f3e36SAndi Kleen if (!eg) { 411b18f3e36SAndi Kleen ret = -ENOMEM; 412b18f3e36SAndi Kleen break; 413b18f3e36SAndi Kleen } 414b18f3e36SAndi Kleen eg->ids = ids; 415b18f3e36SAndi Kleen eg->idnum = idnum; 416b18f3e36SAndi Kleen eg->metric_name = pe->metric_name; 417b18f3e36SAndi Kleen eg->metric_expr = pe->metric_expr; 418b18f3e36SAndi Kleen list_add_tail(&eg->nd, group_list); 419b18f3e36SAndi Kleen ret = 0; 420b18f3e36SAndi Kleen } 421b18f3e36SAndi Kleen } 422b18f3e36SAndi Kleen return ret; 423b18f3e36SAndi Kleen } 424b18f3e36SAndi Kleen 425b18f3e36SAndi Kleen static int metricgroup__add_metric_list(const char *list, struct strbuf *events, 426b18f3e36SAndi Kleen struct list_head *group_list) 427b18f3e36SAndi Kleen { 428b18f3e36SAndi Kleen char *llist, *nlist, *p; 429b18f3e36SAndi Kleen int ret = -EINVAL; 430b18f3e36SAndi Kleen 431b18f3e36SAndi Kleen nlist = strdup(list); 432b18f3e36SAndi Kleen if (!nlist) 433b18f3e36SAndi Kleen return -ENOMEM; 434b18f3e36SAndi Kleen llist = nlist; 435411bc316SAndi Kleen 436411bc316SAndi Kleen strbuf_init(events, 100); 437411bc316SAndi Kleen strbuf_addf(events, "%s", ""); 438411bc316SAndi Kleen 439b18f3e36SAndi Kleen while ((p = strsep(&llist, ",")) != NULL) { 440b18f3e36SAndi Kleen ret = metricgroup__add_metric(p, events, group_list); 441b18f3e36SAndi Kleen if (ret == -EINVAL) { 442b18f3e36SAndi Kleen fprintf(stderr, "Cannot find metric or group `%s'\n", 443b18f3e36SAndi Kleen p); 444b18f3e36SAndi Kleen break; 445b18f3e36SAndi Kleen } 446b18f3e36SAndi Kleen } 447b18f3e36SAndi Kleen free(nlist); 448b18f3e36SAndi Kleen return ret; 449b18f3e36SAndi Kleen } 450b18f3e36SAndi Kleen 451b18f3e36SAndi Kleen static void metricgroup__free_egroups(struct list_head *group_list) 452b18f3e36SAndi Kleen { 453b18f3e36SAndi Kleen struct egroup *eg, *egtmp; 454b18f3e36SAndi Kleen int i; 455b18f3e36SAndi Kleen 456b18f3e36SAndi Kleen list_for_each_entry_safe (eg, egtmp, group_list, nd) { 457b18f3e36SAndi Kleen for (i = 0; i < eg->idnum; i++) 458b18f3e36SAndi Kleen free((char *)eg->ids[i]); 459b18f3e36SAndi Kleen free(eg->ids); 460b18f3e36SAndi Kleen free(eg); 461b18f3e36SAndi Kleen } 462b18f3e36SAndi Kleen } 463b18f3e36SAndi Kleen 464b18f3e36SAndi Kleen int metricgroup__parse_groups(const struct option *opt, 465b18f3e36SAndi Kleen const char *str, 466b18f3e36SAndi Kleen struct rblist *metric_events) 467b18f3e36SAndi Kleen { 468b18f3e36SAndi Kleen struct parse_events_error parse_error; 469b18f3e36SAndi Kleen struct perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value; 470b18f3e36SAndi Kleen struct strbuf extra_events; 471b18f3e36SAndi Kleen LIST_HEAD(group_list); 472b18f3e36SAndi Kleen int ret; 473b18f3e36SAndi Kleen 474b18f3e36SAndi Kleen if (metric_events->nr_entries == 0) 475b18f3e36SAndi Kleen metricgroup__rblist_init(metric_events); 476b18f3e36SAndi Kleen ret = metricgroup__add_metric_list(str, &extra_events, &group_list); 477b18f3e36SAndi Kleen if (ret) 478b18f3e36SAndi Kleen return ret; 479b18f3e36SAndi Kleen pr_debug("adding %s\n", extra_events.buf); 480b18f3e36SAndi Kleen memset(&parse_error, 0, sizeof(struct parse_events_error)); 481b18f3e36SAndi Kleen ret = parse_events(perf_evlist, extra_events.buf, &parse_error); 482b18f3e36SAndi Kleen if (ret) { 483333b5665SAndi Kleen parse_events_print_error(&parse_error, extra_events.buf); 484b18f3e36SAndi Kleen goto out; 485b18f3e36SAndi Kleen } 486b18f3e36SAndi Kleen strbuf_release(&extra_events); 487b18f3e36SAndi Kleen ret = metricgroup__setup_events(&group_list, perf_evlist, 488b18f3e36SAndi Kleen metric_events); 489b18f3e36SAndi Kleen out: 490b18f3e36SAndi Kleen metricgroup__free_egroups(&group_list); 491b18f3e36SAndi Kleen return ret; 492b18f3e36SAndi Kleen } 493742d92ffSThomas Richter 494742d92ffSThomas Richter bool metricgroup__has_metric(const char *metric) 495742d92ffSThomas Richter { 496742d92ffSThomas Richter struct pmu_events_map *map = perf_pmu__find_map(NULL); 497742d92ffSThomas Richter struct pmu_event *pe; 498742d92ffSThomas Richter int i; 499742d92ffSThomas Richter 500742d92ffSThomas Richter if (!map) 501742d92ffSThomas Richter return false; 502742d92ffSThomas Richter 503742d92ffSThomas Richter for (i = 0; ; i++) { 504742d92ffSThomas Richter pe = &map->table[i]; 505742d92ffSThomas Richter 506742d92ffSThomas Richter if (!pe->name && !pe->metric_group && !pe->metric_name) 507742d92ffSThomas Richter break; 508742d92ffSThomas Richter if (!pe->metric_expr) 509742d92ffSThomas Richter continue; 510742d92ffSThomas Richter if (match_metric(pe->metric_name, metric)) 511742d92ffSThomas Richter return true; 512742d92ffSThomas Richter } 513742d92ffSThomas Richter return false; 514742d92ffSThomas Richter } 515