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