perf stat: Enable group read of counters
Jiri Olsa
reviewerv2 cover perf stat: Enable group read of counters
hi,
sending changes to enable group read of perf counters for perf stat command. It allows us to read whole group of counters within single read syscall.
v2 changes:
- fixed release segfault reported by Arnaldo
- rebased to latest Arnaldo's perf/core
- patch 1 already merged in
Also available in here:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/stat_group
Not sure why we haven't supported yet, but anyway it was unavailable for some time due to a bug which was fixed
just recently via:
ba5213ae6b88 ("perf/core: Correct event creation with PERF_FORMAT_GROUP")
thanks,
jirka
---
Jiri Olsa (3):
perf tools: Add perf_evsel__read_size function perf tools: Add perf_evsel__read_counter function perf stat: Use group read for event groups
tools/perf/builtin-stat.c | 30 ++++++++++++++++++++--- tools/perf/util/counts.h | 1 + tools/perf/util/evsel.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/evsel.h | 2 ++ tools/perf/util/stat.c | 4 +++ tools/perf/util/stat.h | 5 ++-- 6 files changed, 175 insertions(+), 6 deletions(-)
Jiri Olsa
reviewerPATCH 1/3 perf tools: Add perf_evsel__read_size function
Currently we use the size of struct perf_counts_values to read the event, which prevents us to put any new member to the struct.
Adding perf_evsel__read_size to return size of the buffer needed for event read.
--- tools/perf/util/evsel.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
tools/perf/util/evsel.c +28 -1
@@ -1261,15 +1261,42 @@ void perf_counts_values__scale(struct perf_counts_values *count, *pscaled = scaled; } +static int perf_evsel__read_size (struct perf_evsel *evsel) +{ +u64 read_format = evsel->attr.read_format; +int entry =sizeof (u64);/* value */ +int size =0 ; +int nr =1 ; + +if (read_format &PERF_FORMAT_TOTAL_TIME_ENABLED ) + size +=sizeof (u64); + +if (read_format &PERF_FORMAT_TOTAL_TIME_RUNNING ) + size +=sizeof (u64); + +if (read_format &PERF_FORMAT_ID ) + entry +=sizeof (u64); + +if (read_format &PERF_FORMAT_GROUP ) { + nr = evsel->nr_members; + size +=sizeof (u64); + } + + size += entry * nr; +return size; +} +int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count) { +size_t size =perf_evsel__read_size (evsel); +memset (count,0 ,sizeof (*count));if (FD (evsel, cpu, thread) <0 )return -EINVAL ; -if (readn (FD (evsel, cpu, thread), count,sizeof (*count)) <=0 ) +if (readn (FD (evsel, cpu, thread), count->values, size) <=0 )return -errno;return 0 ;
Signature · 1 line
2.9.4
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf tools: Add perf_evsel__read_size function
perf tools: Add perf_evsel__read_size function
Commit-ID: de63403bfd14ae8d613f30c9a0d415581b4cb37e Gitweb: http://git.kernel.org/tip/de63403bfd14ae8d613f30c9a0d415581b4cb37e Author: Jiri Olsa <[email protected]> AuthorDate: Wed, 26 Jul 2017 14:02:04 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 26 Jul 2017 14:20:28 -0300
perf tools: Add perf_evsel__read_size function
Currently we use the size of struct perf_counts_values to read the event, which prevents us to put any new member to the struct.
Adding perf_evsel__read_size to return size of the buffer needed for event read.
--- tools/perf/util/evsel.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
tools/perf/util/evsel.c +28 -1
@@ -1261,15 +1261,42 @@ void perf_counts_values__scale(struct perf_counts_values *count, *pscaled = scaled; } +static int perf_evsel__read_size (struct perf_evsel *evsel) +{ +u64 read_format = evsel->attr.read_format; +int entry =sizeof (u64);/* value */ +int size =0 ; +int nr =1 ; + +if (read_format &PERF_FORMAT_TOTAL_TIME_ENABLED ) + size +=sizeof (u64); + +if (read_format &PERF_FORMAT_TOTAL_TIME_RUNNING ) + size +=sizeof (u64); + +if (read_format &PERF_FORMAT_ID ) + entry +=sizeof (u64); + +if (read_format &PERF_FORMAT_GROUP ) { + nr = evsel->nr_members; + size +=sizeof (u64); + } + + size += entry * nr; +return size; +} +int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count) { +size_t size =perf_evsel__read_size (evsel); +memset (count,0 ,sizeof (*count));if (FD (evsel, cpu, thread) <0 )return -EINVAL ; -if (readn (FD (evsel, cpu, thread), count,sizeof (*count)) <=0 ) +if (readn (FD (evsel, cpu, thread), count->values, size) <=0 )return -errno;return 0 ;
Jiri Olsa
reviewerPATCH 2/3 perf tools: Add perf_evsel__read_counter function
In reply to Jiri OlsaAdding perf_evsel__read_counter function to read single or group counter. After calling this function the counter's evsel::counts struct is filled with values for the counter and member of its group if there are any.
--- tools/perf/util/evsel.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 2 + tools/perf/util/stat.c | 4 ++ tools/perf/util/stat.h | 5 ++- 4 files changed, 109 insertions(+), 2 deletions(-)
tools/perf/util/evsel.c +100 -0
@@ -1302,6 +1302,106 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,return 0 ; } +static int +perf_evsel__read_one (struct perf_evsel *evsel,int cpu,int thread) +{ +struct perf_counts_values *count =perf_counts (evsel->counts, cpu, thread); + +return perf_evsel__read (evsel, cpu, thread, count); +} + +static void +perf_evsel__set_count (struct perf_evsel *counter,int cpu,int thread, +u64 val,u64 ena,u64 run) +{ +struct perf_counts_values *count; + + count =perf_counts (counter->counts, cpu, thread); + + count->val = val; + count->ena = ena; + count->run = run; +} + +static int +perf_evsel__process_group_data (struct perf_evsel *leader, +int cpu,int thread,u64 *data) +{ +u64 read_format = leader->attr.read_format; +struct sample_read_value *v; +u64 nr, ena =0 , run =0 , i; + + nr = *data++; + +if (nr != (u64 ) leader->nr_members) +return -EINVAL ; + +if (read_format &PERF_FORMAT_TOTAL_TIME_ENABLED ) + ena = *data++; + +if (read_format &PERF_FORMAT_TOTAL_TIME_RUNNING ) + run = *data++; + + v = (struct sample_read_value *) data; + +perf_evsel__set_count (leader, cpu, thread, + v[0 ].value, ena, run); + +for (i =1 ; i < nr; i++) { +struct perf_evsel *counter; + + counter =perf_evlist__id2evsel (leader->evlist, v[i].id); +if (!counter) +return -EINVAL ; + +perf_evsel__set_count (counter, cpu, thread, + v[i].value, ena, run); + } + +return 0 ; +} + +static int +perf_evsel__read_group (struct perf_evsel *leader,int cpu,int thread) +{ +struct perf_stat_evsel *ps = leader->priv; +u64 read_format = leader->attr.read_format; +int size =perf_evsel__read_size (leader); +u64 *data = ps->group_data; + +if (!(read_format &PERF_FORMAT_ID )) +return -EINVAL ; + +if (!perf_evsel__is_group_leader (leader)) +return -EINVAL ; + +if (!data) { + data =zalloc (size); +if (!data) +return -ENOMEM ; + + ps->group_data = data; + } + +if (FD (leader, cpu, thread) <0 ) +return -EINVAL ; + +if (readn (FD (leader, cpu, thread), data, size) <=0 ) +return -errno; + +return perf_evsel__process_group_data (leader, cpu, thread, data); +} + +int perf_evsel__read_counter (struct perf_evsel *evsel,int cpu,int thread) +{ +u64 read_format = evsel->attr.read_format; + +if (read_format &PERF_FORMAT_GROUP ) +return perf_evsel__read_group (evsel, cpu, thread); +else +return perf_evsel__read_one (evsel, cpu, thread); +} +int __perf_evsel__read_on_cpu (struct perf_evsel *evsel,int cpu,int thread,bool scale) {
tools/perf/util/evsel.h +2 -0
@@ -299,6 +299,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count); +int perf_evsel__read_counter (struct perf_evsel *evsel,int cpu,int thread); +int __perf_evsel__read_on_cpu (struct perf_evsel *evsel,int cpu,int thread,bool scale);
tools/perf/util/stat.c +4 -0
@@ -128,6 +128,10 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)static void perf_evsel__free_stat_priv (struct perf_evsel *evsel) { +struct perf_stat_evsel *ps = evsel->priv; + +if (ps) +free (ps->group_data);zfree (&evsel->priv); }
tools/perf/util/stat.h +3 -2
@@ -28,8 +28,9 @@ enum perf_stat_evsel_id { };struct perf_stat_evsel { -struct stats res_stats[3 ]; -enum perf_stat_evsel_id id; +struct stats res_stats[3 ]; +enum perf_stat_evsel_id id; +u64 *group_data; };enum aggr_mode {
Signature · 1 line
2.9.4
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf evsel: Add read_counter()
perf evsel: Add read_counter()
Commit-ID: f7794d525447f1e4e4b2228dd29dba084005e6bf Gitweb: http://git.kernel.org/tip/f7794d525447f1e4e4b2228dd29dba084005e6bf Author: Jiri Olsa <[email protected]> AuthorDate: Wed, 26 Jul 2017 14:02:05 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 26 Jul 2017 14:21:59 -0300
perf evsel: Add read_counter()
Add perf_evsel__read_counter() to read single or group counter. After calling this function the counter's evsel::counts struct is filled with values for the counter and member of its group if there are any.
--- tools/perf/util/evsel.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 2 + tools/perf/util/stat.c | 4 ++ tools/perf/util/stat.h | 5 ++- 4 files changed, 109 insertions(+), 2 deletions(-)
tools/perf/util/evsel.c +100 -0
@@ -1302,6 +1302,106 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,return 0 ; } +static int +perf_evsel__read_one (struct perf_evsel *evsel,int cpu,int thread) +{ +struct perf_counts_values *count =perf_counts (evsel->counts, cpu, thread); + +return perf_evsel__read (evsel, cpu, thread, count); +} + +static void +perf_evsel__set_count (struct perf_evsel *counter,int cpu,int thread, +u64 val,u64 ena,u64 run) +{ +struct perf_counts_values *count; + + count =perf_counts (counter->counts, cpu, thread); + + count->val = val; + count->ena = ena; + count->run = run; +} + +static int +perf_evsel__process_group_data (struct perf_evsel *leader, +int cpu,int thread,u64 *data) +{ +u64 read_format = leader->attr.read_format; +struct sample_read_value *v; +u64 nr, ena =0 , run =0 , i; + + nr = *data++; + +if (nr != (u64 ) leader->nr_members) +return -EINVAL ; + +if (read_format &PERF_FORMAT_TOTAL_TIME_ENABLED ) + ena = *data++; + +if (read_format &PERF_FORMAT_TOTAL_TIME_RUNNING ) + run = *data++; + + v = (struct sample_read_value *) data; + +perf_evsel__set_count (leader, cpu, thread, + v[0 ].value, ena, run); + +for (i =1 ; i < nr; i++) { +struct perf_evsel *counter; + + counter =perf_evlist__id2evsel (leader->evlist, v[i].id); +if (!counter) +return -EINVAL ; + +perf_evsel__set_count (counter, cpu, thread, + v[i].value, ena, run); + } + +return 0 ; +} + +static int +perf_evsel__read_group (struct perf_evsel *leader,int cpu,int thread) +{ +struct perf_stat_evsel *ps = leader->priv; +u64 read_format = leader->attr.read_format; +int size =perf_evsel__read_size (leader); +u64 *data = ps->group_data; + +if (!(read_format &PERF_FORMAT_ID )) +return -EINVAL ; + +if (!perf_evsel__is_group_leader (leader)) +return -EINVAL ; + +if (!data) { + data =zalloc (size); +if (!data) +return -ENOMEM ; + + ps->group_data = data; + } + +if (FD (leader, cpu, thread) <0 ) +return -EINVAL ; + +if (readn (FD (leader, cpu, thread), data, size) <=0 ) +return -errno; + +return perf_evsel__process_group_data (leader, cpu, thread, data); +} + +int perf_evsel__read_counter (struct perf_evsel *evsel,int cpu,int thread) +{ +u64 read_format = evsel->attr.read_format; + +if (read_format &PERF_FORMAT_GROUP ) +return perf_evsel__read_group (evsel, cpu, thread); +else +return perf_evsel__read_one (evsel, cpu, thread); +} +int __perf_evsel__read_on_cpu (struct perf_evsel *evsel,int cpu,int thread,bool scale) {
tools/perf/util/evsel.h +2 -0
@@ -299,6 +299,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count); +int perf_evsel__read_counter (struct perf_evsel *evsel,int cpu,int thread); +int __perf_evsel__read_on_cpu (struct perf_evsel *evsel,int cpu,int thread,bool scale);
tools/perf/util/stat.c +4 -0
@@ -128,6 +128,10 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)static void perf_evsel__free_stat_priv (struct perf_evsel *evsel) { +struct perf_stat_evsel *ps = evsel->priv; + +if (ps) +free (ps->group_data);zfree (&evsel->priv); }
tools/perf/util/stat.h +3 -2
@@ -28,8 +28,9 @@ enum perf_stat_evsel_id { };struct perf_stat_evsel { -struct stats res_stats[3 ]; -enum perf_stat_evsel_id id; +struct stats res_stats[3 ]; +enum perf_stat_evsel_id id; +u64 *group_data; };enum aggr_mode {
Jiri Olsa
reviewerPATCH 3/3 perf stat: Use group read for event groups
In reply to Jiri OlsaMake perf stat use group read if there are groups defined. The group read will get the values for all member of groups within a single syscall instead of calling read syscall for every event.
We can see considerable less amount of kernel cycles spent on single group read, than reading each event separately, like for following perf stat command:
# perf stat -e {cycles,instructions} -I 10 -a sleep 1Monitored with "perf stat -r 5 -e '{cycles:u,cycles:k}'"
Before:
24,325,676 cycles:u
297,040,775 cycles:k
1.038554134 seconds time elapsedAfter:
25,034,418 cycles:u
158,256,395 cycles:k
1.036864497 seconds time elapsedThe perf_evsel__open fallback changes contributed by Andi Kleen.
--- tools/perf/builtin-stat.c | 30 +++++++++++++++++++++++++++--- tools/perf/util/counts.h | 1 + tools/perf/util/evsel.c | 10 ++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-)
tools/perf/builtin-stat.c +27 -3
@@ -213,10 +213,20 @@ static void perf_stat__reset_stats(void)static int create_perf_stat_counter (struct perf_evsel *evsel) {struct perf_event_attr *attr = &evsel->attr; +struct perf_evsel *leader = evsel->leader; -if (stat_config.scale) +if (stat_config.scale) { attr->read_format =PERF_FORMAT_TOTAL_TIME_ENABLED |PERF_FORMAT_TOTAL_TIME_RUNNING ; + } + +/* +* The event is part of non trivial group, let's enable +* the group read (for leader) and ID retrieval for all +* members. +*/ +if (leader->nr_members >1 ) + attr->read_format |=PERF_FORMAT_ID |PERF_FORMAT_GROUP ; attr->inherit = !no_inherit;
@@ -333,13 +343,21 @@ static int read_counter(struct perf_evsel *counter)struct perf_counts_values *count; count =perf_counts (counter->counts, cpu, thread); -if (perf_evsel__read (counter, cpu, thread, count)) { + +/* +* The leader's group read loads data into its group members +* (via perf_evsel__read_counter) and sets threir count->loaded. +*/ +if (!count->loaded && +perf_evsel__read_counter (counter, cpu, thread)) { counter->counts->scaled =-1 ;perf_counts (counter->counts, cpu, thread)->ena =0 ;perf_counts (counter->counts, cpu, thread)->run =0 ;return -1 ; } + count->loaded = false; +if (STAT_RECORD ) {if (perf_evsel__write_stat_event (counter, cpu, thread, count)) {pr_err ("failed to write stat event\n" );
@@ -559,6 +577,11 @@ static int store_counter_ids(struct perf_evsel *counter)return __store_counter_ids (counter, cpus, threads); } +static bool perf_evsel__should_store_id (struct perf_evsel *counter) +{ +return STAT_RECORD || counter->attr.read_format &PERF_FORMAT_ID ; +} +static int __run_perf_stat (int argc,const char **argv) {int interval = stat_config.interval;
@@ -631,7 +654,8 @@ static int __run_perf_stat(int argc, const char **argv)if (l > unit_width) unit_width = l; -if (STAT_RECORD &&store_counter_ids (counter)) +if (perf_evsel__should_store_id (counter) && +store_counter_ids (counter))return -1 ; }
tools/perf/util/counts.h +1 -0
@@ -12,6 +12,7 @@ struct perf_counts_values { };u64 values[3 ]; }; +bool loaded; };struct perf_counts {
tools/perf/util/evsel.c +10 -0
@@ -49,6 +49,7 @@ static struct {bool clockid_wrong;bool lbr_flags;bool write_backward; +bool group_read; } perf_missing_features;static clockid_t clockid;
@@ -1321,6 +1322,7 @@ perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, count->val = val; count->ena = ena; count->run = run; + count->loaded = true; } static int
@@ -1677,6 +1679,8 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,if (perf_missing_features.lbr_flags) evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |PERF_SAMPLE_BRANCH_NO_CYCLES ); +if (perf_missing_features.group_read && evsel->attr.inherit) + evsel->attr.read_format &= ~(PERF_FORMAT_GROUP |PERF_FORMAT_ID ); retry_sample_id:if (perf_missing_features.sample_id_all) evsel->attr.sample_id_all =0 ;
@@ -1832,6 +1836,12 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, perf_missing_features.lbr_flags = true;pr_debug2 ("switching off branch sample type no (cycles/flags)\n" ); goto fallback_missing_features; + }else if (!perf_missing_features.group_read && + evsel->attr.inherit && + (evsel->attr.read_format &PERF_FORMAT_GROUP )) { + perf_missing_features.group_read = true; +pr_debug2 ("switching off group read\n" ); + goto fallback_missing_features; } out_close: do {
Signature · 1 line
2.9.4
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf stat: Use group read for event groups
perf stat: Use group read for event groups
Commit-ID: 82bf311e15d22e2fa45423b1fb4a21cf925381fe Gitweb: http://git.kernel.org/tip/82bf311e15d22e2fa45423b1fb4a21cf925381fe Author: Jiri Olsa <[email protected]> AuthorDate: Wed, 26 Jul 2017 14:02:06 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 26 Jul 2017 14:25:44 -0300
perf stat: Use group read for event groups
Make perf stat use group read if there are groups defined. The group read will get the values for all member of groups within a single syscall instead of calling read syscall for every event.
We can see considerable less amount of kernel cycles spent on single group read, than reading each event separately, like for following perf stat command:
# perf stat -e {cycles,instructions} -I 10 -a sleep 1Monitored with "perf stat -r 5 -e '{cycles:u,cycles:k}'"
Before:
24,325,676 cycles:u
297,040,775 cycles:k
1.038554134 seconds time elapsedAfter:
25,034,418 cycles:u
158,256,395 cycles:k
1.036864497 seconds time elapsedThe perf_evsel__open fallback changes contributed by Andi Kleen.
--- tools/perf/builtin-stat.c | 30 +++++++++++++++++++++++++++--- tools/perf/util/counts.h | 1 + tools/perf/util/evsel.c | 10 ++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-)
tools/perf/builtin-stat.c +27 -3
@@ -213,10 +213,20 @@ static void perf_stat__reset_stats(void)static int create_perf_stat_counter (struct perf_evsel *evsel) {struct perf_event_attr *attr = &evsel->attr; +struct perf_evsel *leader = evsel->leader; -if (stat_config.scale) +if (stat_config.scale) { attr->read_format =PERF_FORMAT_TOTAL_TIME_ENABLED |PERF_FORMAT_TOTAL_TIME_RUNNING ; + } + +/* +* The event is part of non trivial group, let's enable +* the group read (for leader) and ID retrieval for all +* members. +*/ +if (leader->nr_members >1 ) + attr->read_format |=PERF_FORMAT_ID |PERF_FORMAT_GROUP ; attr->inherit = !no_inherit;
@@ -333,13 +343,21 @@ static int read_counter(struct perf_evsel *counter)struct perf_counts_values *count; count =perf_counts (counter->counts, cpu, thread); -if (perf_evsel__read (counter, cpu, thread, count)) { + +/* +* The leader's group read loads data into its group members +* (via perf_evsel__read_counter) and sets threir count->loaded. +*/ +if (!count->loaded && +perf_evsel__read_counter (counter, cpu, thread)) { counter->counts->scaled =-1 ;perf_counts (counter->counts, cpu, thread)->ena =0 ;perf_counts (counter->counts, cpu, thread)->run =0 ;return -1 ; } + count->loaded = false; +if (STAT_RECORD ) {if (perf_evsel__write_stat_event (counter, cpu, thread, count)) {pr_err ("failed to write stat event\n" );
@@ -559,6 +577,11 @@ static int store_counter_ids(struct perf_evsel *counter)return __store_counter_ids (counter, cpus, threads); } +static bool perf_evsel__should_store_id (struct perf_evsel *counter) +{ +return STAT_RECORD || counter->attr.read_format &PERF_FORMAT_ID ; +} +static int __run_perf_stat (int argc,const char **argv) {int interval = stat_config.interval;
@@ -631,7 +654,8 @@ try_again:if (l > unit_width) unit_width = l; -if (STAT_RECORD &&store_counter_ids (counter)) +if (perf_evsel__should_store_id (counter) && +store_counter_ids (counter))return -1 ; }
tools/perf/util/counts.h +1 -0
@@ -12,6 +12,7 @@ struct perf_counts_values { };u64 values[3 ]; }; +bool loaded; };struct perf_counts {
tools/perf/util/evsel.c +10 -0
@@ -49,6 +49,7 @@ static struct {bool clockid_wrong;bool lbr_flags;bool write_backward; +bool group_read; } perf_missing_features;static clockid_t clockid;
@@ -1321,6 +1322,7 @@ perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, count->val = val; count->ena = ena; count->run = run; + count->loaded = true; } static int
@@ -1677,6 +1679,8 @@ fallback_missing_features:if (perf_missing_features.lbr_flags) evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |PERF_SAMPLE_BRANCH_NO_CYCLES ); +if (perf_missing_features.group_read && evsel->attr.inherit) + evsel->attr.read_format &= ~(PERF_FORMAT_GROUP |PERF_FORMAT_ID ); retry_sample_id:if (perf_missing_features.sample_id_all) evsel->attr.sample_id_all =0 ;
@@ -1832,6 +1836,12 @@ try_fallback: perf_missing_features.lbr_flags = true;pr_debug2 ("switching off branch sample type no (cycles/flags)\n" ); goto fallback_missing_features; + }else if (!perf_missing_features.group_read && + evsel->attr.inherit && + (evsel->attr.read_format &PERF_FORMAT_GROUP )) { + perf_missing_features.group_read = true; +pr_debug2 ("switching off group read\n" ); + goto fallback_missing_features; } out_close: do {