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