~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/metricgroup.c

Version: ~ [ linux-5.10-rc5 ] ~ [ linux-5.9.10 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.79 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.159 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.208 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.245 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.245 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (c) 2017, Intel Corporation.
  3  *
  4  * This program is free software; you can redistribute it and/or modify it
  5  * under the terms and conditions of the GNU General Public License,
  6  * version 2, as published by the Free Software Foundation.
  7  *
  8  * This program is distributed in the hope it will be useful, but WITHOUT
  9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 11  * more details.
 12  *
 13  */
 14 
 15 /* Manage metrics and groups of metrics from JSON files */
 16 
 17 #include "metricgroup.h"
 18 #include "evlist.h"
 19 #include "strbuf.h"
 20 #include "pmu.h"
 21 #include "expr.h"
 22 #include "rblist.h"
 23 #include "pmu.h"
 24 #include <string.h>
 25 #include <stdbool.h>
 26 #include <errno.h>
 27 #include "pmu-events/pmu-events.h"
 28 #include "strbuf.h"
 29 #include "strlist.h"
 30 #include <assert.h>
 31 #include <ctype.h>
 32 
 33 struct metric_event *metricgroup__lookup(struct rblist *metric_events,
 34                                          struct perf_evsel *evsel,
 35                                          bool create)
 36 {
 37         struct rb_node *nd;
 38         struct metric_event me = {
 39                 .evsel = evsel
 40         };
 41         nd = rblist__find(metric_events, &me);
 42         if (nd)
 43                 return container_of(nd, struct metric_event, nd);
 44         if (create) {
 45                 rblist__add_node(metric_events, &me);
 46                 nd = rblist__find(metric_events, &me);
 47                 if (nd)
 48                         return container_of(nd, struct metric_event, nd);
 49         }
 50         return NULL;
 51 }
 52 
 53 static int metric_event_cmp(struct rb_node *rb_node, const void *entry)
 54 {
 55         struct metric_event *a = container_of(rb_node,
 56                                               struct metric_event,
 57                                               nd);
 58         const struct metric_event *b = entry;
 59 
 60         if (a->evsel == b->evsel)
 61                 return 0;
 62         if ((char *)a->evsel < (char *)b->evsel)
 63                 return -1;
 64         return +1;
 65 }
 66 
 67 static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused,
 68                                         const void *entry)
 69 {
 70         struct metric_event *me = malloc(sizeof(struct metric_event));
 71 
 72         if (!me)
 73                 return NULL;
 74         memcpy(me, entry, sizeof(struct metric_event));
 75         me->evsel = ((struct metric_event *)entry)->evsel;
 76         INIT_LIST_HEAD(&me->head);
 77         return &me->nd;
 78 }
 79 
 80 static void metricgroup__rblist_init(struct rblist *metric_events)
 81 {
 82         rblist__init(metric_events);
 83         metric_events->node_cmp = metric_event_cmp;
 84         metric_events->node_new = metric_event_new;
 85 }
 86 
 87 struct egroup {
 88         struct list_head nd;
 89         int idnum;
 90         const char **ids;
 91         const char *metric_name;
 92         const char *metric_expr;
 93 };
 94 
 95 static struct perf_evsel *find_evsel(struct perf_evlist *perf_evlist,
 96                                      const char **ids,
 97                                      int idnum,
 98                                      struct perf_evsel **metric_events)
 99 {
100         struct perf_evsel *ev, *start = NULL;
101         int ind = 0;
102 
103         evlist__for_each_entry (perf_evlist, ev) {
104                 if (!strcmp(ev->name, ids[ind])) {
105                         metric_events[ind] = ev;
106                         if (ind == 0)
107                                 start = ev;
108                         if (++ind == idnum) {
109                                 metric_events[ind] = NULL;
110                                 return start;
111                         }
112                 } else {
113                         ind = 0;
114                         start = NULL;
115                 }
116         }
117         /*
118          * This can happen when an alias expands to multiple
119          * events, like for uncore events.
120          * We don't support this case for now.
121          */
122         return NULL;
123 }
124 
125 static int metricgroup__setup_events(struct list_head *groups,
126                                      struct perf_evlist *perf_evlist,
127                                      struct rblist *metric_events_list)
128 {
129         struct metric_event *me;
130         struct metric_expr *expr;
131         int i = 0;
132         int ret = 0;
133         struct egroup *eg;
134         struct perf_evsel *evsel;
135 
136         list_for_each_entry (eg, groups, nd) {
137                 struct perf_evsel **metric_events;
138 
139                 metric_events = calloc(sizeof(void *), eg->idnum + 1);
140                 if (!metric_events) {
141                         ret = -ENOMEM;
142                         break;
143                 }
144                 evsel = find_evsel(perf_evlist, eg->ids, eg->idnum,
145                                    metric_events);
146                 if (!evsel) {
147                         pr_debug("Cannot resolve %s: %s\n",
148                                         eg->metric_name, eg->metric_expr);
149                         continue;
150                 }
151                 for (i = 0; i < eg->idnum; i++)
152                         metric_events[i]->collect_stat = true;
153                 me = metricgroup__lookup(metric_events_list, evsel, true);
154                 if (!me) {
155                         ret = -ENOMEM;
156                         break;
157                 }
158                 expr = malloc(sizeof(struct metric_expr));
159                 if (!expr) {
160                         ret = -ENOMEM;
161                         break;
162                 }
163                 expr->metric_expr = eg->metric_expr;
164                 expr->metric_name = eg->metric_name;
165                 expr->metric_events = metric_events;
166                 list_add(&expr->nd, &me->head);
167         }
168         return ret;
169 }
170 
171 static bool match_metric(const char *n, const char *list)
172 {
173         int len;
174         char *m;
175 
176         if (!list)
177                 return false;
178         if (!strcmp(list, "all"))
179                 return true;
180         if (!n)
181                 return !strcasecmp(list, "No_group");
182         len = strlen(list);
183         m = strcasestr(n, list);
184         if (!m)
185                 return false;
186         if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
187             (m[len] == 0 || m[len] == ';'))
188                 return true;
189         return false;
190 }
191 
192 struct mep {
193         struct rb_node nd;
194         const char *name;
195         struct strlist *metrics;
196 };
197 
198 static int mep_cmp(struct rb_node *rb_node, const void *entry)
199 {
200         struct mep *a = container_of(rb_node, struct mep, nd);
201         struct mep *b = (struct mep *)entry;
202 
203         return strcmp(a->name, b->name);
204 }
205 
206 static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
207                                         const void *entry)
208 {
209         struct mep *me = malloc(sizeof(struct mep));
210 
211         if (!me)
212                 return NULL;
213         memcpy(me, entry, sizeof(struct mep));
214         me->name = strdup(me->name);
215         if (!me->name)
216                 goto out_me;
217         me->metrics = strlist__new(NULL, NULL);
218         if (!me->metrics)
219                 goto out_name;
220         return &me->nd;
221 out_name:
222         free((char *)me->name);
223 out_me:
224         free(me);
225         return NULL;
226 }
227 
228 static struct mep *mep_lookup(struct rblist *groups, const char *name)
229 {
230         struct rb_node *nd;
231         struct mep me = {
232                 .name = name
233         };
234         nd = rblist__find(groups, &me);
235         if (nd)
236                 return container_of(nd, struct mep, nd);
237         rblist__add_node(groups, &me);
238         nd = rblist__find(groups, &me);
239         if (nd)
240                 return container_of(nd, struct mep, nd);
241         return NULL;
242 }
243 
244 static void mep_delete(struct rblist *rl __maybe_unused,
245                        struct rb_node *nd)
246 {
247         struct mep *me = container_of(nd, struct mep, nd);
248 
249         strlist__delete(me->metrics);
250         free((void *)me->name);
251         free(me);
252 }
253 
254 static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
255 {
256         struct str_node *sn;
257         int n = 0;
258 
259         strlist__for_each_entry (sn, metrics) {
260                 if (raw)
261                         printf("%s%s", n > 0 ? " " : "", sn->s);
262                 else
263                         printf("  %s\n", sn->s);
264                 n++;
265         }
266         if (raw)
267                 putchar('\n');
268 }
269 
270 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
271                         bool raw)
272 {
273         struct pmu_events_map *map = perf_pmu__find_map();
274         struct pmu_event *pe;
275         int i;
276         struct rblist groups;
277         struct rb_node *node, *next;
278         struct strlist *metriclist = NULL;
279 
280         if (!map)
281                 return;
282 
283         if (!metricgroups) {
284                 metriclist = strlist__new(NULL, NULL);
285                 if (!metriclist)
286                         return;
287         }
288 
289         rblist__init(&groups);
290         groups.node_new = mep_new;
291         groups.node_cmp = mep_cmp;
292         groups.node_delete = mep_delete;
293         for (i = 0; ; i++) {
294                 const char *g;
295                 pe = &map->table[i];
296 
297                 if (!pe->name && !pe->metric_group && !pe->metric_name)
298                         break;
299                 if (!pe->metric_expr)
300                         continue;
301                 g = pe->metric_group;
302                 if (!g && pe->metric_name) {
303                         if (pe->name)
304                                 continue;
305                         g = "No_group";
306                 }
307                 if (g) {
308                         char *omg;
309                         char *mg = strdup(g);
310 
311                         if (!mg)
312                                 return;
313                         omg = mg;
314                         while ((g = strsep(&mg, ";")) != NULL) {
315                                 struct mep *me;
316                                 char *s;
317 
318                                 if (*g == 0)
319                                         g = "No_group";
320                                 while (isspace(*g))
321                                         g++;
322                                 if (filter && !strstr(g, filter))
323                                         continue;
324                                 if (raw)
325                                         s = (char *)pe->metric_name;
326                                 else {
327                                         if (asprintf(&s, "%s\n\t[%s]",
328                                                      pe->metric_name, pe->desc) < 0)
329                                                 return;
330                                 }
331 
332                                 if (!s)
333                                         continue;
334 
335                                 if (!metricgroups) {
336                                         strlist__add(metriclist, s);
337                                 } else {
338                                         me = mep_lookup(&groups, g);
339                                         if (!me)
340                                                 continue;
341                                         strlist__add(me->metrics, s);
342                                 }
343                         }
344                         free(omg);
345                 }
346         }
347 
348         if (metricgroups && !raw)
349                 printf("\nMetric Groups:\n\n");
350         else if (metrics && !raw)
351                 printf("\nMetrics:\n\n");
352 
353         for (node = rb_first(&groups.entries); node; node = next) {
354                 struct mep *me = container_of(node, struct mep, nd);
355 
356                 if (metricgroups)
357                         printf("%s%s%s", me->name, metrics ? ":" : "", raw ? " " : "\n");
358                 if (metrics)
359                         metricgroup__print_strlist(me->metrics, raw);
360                 next = rb_next(node);
361                 rblist__remove_node(&groups, node);
362         }
363         if (!metricgroups)
364                 metricgroup__print_strlist(metriclist, raw);
365         strlist__delete(metriclist);
366 }
367 
368 static int metricgroup__add_metric(const char *metric, struct strbuf *events,
369                                    struct list_head *group_list)
370 {
371         struct pmu_events_map *map = perf_pmu__find_map();
372         struct pmu_event *pe;
373         int ret = -EINVAL;
374         int i, j;
375 
376         if (!map)
377                 return 0;
378 
379         for (i = 0; ; i++) {
380                 pe = &map->table[i];
381 
382                 if (!pe->name && !pe->metric_group && !pe->metric_name)
383                         break;
384                 if (!pe->metric_expr)
385                         continue;
386                 if (match_metric(pe->metric_group, metric) ||
387                     match_metric(pe->metric_name, metric)) {
388                         const char **ids;
389                         int idnum;
390                         struct egroup *eg;
391 
392                         pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
393 
394                         if (expr__find_other(pe->metric_expr,
395                                              NULL, &ids, &idnum) < 0)
396                                 continue;
397                         if (events->len > 0)
398                                 strbuf_addf(events, ",");
399                         for (j = 0; j < idnum; j++) {
400                                 pr_debug("found event %s\n", ids[j]);
401                                 strbuf_addf(events, "%s%s",
402                                         j == 0 ? "{" : ",",
403                                         ids[j]);
404                         }
405                         strbuf_addf(events, "}:W");
406 
407                         eg = malloc(sizeof(struct egroup));
408                         if (!eg) {
409                                 ret = -ENOMEM;
410                                 break;
411                         }
412                         eg->ids = ids;
413                         eg->idnum = idnum;
414                         eg->metric_name = pe->metric_name;
415                         eg->metric_expr = pe->metric_expr;
416                         list_add_tail(&eg->nd, group_list);
417                         ret = 0;
418                 }
419         }
420         return ret;
421 }
422 
423 static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
424                                         struct list_head *group_list)
425 {
426         char *llist, *nlist, *p;
427         int ret = -EINVAL;
428 
429         nlist = strdup(list);
430         if (!nlist)
431                 return -ENOMEM;
432         llist = nlist;
433 
434         strbuf_init(events, 100);
435         strbuf_addf(events, "%s", "");
436 
437         while ((p = strsep(&llist, ",")) != NULL) {
438                 ret = metricgroup__add_metric(p, events, group_list);
439                 if (ret == -EINVAL) {
440                         fprintf(stderr, "Cannot find metric or group `%s'\n",
441                                         p);
442                         break;
443                 }
444         }
445         free(nlist);
446         return ret;
447 }
448 
449 static void metricgroup__free_egroups(struct list_head *group_list)
450 {
451         struct egroup *eg, *egtmp;
452         int i;
453 
454         list_for_each_entry_safe (eg, egtmp, group_list, nd) {
455                 for (i = 0; i < eg->idnum; i++)
456                         free((char *)eg->ids[i]);
457                 free(eg->ids);
458                 free(eg);
459         }
460 }
461 
462 int metricgroup__parse_groups(const struct option *opt,
463                            const char *str,
464                            struct rblist *metric_events)
465 {
466         struct parse_events_error parse_error;
467         struct perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value;
468         struct strbuf extra_events;
469         LIST_HEAD(group_list);
470         int ret;
471 
472         if (metric_events->nr_entries == 0)
473                 metricgroup__rblist_init(metric_events);
474         ret = metricgroup__add_metric_list(str, &extra_events, &group_list);
475         if (ret)
476                 return ret;
477         pr_debug("adding %s\n", extra_events.buf);
478         memset(&parse_error, 0, sizeof(struct parse_events_error));
479         ret = parse_events(perf_evlist, extra_events.buf, &parse_error);
480         if (ret) {
481                 parse_events_print_error(&parse_error, extra_events.buf);
482                 goto out;
483         }
484         strbuf_release(&extra_events);
485         ret = metricgroup__setup_events(&group_list, perf_evlist,
486                                         metric_events);
487 out:
488         metricgroup__free_egroups(&group_list);
489         return ret;
490 }
491 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp