@@ -102,12 +102,25 @@ void metricgroup__rblist_exit(struct rblist *metric_events)
102
102
rblist__exit (metric_events );
103
103
}
104
104
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
+
105
116
struct egroup {
106
117
struct list_head nd ;
107
118
struct expr_parse_ctx pctx ;
108
119
const char * metric_name ;
109
120
const char * metric_expr ;
110
121
const char * metric_unit ;
122
+ struct list_head metric_refs ;
123
+ int metric_refs_cnt ;
111
124
int runtime ;
112
125
bool has_constraint ;
113
126
};
@@ -574,27 +587,72 @@ int __weak arch_get_runtimeparam(void)
574
587
static int __add_metric (struct list_head * group_list ,
575
588
struct pmu_event * pe ,
576
589
bool metric_no_group ,
577
- int runtime )
590
+ int runtime ,
591
+ struct egroup * * egp )
578
592
{
593
+ struct metric_ref_node * ref ;
579
594
struct egroup * eg ;
580
595
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 ;
584
625
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
+ }
591
638
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
+ */
592
643
if (expr__find_other (pe -> metric_expr , NULL , & eg -> pctx , runtime ) < 0 ) {
593
644
expr__ctx_clear (& eg -> pctx );
594
645
free (eg );
595
646
return - EINVAL ;
596
647
}
597
648
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
+
598
656
if (list_empty (group_list ))
599
657
list_add (& eg -> nd , group_list );
600
658
else {
@@ -625,16 +683,94 @@ static int __add_metric(struct list_head *group_list,
625
683
(match_metric(__pe->metric_group, __metric) || \
626
684
match_metric(__pe->metric_name, __metric)))
627
685
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
+
628
699
static int add_metric (struct list_head * group_list ,
629
700
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 )
631
708
{
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 ;
632
768
int ret = 0 ;
633
769
634
770
pr_debug ("metric expr %s for %s\n" , pe -> metric_expr , pe -> metric_name );
635
771
636
772
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 );
638
774
} else {
639
775
int j , count ;
640
776
@@ -645,9 +781,8 @@ static int add_metric(struct list_head *group_list,
645
781
* those events to group_list.
646
782
*/
647
783
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 );
651
786
}
652
787
653
788
return ret ;
@@ -665,8 +800,18 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
665
800
666
801
map_for_each_metric (pe , i , map , metric ) {
667
802
has_match = true;
803
+ eg = NULL ;
804
+
805
+ ret = add_metric (group_list , pe , metric_no_group , & eg );
806
+ if (ret )
807
+ return ret ;
668
808
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 );
670
815
if (ret )
671
816
return ret ;
672
817
}
@@ -723,11 +868,22 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
723
868
return ret ;
724
869
}
725
870
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
+
726
881
static void metricgroup__free_egroups (struct list_head * group_list )
727
882
{
728
883
struct egroup * eg , * egtmp ;
729
884
730
885
list_for_each_entry_safe (eg , egtmp , group_list , nd ) {
886
+ egroup__free_refs (eg );
731
887
expr__ctx_clear (& eg -> pctx );
732
888
list_del_init (& eg -> nd );
733
889
free (eg );
0 commit comments