xref: /linux/tools/perf/util/metricgroup.c (revision 75b1a8f9d62e50f05d0e4e9f3c8bcde32527ffc1)
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 "strlist.h"
19 #include <assert.h>
20 #include <linux/ctype.h>
21 #include <linux/string.h>
22 #include <linux/zalloc.h>
23 #include <subcmd/parse-options.h>
24 #include <api/fs/fs.h>
25 #include "util.h"
26 #include <asm/bug.h>
27 #include "cgroup.h"
28 
29 struct metric_event *metricgroup__lookup(struct rblist *metric_events,
30 					 struct evsel *evsel,
31 					 bool create)
32 {
33 	struct rb_node *nd;
34 	struct metric_event me = {
35 		.evsel = evsel
36 	};
37 
38 	if (!metric_events)
39 		return NULL;
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 metric_event_delete(struct rblist *rblist __maybe_unused,
81 				struct rb_node *rb_node)
82 {
83 	struct metric_event *me = container_of(rb_node, struct metric_event, nd);
84 	struct metric_expr *expr, *tmp;
85 
86 	list_for_each_entry_safe(expr, tmp, &me->head, nd) {
87 		free(expr->metric_refs);
88 		free(expr->metric_events);
89 		free(expr);
90 	}
91 
92 	free(me);
93 }
94 
95 static void metricgroup__rblist_init(struct rblist *metric_events)
96 {
97 	rblist__init(metric_events);
98 	metric_events->node_cmp = metric_event_cmp;
99 	metric_events->node_new = metric_event_new;
100 	metric_events->node_delete = metric_event_delete;
101 }
102 
103 void metricgroup__rblist_exit(struct rblist *metric_events)
104 {
105 	rblist__exit(metric_events);
106 }
107 
108 /*
109  * A node in the list of referenced metrics. metric_expr
110  * is held as a convenience to avoid a search through the
111  * metric list.
112  */
113 struct metric_ref_node {
114 	const char *metric_name;
115 	const char *metric_expr;
116 	struct list_head list;
117 };
118 
119 struct metric {
120 	struct list_head nd;
121 	struct expr_parse_ctx pctx;
122 	const char *metric_name;
123 	const char *metric_expr;
124 	const char *metric_unit;
125 	struct list_head metric_refs;
126 	int metric_refs_cnt;
127 	int runtime;
128 	bool has_constraint;
129 };
130 
131 #define RECURSION_ID_MAX 1000
132 
133 struct expr_ids {
134 	struct expr_id	id[RECURSION_ID_MAX];
135 	int		cnt;
136 };
137 
138 static struct expr_id *expr_ids__alloc(struct expr_ids *ids)
139 {
140 	if (ids->cnt >= RECURSION_ID_MAX)
141 		return NULL;
142 	return &ids->id[ids->cnt++];
143 }
144 
145 static void expr_ids__exit(struct expr_ids *ids)
146 {
147 	int i;
148 
149 	for (i = 0; i < ids->cnt; i++)
150 		free(ids->id[i].id);
151 }
152 
153 static bool contains_event(struct evsel **metric_events, int num_events,
154 			const char *event_name)
155 {
156 	int i;
157 
158 	for (i = 0; i < num_events; i++) {
159 		if (!strcmp(metric_events[i]->name, event_name))
160 			return true;
161 	}
162 	return false;
163 }
164 
165 /**
166  * Find a group of events in perf_evlist that correspond to those from a parsed
167  * metric expression. Note, as find_evsel_group is called in the same order as
168  * perf_evlist was constructed, metric_no_merge doesn't need to test for
169  * underfilling a group.
170  * @perf_evlist: a list of events something like: {metric1 leader, metric1
171  * sibling, metric1 sibling}:W,duration_time,{metric2 leader, metric2 sibling,
172  * metric2 sibling}:W,duration_time
173  * @pctx: the parse context for the metric expression.
174  * @metric_no_merge: don't attempt to share events for the metric with other
175  * metrics.
176  * @has_constraint: is there a contraint on the group of events? In which case
177  * the events won't be grouped.
178  * @metric_events: out argument, null terminated array of evsel's associated
179  * with the metric.
180  * @evlist_used: in/out argument, bitmap tracking which evlist events are used.
181  * @return the first metric event or NULL on failure.
182  */
183 static struct evsel *find_evsel_group(struct evlist *perf_evlist,
184 				      struct expr_parse_ctx *pctx,
185 				      bool metric_no_merge,
186 				      bool has_constraint,
187 				      struct evsel **metric_events,
188 				      unsigned long *evlist_used)
189 {
190 	struct evsel *ev, *current_leader = NULL;
191 	struct expr_id_data *val_ptr;
192 	int i = 0, matched_events = 0, events_to_match;
193 	const int idnum = (int)hashmap__size(&pctx->ids);
194 
195 	/*
196 	 * duration_time is always grouped separately, when events are grouped
197 	 * (ie has_constraint is false) then ignore it in the matching loop and
198 	 * add it to metric_events at the end.
199 	 */
200 	if (!has_constraint &&
201 	    hashmap__find(&pctx->ids, "duration_time", (void **)&val_ptr))
202 		events_to_match = idnum - 1;
203 	else
204 		events_to_match = idnum;
205 
206 	evlist__for_each_entry (perf_evlist, ev) {
207 		/*
208 		 * Events with a constraint aren't grouped and match the first
209 		 * events available.
210 		 */
211 		if (has_constraint && ev->weak_group)
212 			continue;
213 		/* Ignore event if already used and merging is disabled. */
214 		if (metric_no_merge && test_bit(ev->idx, evlist_used))
215 			continue;
216 		if (!has_constraint && ev->leader != current_leader) {
217 			/*
218 			 * Start of a new group, discard the whole match and
219 			 * start again.
220 			 */
221 			matched_events = 0;
222 			memset(metric_events, 0,
223 				sizeof(struct evsel *) * idnum);
224 			current_leader = ev->leader;
225 		}
226 		/*
227 		 * Check for duplicate events with the same name. For example,
228 		 * uncore_imc/cas_count_read/ will turn into 6 events per socket
229 		 * on skylakex. Only the first such event is placed in
230 		 * metric_events. If events aren't grouped then this also
231 		 * ensures that the same event in different sibling groups
232 		 * aren't both added to metric_events.
233 		 */
234 		if (contains_event(metric_events, matched_events, ev->name))
235 			continue;
236 		/* Does this event belong to the parse context? */
237 		if (hashmap__find(&pctx->ids, ev->name, (void **)&val_ptr))
238 			metric_events[matched_events++] = ev;
239 
240 		if (matched_events == events_to_match)
241 			break;
242 	}
243 
244 	if (events_to_match != idnum) {
245 		/* Add the first duration_time. */
246 		evlist__for_each_entry(perf_evlist, ev) {
247 			if (!strcmp(ev->name, "duration_time")) {
248 				metric_events[matched_events++] = ev;
249 				break;
250 			}
251 		}
252 	}
253 
254 	if (matched_events != idnum) {
255 		/* Not a whole match */
256 		return NULL;
257 	}
258 
259 	metric_events[idnum] = NULL;
260 
261 	for (i = 0; i < idnum; i++) {
262 		ev = metric_events[i];
263 		/* Don't free the used events. */
264 		set_bit(ev->idx, evlist_used);
265 		/*
266 		 * The metric leader points to the identically named event in
267 		 * metric_events.
268 		 */
269 		ev->metric_leader = ev;
270 		/*
271 		 * Mark two events with identical names in the same group (or
272 		 * globally) as being in use as uncore events may be duplicated
273 		 * for each pmu. Set the metric leader of such events to be the
274 		 * event that appears in metric_events.
275 		 */
276 		evlist__for_each_entry_continue(perf_evlist, ev) {
277 			/*
278 			 * If events are grouped then the search can terminate
279 			 * when then group is left.
280 			 */
281 			if (!has_constraint &&
282 			    ev->leader != metric_events[i]->leader &&
283 			    !strcmp(ev->leader->pmu_name,
284 				    metric_events[i]->leader->pmu_name))
285 				break;
286 			if (!strcmp(metric_events[i]->name, ev->name)) {
287 				set_bit(ev->idx, evlist_used);
288 				ev->metric_leader = metric_events[i];
289 			}
290 		}
291 	}
292 
293 	return metric_events[0];
294 }
295 
296 static int metricgroup__setup_events(struct list_head *groups,
297 				     bool metric_no_merge,
298 				     struct evlist *perf_evlist,
299 				     struct rblist *metric_events_list)
300 {
301 	struct metric_event *me;
302 	struct metric_expr *expr;
303 	int i = 0;
304 	int ret = 0;
305 	struct metric *m;
306 	struct evsel *evsel, *tmp;
307 	unsigned long *evlist_used;
308 
309 	evlist_used = bitmap_alloc(perf_evlist->core.nr_entries);
310 	if (!evlist_used)
311 		return -ENOMEM;
312 
313 	list_for_each_entry (m, groups, nd) {
314 		struct evsel **metric_events;
315 		struct metric_ref *metric_refs = NULL;
316 
317 		metric_events = calloc(sizeof(void *),
318 				hashmap__size(&m->pctx.ids) + 1);
319 		if (!metric_events) {
320 			ret = -ENOMEM;
321 			break;
322 		}
323 		evsel = find_evsel_group(perf_evlist, &m->pctx,
324 					 metric_no_merge,
325 					 m->has_constraint, metric_events,
326 					 evlist_used);
327 		if (!evsel) {
328 			pr_debug("Cannot resolve %s: %s\n",
329 					m->metric_name, m->metric_expr);
330 			free(metric_events);
331 			continue;
332 		}
333 		for (i = 0; metric_events[i]; i++)
334 			metric_events[i]->collect_stat = true;
335 		me = metricgroup__lookup(metric_events_list, evsel, true);
336 		if (!me) {
337 			ret = -ENOMEM;
338 			free(metric_events);
339 			break;
340 		}
341 		expr = malloc(sizeof(struct metric_expr));
342 		if (!expr) {
343 			ret = -ENOMEM;
344 			free(metric_events);
345 			break;
346 		}
347 
348 		/*
349 		 * Collect and store collected nested expressions
350 		 * for metric processing.
351 		 */
352 		if (m->metric_refs_cnt) {
353 			struct metric_ref_node *ref;
354 
355 			metric_refs = zalloc(sizeof(struct metric_ref) * (m->metric_refs_cnt + 1));
356 			if (!metric_refs) {
357 				ret = -ENOMEM;
358 				free(metric_events);
359 				free(expr);
360 				break;
361 			}
362 
363 			i = 0;
364 			list_for_each_entry(ref, &m->metric_refs, list) {
365 				/*
366 				 * Intentionally passing just const char pointers,
367 				 * originally from 'struct pmu_event' object.
368 				 * We don't need to change them, so there's no
369 				 * need to create our own copy.
370 				 */
371 				metric_refs[i].metric_name = ref->metric_name;
372 				metric_refs[i].metric_expr = ref->metric_expr;
373 				i++;
374 			}
375 		};
376 
377 		expr->metric_refs = metric_refs;
378 		expr->metric_expr = m->metric_expr;
379 		expr->metric_name = m->metric_name;
380 		expr->metric_unit = m->metric_unit;
381 		expr->metric_events = metric_events;
382 		expr->runtime = m->runtime;
383 		list_add(&expr->nd, &me->head);
384 	}
385 
386 	evlist__for_each_entry_safe(perf_evlist, tmp, evsel) {
387 		if (!test_bit(evsel->idx, evlist_used)) {
388 			evlist__remove(perf_evlist, evsel);
389 			evsel__delete(evsel);
390 		}
391 	}
392 	bitmap_free(evlist_used);
393 
394 	return ret;
395 }
396 
397 static bool match_metric(const char *n, const char *list)
398 {
399 	int len;
400 	char *m;
401 
402 	if (!list)
403 		return false;
404 	if (!strcmp(list, "all"))
405 		return true;
406 	if (!n)
407 		return !strcasecmp(list, "No_group");
408 	len = strlen(list);
409 	m = strcasestr(n, list);
410 	if (!m)
411 		return false;
412 	if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
413 	    (m[len] == 0 || m[len] == ';'))
414 		return true;
415 	return false;
416 }
417 
418 static bool match_pe_metric(struct pmu_event *pe, const char *metric)
419 {
420 	return match_metric(pe->metric_group, metric) ||
421 	       match_metric(pe->metric_name, metric);
422 }
423 
424 struct mep {
425 	struct rb_node nd;
426 	const char *name;
427 	struct strlist *metrics;
428 };
429 
430 static int mep_cmp(struct rb_node *rb_node, const void *entry)
431 {
432 	struct mep *a = container_of(rb_node, struct mep, nd);
433 	struct mep *b = (struct mep *)entry;
434 
435 	return strcmp(a->name, b->name);
436 }
437 
438 static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
439 					const void *entry)
440 {
441 	struct mep *me = malloc(sizeof(struct mep));
442 
443 	if (!me)
444 		return NULL;
445 	memcpy(me, entry, sizeof(struct mep));
446 	me->name = strdup(me->name);
447 	if (!me->name)
448 		goto out_me;
449 	me->metrics = strlist__new(NULL, NULL);
450 	if (!me->metrics)
451 		goto out_name;
452 	return &me->nd;
453 out_name:
454 	zfree(&me->name);
455 out_me:
456 	free(me);
457 	return NULL;
458 }
459 
460 static struct mep *mep_lookup(struct rblist *groups, const char *name)
461 {
462 	struct rb_node *nd;
463 	struct mep me = {
464 		.name = name
465 	};
466 	nd = rblist__find(groups, &me);
467 	if (nd)
468 		return container_of(nd, struct mep, nd);
469 	rblist__add_node(groups, &me);
470 	nd = rblist__find(groups, &me);
471 	if (nd)
472 		return container_of(nd, struct mep, nd);
473 	return NULL;
474 }
475 
476 static void mep_delete(struct rblist *rl __maybe_unused,
477 		       struct rb_node *nd)
478 {
479 	struct mep *me = container_of(nd, struct mep, nd);
480 
481 	strlist__delete(me->metrics);
482 	zfree(&me->name);
483 	free(me);
484 }
485 
486 static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
487 {
488 	struct str_node *sn;
489 	int n = 0;
490 
491 	strlist__for_each_entry (sn, metrics) {
492 		if (raw)
493 			printf("%s%s", n > 0 ? " " : "", sn->s);
494 		else
495 			printf("  %s\n", sn->s);
496 		n++;
497 	}
498 	if (raw)
499 		putchar('\n');
500 }
501 
502 static int metricgroup__print_pmu_event(struct pmu_event *pe,
503 					bool metricgroups, char *filter,
504 					bool raw, bool details,
505 					struct rblist *groups,
506 					struct strlist *metriclist)
507 {
508 	const char *g;
509 	char *omg, *mg;
510 
511 	g = pe->metric_group;
512 	if (!g && pe->metric_name) {
513 		if (pe->name)
514 			return 0;
515 		g = "No_group";
516 	}
517 
518 	if (!g)
519 		return 0;
520 
521 	mg = strdup(g);
522 
523 	if (!mg)
524 		return -ENOMEM;
525 	omg = mg;
526 	while ((g = strsep(&mg, ";")) != NULL) {
527 		struct mep *me;
528 		char *s;
529 
530 		g = skip_spaces(g);
531 		if (*g == 0)
532 			g = "No_group";
533 		if (filter && !strstr(g, filter))
534 			continue;
535 		if (raw)
536 			s = (char *)pe->metric_name;
537 		else {
538 			if (asprintf(&s, "%s\n%*s%s]",
539 				     pe->metric_name, 8, "[", pe->desc) < 0)
540 				return -1;
541 			if (details) {
542 				if (asprintf(&s, "%s\n%*s%s]",
543 					     s, 8, "[", pe->metric_expr) < 0)
544 					return -1;
545 			}
546 		}
547 
548 		if (!s)
549 			continue;
550 
551 		if (!metricgroups) {
552 			strlist__add(metriclist, s);
553 		} else {
554 			me = mep_lookup(groups, g);
555 			if (!me)
556 				continue;
557 			strlist__add(me->metrics, s);
558 		}
559 
560 		if (!raw)
561 			free(s);
562 	}
563 	free(omg);
564 
565 	return 0;
566 }
567 
568 struct metricgroup_print_sys_idata {
569 	struct strlist *metriclist;
570 	char *filter;
571 	struct rblist *groups;
572 	bool metricgroups;
573 	bool raw;
574 	bool details;
575 };
576 
577 typedef int (*metricgroup_sys_event_iter_fn)(struct pmu_event *pe, void *);
578 
579 struct metricgroup_iter_data {
580 	metricgroup_sys_event_iter_fn fn;
581 	void *data;
582 };
583 
584 static int metricgroup__sys_event_iter(struct pmu_event *pe, void *data)
585 {
586 	struct metricgroup_iter_data *d = data;
587 	struct perf_pmu *pmu = NULL;
588 
589 	if (!pe->metric_expr || !pe->compat)
590 		return 0;
591 
592 	while ((pmu = perf_pmu__scan(pmu))) {
593 
594 		if (!pmu->id || strcmp(pmu->id, pe->compat))
595 			continue;
596 
597 		return d->fn(pe, d->data);
598 	}
599 
600 	return 0;
601 }
602 
603 static int metricgroup__print_sys_event_iter(struct pmu_event *pe, void *data)
604 {
605 	struct metricgroup_print_sys_idata *d = data;
606 
607 	return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw,
608 				     d->details, d->groups, d->metriclist);
609 }
610 
611 void metricgroup__print(bool metrics, bool metricgroups, char *filter,
612 			bool raw, bool details)
613 {
614 	struct pmu_events_map *map = perf_pmu__find_map(NULL);
615 	struct pmu_event *pe;
616 	int i;
617 	struct rblist groups;
618 	struct rb_node *node, *next;
619 	struct strlist *metriclist = NULL;
620 
621 	if (!metricgroups) {
622 		metriclist = strlist__new(NULL, NULL);
623 		if (!metriclist)
624 			return;
625 	}
626 
627 	rblist__init(&groups);
628 	groups.node_new = mep_new;
629 	groups.node_cmp = mep_cmp;
630 	groups.node_delete = mep_delete;
631 	for (i = 0; map; i++) {
632 		pe = &map->table[i];
633 
634 		if (!pe->name && !pe->metric_group && !pe->metric_name)
635 			break;
636 		if (!pe->metric_expr)
637 			continue;
638 		if (metricgroup__print_pmu_event(pe, metricgroups, filter,
639 						 raw, details, &groups,
640 						 metriclist) < 0)
641 			return;
642 	}
643 
644 	{
645 		struct metricgroup_iter_data data = {
646 			.fn = metricgroup__print_sys_event_iter,
647 			.data = (void *) &(struct metricgroup_print_sys_idata){
648 				.metriclist = metriclist,
649 				.metricgroups = metricgroups,
650 				.filter = filter,
651 				.raw = raw,
652 				.details = details,
653 				.groups = &groups,
654 			},
655 		};
656 
657 		pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
658 	}
659 
660 	if (!filter || !rblist__empty(&groups)) {
661 		if (metricgroups && !raw)
662 			printf("\nMetric Groups:\n\n");
663 		else if (metrics && !raw)
664 			printf("\nMetrics:\n\n");
665 	}
666 
667 	for (node = rb_first_cached(&groups.entries); node; node = next) {
668 		struct mep *me = container_of(node, struct mep, nd);
669 
670 		if (metricgroups)
671 			printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n");
672 		if (metrics)
673 			metricgroup__print_strlist(me->metrics, raw);
674 		next = rb_next(node);
675 		rblist__remove_node(&groups, node);
676 	}
677 	if (!metricgroups)
678 		metricgroup__print_strlist(metriclist, raw);
679 	strlist__delete(metriclist);
680 }
681 
682 static void metricgroup__add_metric_weak_group(struct strbuf *events,
683 					       struct expr_parse_ctx *ctx)
684 {
685 	struct hashmap_entry *cur;
686 	size_t bkt;
687 	bool no_group = true, has_duration = false;
688 
689 	hashmap__for_each_entry((&ctx->ids), cur, bkt) {
690 		pr_debug("found event %s\n", (const char *)cur->key);
691 		/*
692 		 * Duration time maps to a software event and can make
693 		 * groups not count. Always use it outside a
694 		 * group.
695 		 */
696 		if (!strcmp(cur->key, "duration_time")) {
697 			has_duration = true;
698 			continue;
699 		}
700 		strbuf_addf(events, "%s%s",
701 			no_group ? "{" : ",",
702 			(const char *)cur->key);
703 		no_group = false;
704 	}
705 	if (!no_group) {
706 		strbuf_addf(events, "}:W");
707 		if (has_duration)
708 			strbuf_addf(events, ",duration_time");
709 	} else if (has_duration)
710 		strbuf_addf(events, "duration_time");
711 }
712 
713 static void metricgroup__add_metric_non_group(struct strbuf *events,
714 					      struct expr_parse_ctx *ctx)
715 {
716 	struct hashmap_entry *cur;
717 	size_t bkt;
718 	bool first = true;
719 
720 	hashmap__for_each_entry((&ctx->ids), cur, bkt) {
721 		if (!first)
722 			strbuf_addf(events, ",");
723 		strbuf_addf(events, "%s", (const char *)cur->key);
724 		first = false;
725 	}
726 }
727 
728 static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
729 {
730 	static bool violate_nmi_constraint;
731 
732 	if (!foot) {
733 		pr_warning("Splitting metric group %s into standalone metrics.\n", name);
734 		violate_nmi_constraint = true;
735 		return;
736 	}
737 
738 	if (!violate_nmi_constraint)
739 		return;
740 
741 	pr_warning("Try disabling the NMI watchdog to comply NO_NMI_WATCHDOG metric constraint:\n"
742 		   "    echo 0 > /proc/sys/kernel/nmi_watchdog\n"
743 		   "    perf stat ...\n"
744 		   "    echo 1 > /proc/sys/kernel/nmi_watchdog\n");
745 }
746 
747 static bool metricgroup__has_constraint(struct pmu_event *pe)
748 {
749 	if (!pe->metric_constraint)
750 		return false;
751 
752 	if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") &&
753 	    sysctl__nmi_watchdog_enabled()) {
754 		metricgroup___watchdog_constraint_hint(pe->metric_name, false);
755 		return true;
756 	}
757 
758 	return false;
759 }
760 
761 int __weak arch_get_runtimeparam(struct pmu_event *pe __maybe_unused)
762 {
763 	return 1;
764 }
765 
766 struct metricgroup_add_iter_data {
767 	struct list_head *metric_list;
768 	const char *metric;
769 	struct metric **m;
770 	struct expr_ids *ids;
771 	int *ret;
772 	bool *has_match;
773 	bool metric_no_group;
774 };
775 
776 static int __add_metric(struct list_head *metric_list,
777 			struct pmu_event *pe,
778 			bool metric_no_group,
779 			int runtime,
780 			struct metric **mp,
781 			struct expr_id *parent,
782 			struct expr_ids *ids)
783 {
784 	struct metric_ref_node *ref;
785 	struct metric *m;
786 
787 	if (*mp == NULL) {
788 		/*
789 		 * We got in here for the parent group,
790 		 * allocate it and put it on the list.
791 		 */
792 		m = zalloc(sizeof(*m));
793 		if (!m)
794 			return -ENOMEM;
795 
796 		expr__ctx_init(&m->pctx);
797 		m->metric_name = pe->metric_name;
798 		m->metric_expr = pe->metric_expr;
799 		m->metric_unit = pe->unit;
800 		m->runtime = runtime;
801 		m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
802 		INIT_LIST_HEAD(&m->metric_refs);
803 		m->metric_refs_cnt = 0;
804 
805 		parent = expr_ids__alloc(ids);
806 		if (!parent) {
807 			free(m);
808 			return -EINVAL;
809 		}
810 
811 		parent->id = strdup(pe->metric_name);
812 		if (!parent->id) {
813 			free(m);
814 			return -ENOMEM;
815 		}
816 		*mp = m;
817 	} else {
818 		/*
819 		 * We got here for the referenced metric, via the
820 		 * recursive metricgroup__add_metric call, add
821 		 * it to the parent group.
822 		 */
823 		m = *mp;
824 
825 		ref = malloc(sizeof(*ref));
826 		if (!ref)
827 			return -ENOMEM;
828 
829 		/*
830 		 * Intentionally passing just const char pointers,
831 		 * from 'pe' object, so they never go away. We don't
832 		 * need to change them, so there's no need to create
833 		 * our own copy.
834 		 */
835 		ref->metric_name = pe->metric_name;
836 		ref->metric_expr = pe->metric_expr;
837 
838 		list_add(&ref->list, &m->metric_refs);
839 		m->metric_refs_cnt++;
840 	}
841 
842 	/* Force all found IDs in metric to have us as parent ID. */
843 	WARN_ON_ONCE(!parent);
844 	m->pctx.parent = parent;
845 
846 	/*
847 	 * For both the parent and referenced metrics, we parse
848 	 * all the metric's IDs and add it to the parent context.
849 	 */
850 	if (expr__find_other(pe->metric_expr, NULL, &m->pctx, runtime) < 0) {
851 		if (m->metric_refs_cnt == 0) {
852 			expr__ctx_clear(&m->pctx);
853 			free(m);
854 			*mp = NULL;
855 		}
856 		return -EINVAL;
857 	}
858 
859 	/*
860 	 * We add new group only in the 'parent' call,
861 	 * so bail out for referenced metric case.
862 	 */
863 	if (m->metric_refs_cnt)
864 		return 0;
865 
866 	if (list_empty(metric_list))
867 		list_add(&m->nd, metric_list);
868 	else {
869 		struct list_head *pos;
870 
871 		/* Place the largest groups at the front. */
872 		list_for_each_prev(pos, metric_list) {
873 			struct metric *old = list_entry(pos, struct metric, nd);
874 
875 			if (hashmap__size(&m->pctx.ids) <=
876 			    hashmap__size(&old->pctx.ids))
877 				break;
878 		}
879 		list_add(&m->nd, pos);
880 	}
881 
882 	return 0;
883 }
884 
885 #define map_for_each_event(__pe, __idx, __map)					\
886 	if (__map)								\
887 		for (__idx = 0, __pe = &__map->table[__idx];			\
888 		     __pe->name || __pe->metric_group || __pe->metric_name;	\
889 		     __pe = &__map->table[++__idx])
890 
891 #define map_for_each_metric(__pe, __idx, __map, __metric)		\
892 	map_for_each_event(__pe, __idx, __map)				\
893 		if (__pe->metric_expr &&				\
894 		    (match_metric(__pe->metric_group, __metric) ||	\
895 		     match_metric(__pe->metric_name, __metric)))
896 
897 static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *map)
898 {
899 	struct pmu_event *pe;
900 	int i;
901 
902 	map_for_each_event(pe, i, map) {
903 		if (match_metric(pe->metric_name, metric))
904 			return pe;
905 	}
906 
907 	return NULL;
908 }
909 
910 static int recursion_check(struct metric *m, const char *id, struct expr_id **parent,
911 			   struct expr_ids *ids)
912 {
913 	struct expr_id_data *data;
914 	struct expr_id *p;
915 	int ret;
916 
917 	/*
918 	 * We get the parent referenced by 'id' argument and
919 	 * traverse through all the parent object IDs to check
920 	 * if we already processed 'id', if we did, it's recursion
921 	 * and we fail.
922 	 */
923 	ret = expr__get_id(&m->pctx, id, &data);
924 	if (ret)
925 		return ret;
926 
927 	p = expr_id_data__parent(data);
928 
929 	while (p->parent) {
930 		if (!strcmp(p->id, id)) {
931 			pr_err("failed: recursion detected for %s\n", id);
932 			return -1;
933 		}
934 		p = p->parent;
935 	}
936 
937 	/*
938 	 * If we are over the limit of static entris, the metric
939 	 * is too difficult/nested to process, fail as well.
940 	 */
941 	p = expr_ids__alloc(ids);
942 	if (!p) {
943 		pr_err("failed: too many nested metrics\n");
944 		return -EINVAL;
945 	}
946 
947 	p->id     = strdup(id);
948 	p->parent = expr_id_data__parent(data);
949 	*parent   = p;
950 
951 	return p->id ? 0 : -ENOMEM;
952 }
953 
954 static int add_metric(struct list_head *metric_list,
955 		      struct pmu_event *pe,
956 		      bool metric_no_group,
957 		      struct metric **mp,
958 		      struct expr_id *parent,
959 		      struct expr_ids *ids);
960 
961 static int __resolve_metric(struct metric *m,
962 			    bool metric_no_group,
963 			    struct list_head *metric_list,
964 			    struct pmu_events_map *map,
965 			    struct expr_ids *ids)
966 {
967 	struct hashmap_entry *cur;
968 	size_t bkt;
969 	bool all;
970 	int ret;
971 
972 	/*
973 	 * Iterate all the parsed IDs and if there's metric,
974 	 * add it to the context.
975 	 */
976 	do {
977 		all = true;
978 		hashmap__for_each_entry((&m->pctx.ids), cur, bkt) {
979 			struct expr_id *parent;
980 			struct pmu_event *pe;
981 
982 			pe = find_metric(cur->key, map);
983 			if (!pe)
984 				continue;
985 
986 			ret = recursion_check(m, cur->key, &parent, ids);
987 			if (ret)
988 				return ret;
989 
990 			all = false;
991 			/* The metric key itself needs to go out.. */
992 			expr__del_id(&m->pctx, cur->key);
993 
994 			/* ... and it gets resolved to the parent context. */
995 			ret = add_metric(metric_list, pe, metric_no_group, &m, parent, ids);
996 			if (ret)
997 				return ret;
998 
999 			/*
1000 			 * We added new metric to hashmap, so we need
1001 			 * to break the iteration and start over.
1002 			 */
1003 			break;
1004 		}
1005 	} while (!all);
1006 
1007 	return 0;
1008 }
1009 
1010 static int resolve_metric(bool metric_no_group,
1011 			  struct list_head *metric_list,
1012 			  struct pmu_events_map *map,
1013 			  struct expr_ids *ids)
1014 {
1015 	struct metric *m;
1016 	int err;
1017 
1018 	list_for_each_entry(m, metric_list, nd) {
1019 		err = __resolve_metric(m, metric_no_group, metric_list, map, ids);
1020 		if (err)
1021 			return err;
1022 	}
1023 	return 0;
1024 }
1025 
1026 static int add_metric(struct list_head *metric_list,
1027 		      struct pmu_event *pe,
1028 		      bool metric_no_group,
1029 		      struct metric **m,
1030 		      struct expr_id *parent,
1031 		      struct expr_ids *ids)
1032 {
1033 	struct metric *orig = *m;
1034 	int ret = 0;
1035 
1036 	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
1037 
1038 	if (!strstr(pe->metric_expr, "?")) {
1039 		ret = __add_metric(metric_list, pe, metric_no_group, 1, m, parent, ids);
1040 	} else {
1041 		int j, count;
1042 
1043 		count = arch_get_runtimeparam(pe);
1044 
1045 		/* This loop is added to create multiple
1046 		 * events depend on count value and add
1047 		 * those events to metric_list.
1048 		 */
1049 
1050 		for (j = 0; j < count && !ret; j++, *m = orig)
1051 			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
1052 	}
1053 
1054 	return ret;
1055 }
1056 
1057 static int metricgroup__add_metric_sys_event_iter(struct pmu_event *pe,
1058 						  void *data)
1059 {
1060 	struct metricgroup_add_iter_data *d = data;
1061 	int ret;
1062 
1063 	if (!match_pe_metric(pe, d->metric))
1064 		return 0;
1065 
1066 	ret = add_metric(d->metric_list, pe, d->metric_no_group, d->m, NULL, d->ids);
1067 	if (ret)
1068 		return ret;
1069 
1070 	ret = resolve_metric(d->metric_no_group,
1071 				     d->metric_list, NULL, d->ids);
1072 	if (ret)
1073 		return ret;
1074 
1075 	*(d->has_match) = true;
1076 
1077 	return *d->ret;
1078 }
1079 
1080 static int metricgroup__add_metric(const char *metric, bool metric_no_group,
1081 				   struct strbuf *events,
1082 				   struct list_head *metric_list,
1083 				   struct pmu_events_map *map)
1084 {
1085 	struct expr_ids ids = { .cnt = 0, };
1086 	struct pmu_event *pe;
1087 	struct metric *m;
1088 	LIST_HEAD(list);
1089 	int i, ret;
1090 	bool has_match = false;
1091 
1092 	map_for_each_metric(pe, i, map, metric) {
1093 		has_match = true;
1094 		m = NULL;
1095 
1096 		ret = add_metric(&list, pe, metric_no_group, &m, NULL, &ids);
1097 		if (ret)
1098 			goto out;
1099 
1100 		/*
1101 		 * Process any possible referenced metrics
1102 		 * included in the expression.
1103 		 */
1104 		ret = resolve_metric(metric_no_group,
1105 				     &list, map, &ids);
1106 		if (ret)
1107 			goto out;
1108 	}
1109 
1110 	{
1111 		struct metricgroup_iter_data data = {
1112 			.fn = metricgroup__add_metric_sys_event_iter,
1113 			.data = (void *) &(struct metricgroup_add_iter_data) {
1114 				.metric_list = &list,
1115 				.metric = metric,
1116 				.metric_no_group = metric_no_group,
1117 				.m = &m,
1118 				.ids = &ids,
1119 				.has_match = &has_match,
1120 				.ret = &ret,
1121 			},
1122 		};
1123 
1124 		pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
1125 	}
1126 	/* End of pmu events. */
1127 	if (!has_match) {
1128 		ret = -EINVAL;
1129 		goto out;
1130 	}
1131 
1132 	list_for_each_entry(m, &list, nd) {
1133 		if (events->len > 0)
1134 			strbuf_addf(events, ",");
1135 
1136 		if (m->has_constraint) {
1137 			metricgroup__add_metric_non_group(events,
1138 							  &m->pctx);
1139 		} else {
1140 			metricgroup__add_metric_weak_group(events,
1141 							   &m->pctx);
1142 		}
1143 	}
1144 
1145 out:
1146 	/*
1147 	 * add to metric_list so that they can be released
1148 	 * even if it's failed
1149 	 */
1150 	list_splice(&list, metric_list);
1151 	expr_ids__exit(&ids);
1152 	return ret;
1153 }
1154 
1155 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
1156 					struct strbuf *events,
1157 					struct list_head *metric_list,
1158 					struct pmu_events_map *map)
1159 {
1160 	char *llist, *nlist, *p;
1161 	int ret = -EINVAL;
1162 
1163 	nlist = strdup(list);
1164 	if (!nlist)
1165 		return -ENOMEM;
1166 	llist = nlist;
1167 
1168 	strbuf_init(events, 100);
1169 	strbuf_addf(events, "%s", "");
1170 
1171 	while ((p = strsep(&llist, ",")) != NULL) {
1172 		ret = metricgroup__add_metric(p, metric_no_group, events,
1173 					      metric_list, map);
1174 		if (ret == -EINVAL) {
1175 			fprintf(stderr, "Cannot find metric or group `%s'\n",
1176 					p);
1177 			break;
1178 		}
1179 	}
1180 	free(nlist);
1181 
1182 	if (!ret)
1183 		metricgroup___watchdog_constraint_hint(NULL, true);
1184 
1185 	return ret;
1186 }
1187 
1188 static void metric__free_refs(struct metric *metric)
1189 {
1190 	struct metric_ref_node *ref, *tmp;
1191 
1192 	list_for_each_entry_safe(ref, tmp, &metric->metric_refs, list) {
1193 		list_del(&ref->list);
1194 		free(ref);
1195 	}
1196 }
1197 
1198 static void metricgroup__free_metrics(struct list_head *metric_list)
1199 {
1200 	struct metric *m, *tmp;
1201 
1202 	list_for_each_entry_safe (m, tmp, metric_list, nd) {
1203 		metric__free_refs(m);
1204 		expr__ctx_clear(&m->pctx);
1205 		list_del_init(&m->nd);
1206 		free(m);
1207 	}
1208 }
1209 
1210 static int parse_groups(struct evlist *perf_evlist, const char *str,
1211 			bool metric_no_group,
1212 			bool metric_no_merge,
1213 			struct perf_pmu *fake_pmu,
1214 			struct rblist *metric_events,
1215 			struct pmu_events_map *map)
1216 {
1217 	struct parse_events_error parse_error;
1218 	struct strbuf extra_events;
1219 	LIST_HEAD(metric_list);
1220 	int ret;
1221 
1222 	if (metric_events->nr_entries == 0)
1223 		metricgroup__rblist_init(metric_events);
1224 	ret = metricgroup__add_metric_list(str, metric_no_group,
1225 					   &extra_events, &metric_list, map);
1226 	if (ret)
1227 		goto out;
1228 	pr_debug("adding %s\n", extra_events.buf);
1229 	bzero(&parse_error, sizeof(parse_error));
1230 	ret = __parse_events(perf_evlist, extra_events.buf, &parse_error, fake_pmu);
1231 	if (ret) {
1232 		parse_events_print_error(&parse_error, extra_events.buf);
1233 		goto out;
1234 	}
1235 	ret = metricgroup__setup_events(&metric_list, metric_no_merge,
1236 					perf_evlist, metric_events);
1237 out:
1238 	metricgroup__free_metrics(&metric_list);
1239 	strbuf_release(&extra_events);
1240 	return ret;
1241 }
1242 
1243 int metricgroup__parse_groups(const struct option *opt,
1244 			      const char *str,
1245 			      bool metric_no_group,
1246 			      bool metric_no_merge,
1247 			      struct rblist *metric_events)
1248 {
1249 	struct evlist *perf_evlist = *(struct evlist **)opt->value;
1250 	struct pmu_events_map *map = perf_pmu__find_map(NULL);
1251 
1252 
1253 	return parse_groups(perf_evlist, str, metric_no_group,
1254 			    metric_no_merge, NULL, metric_events, map);
1255 }
1256 
1257 int metricgroup__parse_groups_test(struct evlist *evlist,
1258 				   struct pmu_events_map *map,
1259 				   const char *str,
1260 				   bool metric_no_group,
1261 				   bool metric_no_merge,
1262 				   struct rblist *metric_events)
1263 {
1264 	return parse_groups(evlist, str, metric_no_group,
1265 			    metric_no_merge, &perf_pmu__fake, metric_events, map);
1266 }
1267 
1268 bool metricgroup__has_metric(const char *metric)
1269 {
1270 	struct pmu_events_map *map = perf_pmu__find_map(NULL);
1271 	struct pmu_event *pe;
1272 	int i;
1273 
1274 	if (!map)
1275 		return false;
1276 
1277 	for (i = 0; ; i++) {
1278 		pe = &map->table[i];
1279 
1280 		if (!pe->name && !pe->metric_group && !pe->metric_name)
1281 			break;
1282 		if (!pe->metric_expr)
1283 			continue;
1284 		if (match_metric(pe->metric_name, metric))
1285 			return true;
1286 	}
1287 	return false;
1288 }
1289 
1290 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
1291 				    struct rblist *new_metric_events,
1292 				    struct rblist *old_metric_events)
1293 {
1294 	unsigned i;
1295 
1296 	for (i = 0; i < rblist__nr_entries(old_metric_events); i++) {
1297 		struct rb_node *nd;
1298 		struct metric_event *old_me, *new_me;
1299 		struct metric_expr *old_expr, *new_expr;
1300 		struct evsel *evsel;
1301 		size_t alloc_size;
1302 		int idx, nr;
1303 
1304 		nd = rblist__entry(old_metric_events, i);
1305 		old_me = container_of(nd, struct metric_event, nd);
1306 
1307 		evsel = evlist__find_evsel(evlist, old_me->evsel->idx);
1308 		if (!evsel)
1309 			return -EINVAL;
1310 		new_me = metricgroup__lookup(new_metric_events, evsel, true);
1311 		if (!new_me)
1312 			return -ENOMEM;
1313 
1314 		pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n",
1315 			 cgrp ? cgrp->name : "root", evsel->name, evsel->idx);
1316 
1317 		list_for_each_entry(old_expr, &old_me->head, nd) {
1318 			new_expr = malloc(sizeof(*new_expr));
1319 			if (!new_expr)
1320 				return -ENOMEM;
1321 
1322 			new_expr->metric_expr = old_expr->metric_expr;
1323 			new_expr->metric_name = old_expr->metric_name;
1324 			new_expr->metric_unit = old_expr->metric_unit;
1325 			new_expr->runtime = old_expr->runtime;
1326 
1327 			if (old_expr->metric_refs) {
1328 				/* calculate number of metric_events */
1329 				for (nr = 0; old_expr->metric_refs[nr].metric_name; nr++)
1330 					continue;
1331 				alloc_size = sizeof(*new_expr->metric_refs);
1332 				new_expr->metric_refs = calloc(nr + 1, alloc_size);
1333 				if (!new_expr->metric_refs) {
1334 					free(new_expr);
1335 					return -ENOMEM;
1336 				}
1337 
1338 				memcpy(new_expr->metric_refs, old_expr->metric_refs,
1339 				       nr * alloc_size);
1340 			} else {
1341 				new_expr->metric_refs = NULL;
1342 			}
1343 
1344 			/* calculate number of metric_events */
1345 			for (nr = 0; old_expr->metric_events[nr]; nr++)
1346 				continue;
1347 			alloc_size = sizeof(*new_expr->metric_events);
1348 			new_expr->metric_events = calloc(nr + 1, alloc_size);
1349 			if (!new_expr->metric_events) {
1350 				free(new_expr->metric_refs);
1351 				free(new_expr);
1352 				return -ENOMEM;
1353 			}
1354 
1355 			/* copy evsel in the same position */
1356 			for (idx = 0; idx < nr; idx++) {
1357 				evsel = old_expr->metric_events[idx];
1358 				evsel = evlist__find_evsel(evlist, evsel->idx);
1359 				if (evsel == NULL) {
1360 					free(new_expr->metric_events);
1361 					free(new_expr->metric_refs);
1362 					free(new_expr);
1363 					return -EINVAL;
1364 				}
1365 				new_expr->metric_events[idx] = evsel;
1366 			}
1367 
1368 			list_add(&new_expr->nd, &new_me->head);
1369 		}
1370 	}
1371 	return 0;
1372 }
1373