Commit 82bf311e authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo

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 1

Monitored 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 elapsed

After:
        25,034,418      cycles:u
       158,256,395      cycles:k

       1.036864497 seconds time elapsed

The perf_evsel__open fallback changes contributed by Andi Kleen.
Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20170726120206.9099-4-jolsa@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent f7794d52
...@@ -213,10 +213,20 @@ static void perf_stat__reset_stats(void) ...@@ -213,10 +213,20 @@ static void perf_stat__reset_stats(void)
static int create_perf_stat_counter(struct perf_evsel *evsel) static int create_perf_stat_counter(struct perf_evsel *evsel)
{ {
struct perf_event_attr *attr = &evsel->attr; 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 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
PERF_FORMAT_TOTAL_TIME_RUNNING; 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; attr->inherit = !no_inherit;
...@@ -333,13 +343,21 @@ static int read_counter(struct perf_evsel *counter) ...@@ -333,13 +343,21 @@ static int read_counter(struct perf_evsel *counter)
struct perf_counts_values *count; struct perf_counts_values *count;
count = perf_counts(counter->counts, cpu, thread); 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; counter->counts->scaled = -1;
perf_counts(counter->counts, cpu, thread)->ena = 0; perf_counts(counter->counts, cpu, thread)->ena = 0;
perf_counts(counter->counts, cpu, thread)->run = 0; perf_counts(counter->counts, cpu, thread)->run = 0;
return -1; return -1;
} }
count->loaded = false;
if (STAT_RECORD) { if (STAT_RECORD) {
if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { if (perf_evsel__write_stat_event(counter, cpu, thread, count)) {
pr_err("failed to write stat event\n"); pr_err("failed to write stat event\n");
...@@ -559,6 +577,11 @@ static int store_counter_ids(struct perf_evsel *counter) ...@@ -559,6 +577,11 @@ static int store_counter_ids(struct perf_evsel *counter)
return __store_counter_ids(counter, cpus, threads); 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) static int __run_perf_stat(int argc, const char **argv)
{ {
int interval = stat_config.interval; int interval = stat_config.interval;
...@@ -631,7 +654,8 @@ static int __run_perf_stat(int argc, const char **argv) ...@@ -631,7 +654,8 @@ static int __run_perf_stat(int argc, const char **argv)
if (l > unit_width) if (l > unit_width)
unit_width = l; unit_width = l;
if (STAT_RECORD && store_counter_ids(counter)) if (perf_evsel__should_store_id(counter) &&
store_counter_ids(counter))
return -1; return -1;
} }
......
...@@ -12,6 +12,7 @@ struct perf_counts_values { ...@@ -12,6 +12,7 @@ struct perf_counts_values {
}; };
u64 values[3]; u64 values[3];
}; };
bool loaded;
}; };
struct perf_counts { struct perf_counts {
......
...@@ -49,6 +49,7 @@ static struct { ...@@ -49,6 +49,7 @@ static struct {
bool clockid_wrong; bool clockid_wrong;
bool lbr_flags; bool lbr_flags;
bool write_backward; bool write_backward;
bool group_read;
} perf_missing_features; } perf_missing_features;
static clockid_t clockid; static clockid_t clockid;
...@@ -1321,6 +1322,7 @@ perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, ...@@ -1321,6 +1322,7 @@ perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread,
count->val = val; count->val = val;
count->ena = ena; count->ena = ena;
count->run = run; count->run = run;
count->loaded = true;
} }
static int static int
...@@ -1677,6 +1679,8 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, ...@@ -1677,6 +1679,8 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
if (perf_missing_features.lbr_flags) if (perf_missing_features.lbr_flags)
evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
PERF_SAMPLE_BRANCH_NO_CYCLES); 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: retry_sample_id:
if (perf_missing_features.sample_id_all) if (perf_missing_features.sample_id_all)
evsel->attr.sample_id_all = 0; evsel->attr.sample_id_all = 0;
...@@ -1832,6 +1836,12 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, ...@@ -1832,6 +1836,12 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
perf_missing_features.lbr_flags = true; perf_missing_features.lbr_flags = true;
pr_debug2("switching off branch sample type no (cycles/flags)\n"); pr_debug2("switching off branch sample type no (cycles/flags)\n");
goto fallback_missing_features; 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: out_close:
do { do {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment