Skip to content

Commit 83de0b7

Browse files
olsajiriacmel
authored andcommitted
perf metric: Collect referenced metrics in struct metric_ref_node
Collecting referenced metrics in struct metric_ref_node object, so we can process them later on. The change will parse nested metric names out of expression and 'resolve' them. All referenced metrics are dissolved into one context, meaning all nested metrics events and added to the parent context. Signed-off-by: Jiri Olsa <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Andi Kleen <[email protected]> Cc: John Garry <[email protected]> Cc: Michael Petlan <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Paul Clarke <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Link: http://lore.kernel.org/lkml/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent e7e1bad commit 83de0b7

File tree

1 file changed

+172
-16
lines changed

1 file changed

+172
-16
lines changed

tools/perf/util/metricgroup.c

+172-16
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,25 @@ void metricgroup__rblist_exit(struct rblist *metric_events)
102102
rblist__exit(metric_events);
103103
}
104104

105+
/*
106+
* A node in the list of referenced metrics. metric_expr
107+
* is held as a convenience to avoid a search through the
108+
* metric list.
109+
*/
110+
struct metric_ref_node {
111+
const char *metric_name;
112+
const char *metric_expr;
113+
struct list_head list;
114+
};
115+
105116
struct egroup {
106117
struct list_head nd;
107118
struct expr_parse_ctx pctx;
108119
const char *metric_name;
109120
const char *metric_expr;
110121
const char *metric_unit;
122+
struct list_head metric_refs;
123+
int metric_refs_cnt;
111124
int runtime;
112125
bool has_constraint;
113126
};
@@ -574,27 +587,72 @@ int __weak arch_get_runtimeparam(void)
574587
static int __add_metric(struct list_head *group_list,
575588
struct pmu_event *pe,
576589
bool metric_no_group,
577-
int runtime)
590+
int runtime,
591+
struct egroup **egp)
578592
{
593+
struct metric_ref_node *ref;
579594
struct egroup *eg;
580595

581-
eg = malloc(sizeof(*eg));
582-
if (!eg)
583-
return -ENOMEM;
596+
if (*egp == NULL) {
597+
/*
598+
* We got in here for the parent group,
599+
* allocate it and put it on the list.
600+
*/
601+
eg = malloc(sizeof(*eg));
602+
if (!eg)
603+
return -ENOMEM;
604+
605+
expr__ctx_init(&eg->pctx);
606+
eg->metric_name = pe->metric_name;
607+
eg->metric_expr = pe->metric_expr;
608+
eg->metric_unit = pe->unit;
609+
eg->runtime = runtime;
610+
eg->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
611+
INIT_LIST_HEAD(&eg->metric_refs);
612+
eg->metric_refs_cnt = 0;
613+
*egp = eg;
614+
} else {
615+
/*
616+
* We got here for the referenced metric, via the
617+
* recursive metricgroup__add_metric call, add
618+
* it to the parent group.
619+
*/
620+
eg = *egp;
621+
622+
ref = malloc(sizeof(*ref));
623+
if (!ref)
624+
return -ENOMEM;
584625

585-
expr__ctx_init(&eg->pctx);
586-
eg->metric_name = pe->metric_name;
587-
eg->metric_expr = pe->metric_expr;
588-
eg->metric_unit = pe->unit;
589-
eg->runtime = runtime;
590-
eg->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
626+
/*
627+
* Intentionally passing just const char pointers,
628+
* from 'pe' object, so they never go away. We don't
629+
* need to change them, so there's no need to create
630+
* our own copy.
631+
*/
632+
ref->metric_name = pe->metric_name;
633+
ref->metric_expr = pe->metric_expr;
634+
635+
list_add(&ref->list, &eg->metric_refs);
636+
eg->metric_refs_cnt++;
637+
}
591638

639+
/*
640+
* For both the parent and referenced metrics, we parse
641+
* all the metric's IDs and add it to the parent context.
642+
*/
592643
if (expr__find_other(pe->metric_expr, NULL, &eg->pctx, runtime) < 0) {
593644
expr__ctx_clear(&eg->pctx);
594645
free(eg);
595646
return -EINVAL;
596647
}
597648

649+
/*
650+
* We add new group only in the 'parent' call,
651+
* so bail out for referenced metric case.
652+
*/
653+
if (eg->metric_refs_cnt)
654+
return 0;
655+
598656
if (list_empty(group_list))
599657
list_add(&eg->nd, group_list);
600658
else {
@@ -625,16 +683,94 @@ static int __add_metric(struct list_head *group_list,
625683
(match_metric(__pe->metric_group, __metric) || \
626684
match_metric(__pe->metric_name, __metric)))
627685

686+
static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *map)
687+
{
688+
struct pmu_event *pe;
689+
int i;
690+
691+
map_for_each_event(pe, i, map) {
692+
if (match_metric(pe->metric_name, metric))
693+
return pe;
694+
}
695+
696+
return NULL;
697+
}
698+
628699
static int add_metric(struct list_head *group_list,
629700
struct pmu_event *pe,
630-
bool metric_no_group)
701+
bool metric_no_group,
702+
struct egroup **egp);
703+
704+
static int __resolve_metric(struct egroup *eg,
705+
bool metric_no_group,
706+
struct list_head *group_list,
707+
struct pmu_events_map *map)
631708
{
709+
struct hashmap_entry *cur;
710+
size_t bkt;
711+
bool all;
712+
int ret;
713+
714+
/*
715+
* Iterate all the parsed IDs and if there's metric,
716+
* add it to the context.
717+
*/
718+
do {
719+
all = true;
720+
hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
721+
struct pmu_event *pe;
722+
723+
pe = find_metric(cur->key, map);
724+
if (!pe)
725+
continue;
726+
727+
all = false;
728+
/* The metric key itself needs to go out.. */
729+
expr__del_id(&eg->pctx, cur->key);
730+
731+
/* ... and it gets resolved to the parent context. */
732+
ret = add_metric(group_list, pe, metric_no_group, &eg);
733+
if (ret)
734+
return ret;
735+
736+
/*
737+
* We added new metric to hashmap, so we need
738+
* to break the iteration and start over.
739+
*/
740+
break;
741+
}
742+
} while (!all);
743+
744+
return 0;
745+
}
746+
747+
static int resolve_metric(bool metric_no_group,
748+
struct list_head *metric_list,
749+
struct pmu_events_map *map)
750+
{
751+
struct egroup *eg;
752+
int err;
753+
754+
list_for_each_entry(eg, metric_list, nd) {
755+
err = __resolve_metric(eg, metric_no_group, metric_list, map);
756+
if (err)
757+
return err;
758+
}
759+
return 0;
760+
}
761+
762+
static int add_metric(struct list_head *group_list,
763+
struct pmu_event *pe,
764+
bool metric_no_group,
765+
struct egroup **egp)
766+
{
767+
struct egroup *orig = *egp;
632768
int ret = 0;
633769

634770
pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
635771

636772
if (!strstr(pe->metric_expr, "?")) {
637-
ret = __add_metric(group_list, pe, metric_no_group, 1);
773+
ret = __add_metric(group_list, pe, metric_no_group, 1, egp);
638774
} else {
639775
int j, count;
640776

@@ -645,9 +781,8 @@ static int add_metric(struct list_head *group_list,
645781
* those events to group_list.
646782
*/
647783

648-
for (j = 0; j < count && !ret; j++) {
649-
ret = __add_metric(group_list, pe, metric_no_group, j);
650-
}
784+
for (j = 0; j < count && !ret; j++, *egp = orig)
785+
ret = __add_metric(group_list, pe, metric_no_group, j, egp);
651786
}
652787

653788
return ret;
@@ -665,8 +800,18 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
665800

666801
map_for_each_metric(pe, i, map, metric) {
667802
has_match = true;
803+
eg = NULL;
804+
805+
ret = add_metric(group_list, pe, metric_no_group, &eg);
806+
if (ret)
807+
return ret;
668808

669-
ret = add_metric(group_list, pe, metric_no_group);
809+
/*
810+
* Process any possible referenced metrics
811+
* included in the expression.
812+
*/
813+
ret = resolve_metric(metric_no_group,
814+
group_list, map);
670815
if (ret)
671816
return ret;
672817
}
@@ -723,11 +868,22 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
723868
return ret;
724869
}
725870

871+
static void egroup__free_refs(struct egroup *egroup)
872+
{
873+
struct metric_ref_node *ref, *tmp;
874+
875+
list_for_each_entry_safe(ref, tmp, &egroup->metric_refs, list) {
876+
list_del(&ref->list);
877+
free(ref);
878+
}
879+
}
880+
726881
static void metricgroup__free_egroups(struct list_head *group_list)
727882
{
728883
struct egroup *eg, *egtmp;
729884

730885
list_for_each_entry_safe (eg, egtmp, group_list, nd) {
886+
egroup__free_refs(eg);
731887
expr__ctx_clear(&eg->pctx);
732888
list_del_init(&eg->nd);
733889
free(eg);

0 commit comments

Comments
 (0)