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

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

Version: ~ [ linux-5.13-rc7 ] ~ [ linux-5.12.12 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.45 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.127 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.195 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.237 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.273 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.273 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ 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 // 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 "expr.h"
 15 #include "rblist.h"
 16 #include <string.h>
 17 #include <errno.h>
 18 #include "pmu-events/pmu-events.h"
 19 #include "strlist.h"
 20 #include <assert.h>
 21 #include <linux/ctype.h>
 22 #include <linux/string.h>
 23 #include <linux/zalloc.h>
 24 #include <subcmd/parse-options.h>
 25 
 26 struct metric_event *metricgroup__lookup(struct rblist *metric_events,
 27                                          struct evsel *evsel,
 28                                          bool create)
 29 {
 30         struct rb_node *nd;
 31         struct metric_event me = {
 32                 .evsel = evsel
 33         };
 34 
 35         if (!metric_events)
 36                 return NULL;
 37 
 38         nd = rblist__find(metric_events, &me);
 39         if (nd)
 40                 return container_of(nd, struct metric_event, nd);
 41         if (create) {
 42                 rblist__add_node(metric_events, &me);
 43                 nd = rblist__find(metric_events, &me);
 44                 if (nd)
 45                         return container_of(nd, struct metric_event, nd);
 46         }
 47         return NULL;
 48 }
 49 
 50 static int metric_event_cmp(struct rb_node *rb_node, const void *entry)
 51 {
 52         struct metric_event *a = container_of(rb_node,
 53                                               struct metric_event,
 54                                               nd);
 55         const struct metric_event *b = entry;
 56 
 57         if (a->evsel == b->evsel)
 58                 return 0;
 59         if ((char *)a->evsel < (char *)b->evsel)
 60                 return -1;
 61         return +1;
 62 }
 63 
 64 static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused,
 65                                         const void *entry)
 66 {
 67         struct metric_event *me = malloc(sizeof(struct metric_event));
 68 
 69         if (!me)
 70                 return NULL;
 71         memcpy(me, entry, sizeof(struct metric_event));
 72         me->evsel = ((struct metric_event *)entry)->evsel;
 73         INIT_LIST_HEAD(&me->head);
 74         return &me->nd;
 75 }
 76 
 77 static void metricgroup__rblist_init(struct rblist *metric_events)
 78 {
 79         rblist__init(metric_events);
 80         metric_events->node_cmp = metric_event_cmp;
 81         metric_events->node_new = metric_event_new;
 82 }
 83 
 84 struct egroup {
 85         struct list_head nd;
 86         int idnum;
 87         const char **ids;
 88         const char *metric_name;
 89         const char *metric_expr;
 90         const char *metric_unit;
 91 };
 92 
 93 static struct evsel *find_evsel_group(struct evlist *perf_evlist,
 94                                       const char **ids,
 95                                       int idnum,
 96                                       struct evsel **metric_events)
 97 {
 98         struct evsel *ev;
 99         int i = 0;
100         bool leader_found;
101 
102         evlist__for_each_entry (perf_evlist, ev) {
103                 if (!strcmp(ev->name, ids[i])) {
104                         if (!metric_events[i])
105                                 metric_events[i] = ev;
106                         i++;
107                         if (i == idnum)
108                                 break;
109                 } else {
110                         if (i + 1 == idnum) {
111                                 /* Discard the whole match and start again */
112                                 i = 0;
113                                 memset(metric_events, 0,
114                                        sizeof(struct evsel *) * idnum);
115                                 continue;
116                         }
117 
118                         if (!strcmp(ev->name, ids[i]))
119                                 metric_events[i] = ev;
120                         else {
121                                 /* Discard the whole match and start again */
122                                 i = 0;
123                                 memset(metric_events, 0,
124                                        sizeof(struct evsel *) * idnum);
125                                 continue;
126                         }
127                 }
128         }
129 
130         if (i != idnum) {
131                 /* Not whole match */
132                 return NULL;
133         }
134 
135         metric_events[idnum] = NULL;
136 
137         for (i = 0; i < idnum; i++) {
138                 leader_found = false;
139                 evlist__for_each_entry(perf_evlist, ev) {
140                         if (!leader_found && (ev == metric_events[i]))
141                                 leader_found = true;
142 
143                         if (leader_found &&
144                             !strcmp(ev->name, metric_events[i]->name)) {
145                                 ev->metric_leader = metric_events[i];
146                         }
147                 }
148         }
149 
150         return metric_events[0];
151 }
152 
153 static int metricgroup__setup_events(struct list_head *groups,
154                                      struct evlist *perf_evlist,
155                                      struct rblist *metric_events_list)
156 {
157         struct metric_event *me;
158         struct metric_expr *expr;
159         int i = 0;
160         int ret = 0;
161         struct egroup *eg;
162         struct evsel *evsel;
163 
164         list_for_each_entry (eg, groups, nd) {
165                 struct evsel **metric_events;
166 
167                 metric_events = calloc(sizeof(void *), eg->idnum + 1);
168                 if (!metric_events) {
169                         ret = -ENOMEM;
170                         break;
171                 }
172                 evsel = find_evsel_group(perf_evlist, eg->ids, eg->idnum,
173                                          metric_events);
174                 if (!evsel) {
175                         pr_debug("Cannot resolve %s: %s\n",
176                                         eg->metric_name, eg->metric_expr);
177                         continue;
178                 }
179                 for (i = 0; i < eg->idnum; i++)
180                         metric_events[i]->collect_stat = true;
181                 me = metricgroup__lookup(metric_events_list, evsel, true);
182                 if (!me) {
183                         ret = -ENOMEM;
184                         break;
185                 }
186                 expr = malloc(sizeof(struct metric_expr));
187                 if (!expr) {
188                         ret = -ENOMEM;
189                         break;
190                 }
191                 expr->metric_expr = eg->metric_expr;
192                 expr->metric_name = eg->metric_name;
193                 expr->metric_unit = eg->metric_unit;
194                 expr->metric_events = metric_events;
195                 list_add(&expr->nd, &me->head);
196         }
197         return ret;
198 }
199 
200 static bool match_metric(const char *n, const char *list)
201 {
202         int len;
203         char *m;
204 
205         if (!list)
206                 return false;
207         if (!strcmp(list, "all"))
208                 return true;
209         if (!n)
210                 return !strcasecmp(list, "No_group");
211         len = strlen(list);
212         m = strcasestr(n, list);
213         if (!m)
214                 return false;
215         if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
216             (m[len] == 0 || m[len] == ';'))
217                 return true;
218         return false;
219 }
220 
221 struct mep {
222         struct rb_node nd;
223         const char *name;
224         struct strlist *metrics;
225 };
226 
227 static int mep_cmp(struct rb_node *rb_node, const void *entry)
228 {
229         struct mep *a = container_of(rb_node, struct mep, nd);
230         struct mep *b = (struct mep *)entry;
231 
232         return strcmp(a->name, b->name);
233 }
234 
235 static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
236                                         const void *entry)
237 {
238         struct mep *me = malloc(sizeof(struct mep));
239 
240         if (!me)
241                 return NULL;
242         memcpy(me, entry, sizeof(struct mep));
243         me->name = strdup(me->name);
244         if (!me->name)
245                 goto out_me;
246         me->metrics = strlist__new(NULL, NULL);
247         if (!me->metrics)
248                 goto out_name;
249         return &me->nd;
250 out_name:
251         zfree(&me->name);
252 out_me:
253         free(me);
254         return NULL;
255 }
256 
257 static struct mep *mep_lookup(struct rblist *groups, const char *name)
258 {
259         struct rb_node *nd;
260         struct mep me = {
261                 .name = name
262         };
263         nd = rblist__find(groups, &me);
264         if (nd)
265                 return container_of(nd, struct mep, nd);
266         rblist__add_node(groups, &me);
267         nd = rblist__find(groups, &me);
268         if (nd)
269                 return container_of(nd, struct mep, nd);
270         return NULL;
271 }
272 
273 static void mep_delete(struct rblist *rl __maybe_unused,
274                        struct rb_node *nd)
275 {
276         struct mep *me = container_of(nd, struct mep, nd);
277 
278         strlist__delete(me->metrics);
279         zfree(&me->name);
280         free(me);
281 }
282 
283 static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
284 {
285         struct str_node *sn;
286         int n = 0;
287 
288         strlist__for_each_entry (sn, metrics) {
289                 if (raw)
290                         printf("%s%s", n > 0 ? " " : "", sn->s);
291                 else
292                         printf("  %s\n", sn->s);
293                 n++;
294         }
295         if (raw)
296                 putchar('\n');
297 }
298 
299 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
300                         bool raw, bool details)
301 {
302         struct pmu_events_map *map = perf_pmu__find_map(NULL);
303         struct pmu_event *pe;
304         int i;
305         struct rblist groups;
306         struct rb_node *node, *next;
307         struct strlist *metriclist = NULL;
308 
309         if (!map)
310                 return;
311 
312         if (!metricgroups) {
313                 metriclist = strlist__new(NULL, NULL);
314                 if (!metriclist)
315                         return;
316         }
317 
318         rblist__init(&groups);
319         groups.node_new = mep_new;
320         groups.node_cmp = mep_cmp;
321         groups.node_delete = mep_delete;
322         for (i = 0; ; i++) {
323                 const char *g;
324                 pe = &map->table[i];
325 
326                 if (!pe->name && !pe->metric_group && !pe->metric_name)
327                         break;
328                 if (!pe->metric_expr)
329                         continue;
330                 g = pe->metric_group;
331                 if (!g && pe->metric_name) {
332                         if (pe->name)
333                                 continue;
334                         g = "No_group";
335                 }
336                 if (g) {
337                         char *omg;
338                         char *mg = strdup(g);
339 
340                         if (!mg)
341                                 return;
342                         omg = mg;
343                         while ((g = strsep(&mg, ";")) != NULL) {
344                                 struct mep *me;
345                                 char *s;
346 
347                                 g = skip_spaces(g);
348                                 if (*g == 0)
349                                         g = "No_group";
350                                 if (filter && !strstr(g, filter))
351                                         continue;
352                                 if (raw)
353                                         s = (char *)pe->metric_name;
354                                 else {
355                                         if (asprintf(&s, "%s\n%*s%s]",
356                                                      pe->metric_name, 8, "[", pe->desc) < 0)
357                                                 return;
358 
359                                         if (details) {
360                                                 if (asprintf(&s, "%s\n%*s%s]",
361                                                              s, 8, "[", pe->metric_expr) < 0)
362                                                         return;
363                                         }
364                                 }
365 
366                                 if (!s)
367                                         continue;
368 
369                                 if (!metricgroups) {
370                                         strlist__add(metriclist, s);
371                                 } else {
372                                         me = mep_lookup(&groups, g);
373                                         if (!me)
374                                                 continue;
375                                         strlist__add(me->metrics, s);
376                                 }
377                         }
378                         free(omg);
379                 }
380         }
381 
382         if (metricgroups && !raw)
383                 printf("\nMetric Groups:\n\n");
384         else if (metrics && !raw)
385                 printf("\nMetrics:\n\n");
386 
387         for (node = rb_first_cached(&groups.entries); node; node = next) {
388                 struct mep *me = container_of(node, struct mep, nd);
389 
390                 if (metricgroups)
391                         printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n");
392                 if (metrics)
393                         metricgroup__print_strlist(me->metrics, raw);
394                 next = rb_next(node);
395                 rblist__remove_node(&groups, node);
396         }
397         if (!metricgroups)
398                 metricgroup__print_strlist(metriclist, raw);
399         strlist__delete(metriclist);
400 }
401 
402 static int metricgroup__add_metric(const char *metric, struct strbuf *events,
403                                    struct list_head *group_list)
404 {
405         struct pmu_events_map *map = perf_pmu__find_map(NULL);
406         struct pmu_event *pe;
407         int ret = -EINVAL;
408         int i, j;
409 
410         if (!map)
411                 return 0;
412 
413         for (i = 0; ; i++) {
414                 pe = &map->table[i];
415 
416                 if (!pe->name && !pe->metric_group && !pe->metric_name)
417                         break;
418                 if (!pe->metric_expr)
419                         continue;
420                 if (match_metric(pe->metric_group, metric) ||
421                     match_metric(pe->metric_name, metric)) {
422                         const char **ids;
423                         int idnum;
424                         struct egroup *eg;
425                         bool no_group = false;
426 
427                         pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
428 
429                         if (expr__find_other(pe->metric_expr,
430                                              NULL, &ids, &idnum) < 0)
431                                 continue;
432                         if (events->len > 0)
433                                 strbuf_addf(events, ",");
434                         for (j = 0; j < idnum; j++) {
435                                 pr_debug("found event %s\n", ids[j]);
436                                 /*
437                                  * Duration time maps to a software event and can make
438                                  * groups not count. Always use it outside a
439                                  * group.
440                                  */
441                                 if (!strcmp(ids[j], "duration_time")) {
442                                         if (j > 0)
443                                                 strbuf_addf(events, "}:W,");
444                                         strbuf_addf(events, "duration_time");
445                                         no_group = true;
446                                         continue;
447                                 }
448                                 strbuf_addf(events, "%s%s",
449                                         j == 0 || no_group ? "{" : ",",
450                                         ids[j]);
451                                 no_group = false;
452                         }
453                         if (!no_group)
454                                 strbuf_addf(events, "}:W");
455 
456                         eg = malloc(sizeof(struct egroup));
457                         if (!eg) {
458                                 ret = -ENOMEM;
459                                 break;
460                         }
461                         eg->ids = ids;
462                         eg->idnum = idnum;
463                         eg->metric_name = pe->metric_name;
464                         eg->metric_expr = pe->metric_expr;
465                         eg->metric_unit = pe->unit;
466                         list_add_tail(&eg->nd, group_list);
467                         ret = 0;
468                 }
469         }
470         return ret;
471 }
472 
473 static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
474                                         struct list_head *group_list)
475 {
476         char *llist, *nlist, *p;
477         int ret = -EINVAL;
478 
479         nlist = strdup(list);
480         if (!nlist)
481                 return -ENOMEM;
482         llist = nlist;
483 
484         strbuf_init(events, 100);
485         strbuf_addf(events, "%s", "");
486 
487         while ((p = strsep(&llist, ",")) != NULL) {
488                 ret = metricgroup__add_metric(p, events, group_list);
489                 if (ret == -EINVAL) {
490                         fprintf(stderr, "Cannot find metric or group `%s'\n",
491                                         p);
492                         break;
493                 }
494         }
495         free(nlist);
496         return ret;
497 }
498 
499 static void metricgroup__free_egroups(struct list_head *group_list)
500 {
501         struct egroup *eg, *egtmp;
502         int i;
503 
504         list_for_each_entry_safe (eg, egtmp, group_list, nd) {
505                 for (i = 0; i < eg->idnum; i++)
506                         zfree(&eg->ids[i]);
507                 zfree(&eg->ids);
508                 list_del_init(&eg->nd);
509                 free(eg);
510         }
511 }
512 
513 int metricgroup__parse_groups(const struct option *opt,
514                            const char *str,
515                            struct rblist *metric_events)
516 {
517         struct parse_events_error parse_error;
518         struct evlist *perf_evlist = *(struct evlist **)opt->value;
519         struct strbuf extra_events;
520         LIST_HEAD(group_list);
521         int ret;
522 
523         if (metric_events->nr_entries == 0)
524                 metricgroup__rblist_init(metric_events);
525         ret = metricgroup__add_metric_list(str, &extra_events, &group_list);
526         if (ret)
527                 return ret;
528         pr_debug("adding %s\n", extra_events.buf);
529         bzero(&parse_error, sizeof(parse_error));
530         ret = parse_events(perf_evlist, extra_events.buf, &parse_error);
531         if (ret) {
532                 parse_events_print_error(&parse_error, extra_events.buf);
533                 goto out;
534         }
535         strbuf_release(&extra_events);
536         ret = metricgroup__setup_events(&group_list, perf_evlist,
537                                         metric_events);
538 out:
539         metricgroup__free_egroups(&group_list);
540         return ret;
541 }
542 
543 bool metricgroup__has_metric(const char *metric)
544 {
545         struct pmu_events_map *map = perf_pmu__find_map(NULL);
546         struct pmu_event *pe;
547         int i;
548 
549         if (!map)
550                 return false;
551 
552         for (i = 0; ; i++) {
553                 pe = &map->table[i];
554 
555                 if (!pe->name && !pe->metric_group && !pe->metric_name)
556                         break;
557                 if (!pe->metric_expr)
558                         continue;
559                 if (match_metric(pe->metric_name, metric))
560                         return true;
561         }
562         return false;
563 }
564 

~ [ 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