Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf evlist: Remove nr_groups

Maintaining the number of groups during event parsing is problematic
and since changing to sort/regroup events can only be computed by a
linear pass over the evlist. As the value is generally only used in
tests, rather than hold it in a variable compute it by passing over
the evlist when necessary.

This change highlights that libpfm's counting of groups with a single
entry disagreed with regular event parsing. The libpfm tests are
updated accordingly.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Kim Phillips <kim.phillips@amd.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Steinar H. Gunderson <sesse@google.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
9d2dc632 e733f87e

+45 -38
+17 -1
tools/lib/perf/evlist.c
··· 703 703 struct perf_evsel *first = list_entry(evlist->entries.next, 704 704 struct perf_evsel, node); 705 705 706 - evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0; 707 706 __perf_evlist__set_leader(&evlist->entries, first); 708 707 } 708 + } 709 + 710 + int perf_evlist__nr_groups(struct perf_evlist *evlist) 711 + { 712 + struct perf_evsel *evsel; 713 + int nr_groups = 0; 714 + 715 + perf_evlist__for_each_evsel(evlist, evsel) { 716 + /* 717 + * evsels by default have a nr_members of 1, and they are their 718 + * own leader. If the nr_members is >1 then this is an 719 + * indication of a group. 720 + */ 721 + if (evsel->leader == evsel && evsel->nr_members > 1) 722 + nr_groups++; 723 + } 724 + return nr_groups; 709 725 }
-1
tools/lib/perf/include/internal/evlist.h
··· 17 17 struct perf_evlist { 18 18 struct list_head entries; 19 19 int nr_entries; 20 - int nr_groups; 21 20 bool has_user_cpus; 22 21 bool needs_map_propagation; 23 22 /**
+1
tools/lib/perf/include/perf/evlist.h
··· 47 47 (pos) = perf_evlist__next_mmap((evlist), (pos), overwrite)) 48 48 49 49 LIBPERF_API void perf_evlist__set_leader(struct perf_evlist *evlist); 50 + LIBPERF_API int perf_evlist__nr_groups(struct perf_evlist *evlist); 50 51 #endif /* __LIBPERF_EVLIST_H */
+1 -1
tools/perf/builtin-record.c
··· 2474 2474 rec->tool.ordered_events = false; 2475 2475 } 2476 2476 2477 - if (!rec->evlist->core.nr_groups) 2477 + if (evlist__nr_groups(rec->evlist) == 0) 2478 2478 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 2479 2479 2480 2480 if (data->is_pipe) {
+1 -1
tools/perf/builtin-report.c
··· 1481 1481 1482 1482 setup_forced_leader(&report, session->evlist); 1483 1483 1484 - if (symbol_conf.group_sort_idx && !session->evlist->core.nr_groups) { 1484 + if (symbol_conf.group_sort_idx && evlist__nr_groups(session->evlist) == 0) { 1485 1485 parse_options_usage(NULL, options, "group-sort-idx", 0); 1486 1486 ret = -EINVAL; 1487 1487 goto error;
-1
tools/perf/tests/bpf.c
··· 153 153 } 154 154 155 155 evlist__splice_list_tail(evlist, &parse_state.list); 156 - evlist->core.nr_groups = parse_state.nr_groups; 157 156 158 157 evlist__config(evlist, &opts, NULL); 159 158
+11 -11
tools/perf/tests/parse-events.c
··· 53 53 struct evsel *evsel = evlist__first(evlist); 54 54 55 55 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 56 - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); 56 + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); 57 57 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); 58 58 TEST_ASSERT_VAL("wrong sample_type", 59 59 PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); ··· 66 66 struct evsel *evsel; 67 67 68 68 TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); 69 - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); 69 + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); 70 70 71 71 evlist__for_each_entry(evlist, evsel) { 72 72 TEST_ASSERT_VAL("wrong type", ··· 677 677 struct evsel *evsel, *leader; 678 678 679 679 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 680 - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); 680 + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); 681 681 682 682 /* instructions:k */ 683 683 evsel = leader = evlist__first(evlist); ··· 719 719 struct evsel *evsel, *leader; 720 720 721 721 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); 722 - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); 722 + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); 723 723 724 724 /* faults + :ku modifier */ 725 725 evsel = leader = evlist__first(evlist); ··· 775 775 struct evsel *evsel, *leader; 776 776 777 777 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); 778 - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); 778 + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist__nr_groups(evlist)); 779 779 780 780 /* group1 syscalls:sys_enter_openat:H */ 781 781 evsel = leader = evlist__first(evlist); ··· 868 868 struct evsel *evsel, *leader; 869 869 870 870 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 871 - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); 871 + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); 872 872 873 873 /* cycles:u + p */ 874 874 evsel = leader = evlist__first(evlist); ··· 912 912 struct evsel *evsel, *leader; 913 913 914 914 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); 915 - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); 915 + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist__nr_groups(evlist)); 916 916 917 917 /* cycles + G */ 918 918 evsel = leader = evlist__first(evlist); ··· 998 998 struct evsel *evsel, *leader; 999 999 1000 1000 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 1001 - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); 1001 + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); 1002 1002 1003 1003 /* cycles + :H group modifier */ 1004 1004 evsel = leader = evlist__first(evlist); ··· 1038 1038 struct evsel *evsel, *leader; 1039 1039 1040 1040 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 1041 - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); 1041 + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); 1042 1042 1043 1043 /* cycles + :G group modifier */ 1044 1044 evsel = leader = evlist__first(evlist); ··· 1078 1078 struct evsel *evsel, *leader; 1079 1079 1080 1080 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 1081 - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); 1081 + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); 1082 1082 1083 1083 /* cycles:G + :u group modifier */ 1084 1084 evsel = leader = evlist__first(evlist); ··· 1118 1118 struct evsel *evsel, *leader; 1119 1119 1120 1120 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 1121 - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); 1121 + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); 1122 1122 1123 1123 /* cycles:G + :uG group modifier */ 1124 1124 evsel = leader = evlist__first(evlist);
+6 -6
tools/perf/tests/pfm.c
··· 76 76 count_pfm_events(&evlist->core), 77 77 table[i].nr_events); 78 78 TEST_ASSERT_EQUAL(table[i].events, 79 - evlist->core.nr_groups, 79 + evlist__nr_groups(evlist), 80 80 0); 81 81 82 82 evlist__delete(evlist); ··· 103 103 { 104 104 .events = "{instructions}", 105 105 .nr_events = 1, 106 - .nr_groups = 1, 106 + .nr_groups = 0, 107 107 }, 108 108 { 109 109 .events = "{instructions},{}", 110 110 .nr_events = 1, 111 - .nr_groups = 1, 111 + .nr_groups = 0, 112 112 }, 113 113 { 114 114 .events = "{},{instructions}", 115 115 .nr_events = 1, 116 - .nr_groups = 1, 116 + .nr_groups = 0, 117 117 }, 118 118 { 119 119 .events = "{instructions},{instructions}", 120 120 .nr_events = 2, 121 - .nr_groups = 2, 121 + .nr_groups = 0, 122 122 }, 123 123 { 124 124 .events = "{instructions,cycles},{instructions,cycles}", ··· 161 161 count_pfm_events(&evlist->core), 162 162 table[i].nr_events); 163 163 TEST_ASSERT_EQUAL(table[i].events, 164 - evlist->core.nr_groups, 164 + evlist__nr_groups(evlist), 165 165 table[i].nr_groups); 166 166 167 167 evlist__delete(evlist);
+1 -1
tools/perf/util/evlist.c
··· 1777 1777 */ 1778 1778 void evlist__force_leader(struct evlist *evlist) 1779 1779 { 1780 - if (!evlist->core.nr_groups) { 1780 + if (evlist__nr_groups(evlist) == 0) { 1781 1781 struct evsel *leader = evlist__first(evlist); 1782 1782 1783 1783 evlist__set_leader(evlist);
+6
tools/perf/util/evlist.h
··· 9 9 #include <api/fd/array.h> 10 10 #include <internal/evlist.h> 11 11 #include <internal/evsel.h> 12 + #include <perf/evlist.h> 12 13 #include "events_stats.h" 13 14 #include "evsel.h" 14 15 #include <pthread.h> ··· 254 253 struct perf_evsel *evsel = perf_evlist__last(&evlist->core); 255 254 256 255 return container_of(evsel, struct evsel, core); 256 + } 257 + 258 + static inline int evlist__nr_groups(struct evlist *evlist) 259 + { 260 + return perf_evlist__nr_groups(&evlist->core); 257 261 } 258 262 259 263 int evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size);
+1 -2
tools/perf/util/header.c
··· 786 786 static int write_group_desc(struct feat_fd *ff, 787 787 struct evlist *evlist) 788 788 { 789 - u32 nr_groups = evlist->core.nr_groups; 789 + u32 nr_groups = evlist__nr_groups(evlist); 790 790 struct evsel *evsel; 791 791 int ret; 792 792 ··· 2807 2807 * Rebuild group relationship based on the group_desc 2808 2808 */ 2809 2809 session = container_of(ff->ph, struct perf_session, header); 2810 - session->evlist->core.nr_groups = nr_groups; 2811 2810 2812 2811 i = nr = 0; 2813 2812 evlist__for_each_entry(session->evlist, evsel) {
-1
tools/perf/util/parse-events.c
··· 2260 2260 if (!ret) { 2261 2261 struct evsel *last; 2262 2262 2263 - evlist->core.nr_groups += parse_state.nr_groups; 2264 2263 last = evlist__last(evlist); 2265 2264 last->cmdline_group_boundary = true; 2266 2265
-1
tools/perf/util/parse-events.h
··· 122 122 struct parse_events_state { 123 123 struct list_head list; 124 124 int idx; 125 - int nr_groups; 126 125 struct parse_events_error *error; 127 126 struct evlist *evlist; 128 127 struct list_head *terms;
-10
tools/perf/util/parse-events.y
··· 49 49 free(list_evsel); 50 50 } 51 51 52 - static void inc_group_count(struct list_head *list, 53 - struct parse_events_state *parse_state) 54 - { 55 - /* Count groups only have more than 1 members */ 56 - if (!list_is_last(list->next, list)) 57 - parse_state->nr_groups++; 58 - } 59 - 60 52 %} 61 53 62 54 %token PE_START_EVENTS PE_START_TERMS ··· 193 201 { 194 202 struct list_head *list = $3; 195 203 196 - inc_group_count(list, _parse_state); 197 204 /* Takes ownership of $1. */ 198 205 parse_events__set_leader($1, list); 199 206 $$ = list; ··· 202 211 { 203 212 struct list_head *list = $2; 204 213 205 - inc_group_count(list, _parse_state); 206 214 parse_events__set_leader(NULL, list); 207 215 $$ = list; 208 216 }
-1
tools/perf/util/pfm.c
··· 112 112 "cannot close a non-existing event group\n"); 113 113 goto error; 114 114 } 115 - evlist->core.nr_groups++; 116 115 grp_leader = NULL; 117 116 grp_evt = -1; 118 117 }