Skip to content

Commit d484361

Browse files
captain5050acmel
authored andcommitted
perf evlist: Reduce affinity use and move into iterator, fix no affinity
The evlist__for_each_cpu iterator will call sched_setaffitinity when moving between CPUs to avoid IPIs. If only 1 IPI is saved then this may be unprofitable as the delay to get scheduled may be considerable. This may be particularly true if reading an event group in `perf stat` in interval mode. Move the affinity handling completely into the iterator so that a single evlist__use_affinity can determine whether CPU affinities will be used. For `perf record` the change is minimal as the dummy event and the real event will always make the use of affinities the thing to do. In `perf stat`, tool events are ignored and affinities only used if >1 event on the same CPU occur. Determining if affinities are useful is done by evlist__use_affinity which tests per-event whether the event's PMU benefits from affinity use - it is assumed only perf event using PMUs do. Fix a bug where when there are no affinities that the CPU map iterator may reference a CPU not present in the initial evsel. Fix by making the iterator and non-iterator code common. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Andres Freund <andres@anarazel.de> Cc: Dapeng Mi <dapeng1.mi@linux.intel.com> Cc: Dr. David Alan Gilbert <linux@treblig.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Falcon <thomas.falcon@intel.com> Cc: Thomas Richter <tmricht@linux.ibm.com> Cc: Yang Li <yang.lee@linux.alibaba.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 4717291 commit d484361

5 files changed

Lines changed: 174 additions & 131 deletions

File tree

tools/perf/builtin-stat.c

Lines changed: 44 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -369,19 +369,11 @@ static int read_counter_cpu(struct evsel *counter, int cpu_map_idx)
369369
static int read_counters_with_affinity(void)
370370
{
371371
struct evlist_cpu_iterator evlist_cpu_itr;
372-
struct affinity saved_affinity, *affinity;
373372

374373
if (all_counters_use_bpf)
375374
return 0;
376375

377-
if (!target__has_cpu(&target) || target__has_per_thread(&target))
378-
affinity = NULL;
379-
else if (affinity__setup(&saved_affinity) < 0)
380-
return -1;
381-
else
382-
affinity = &saved_affinity;
383-
384-
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
376+
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
385377
struct evsel *counter = evlist_cpu_itr.evsel;
386378

387379
if (evsel__is_bpf(counter))
@@ -393,8 +385,6 @@ static int read_counters_with_affinity(void)
393385
if (!counter->err)
394386
counter->err = read_counter_cpu(counter, evlist_cpu_itr.cpu_map_idx);
395387
}
396-
if (affinity)
397-
affinity__cleanup(&saved_affinity);
398388

399389
return 0;
400390
}
@@ -793,7 +783,6 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
793783
const bool forks = (argc > 0);
794784
bool is_pipe = STAT_RECORD ? perf_stat.data.is_pipe : false;
795785
struct evlist_cpu_iterator evlist_cpu_itr;
796-
struct affinity saved_affinity, *affinity = NULL;
797786
int err, open_err = 0;
798787
bool second_pass = false, has_supported_counters;
799788

@@ -805,14 +794,6 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
805794
child_pid = evsel_list->workload.pid;
806795
}
807796

808-
if (!cpu_map__is_dummy(evsel_list->core.user_requested_cpus)) {
809-
if (affinity__setup(&saved_affinity) < 0) {
810-
err = -1;
811-
goto err_out;
812-
}
813-
affinity = &saved_affinity;
814-
}
815-
816797
evlist__for_each_entry(evsel_list, counter) {
817798
counter->reset_group = false;
818799
if (bpf_counter__load(counter, &target)) {
@@ -825,57 +806,56 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
825806

826807
evlist__reset_aggr_stats(evsel_list);
827808

828-
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
829-
counter = evlist_cpu_itr.evsel;
809+
/*
810+
* bperf calls evsel__open_per_cpu() in bperf__load(), so
811+
* no need to call it again here.
812+
*/
813+
if (!target.use_bpf) {
814+
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
815+
counter = evlist_cpu_itr.evsel;
830816

831-
/*
832-
* bperf calls evsel__open_per_cpu() in bperf__load(), so
833-
* no need to call it again here.
834-
*/
835-
if (target.use_bpf)
836-
break;
817+
if (counter->reset_group || !counter->supported)
818+
continue;
819+
if (evsel__is_bperf(counter))
820+
continue;
837821

838-
if (counter->reset_group || !counter->supported)
839-
continue;
840-
if (evsel__is_bperf(counter))
841-
continue;
822+
while (true) {
823+
if (create_perf_stat_counter(counter, &stat_config,
824+
evlist_cpu_itr.cpu_map_idx) == 0)
825+
break;
842826

843-
while (true) {
844-
if (create_perf_stat_counter(counter, &stat_config,
845-
evlist_cpu_itr.cpu_map_idx) == 0)
846-
break;
827+
open_err = errno;
828+
/*
829+
* Weak group failed. We cannot just undo this
830+
* here because earlier CPUs might be in group
831+
* mode, and the kernel doesn't support mixing
832+
* group and non group reads. Defer it to later.
833+
* Don't close here because we're in the wrong
834+
* affinity.
835+
*/
836+
if ((open_err == EINVAL || open_err == EBADF) &&
837+
evsel__leader(counter) != counter &&
838+
counter->weak_group) {
839+
evlist__reset_weak_group(evsel_list, counter, false);
840+
assert(counter->reset_group);
841+
counter->supported = true;
842+
second_pass = true;
843+
break;
844+
}
847845

848-
open_err = errno;
849-
/*
850-
* Weak group failed. We cannot just undo this here
851-
* because earlier CPUs might be in group mode, and the kernel
852-
* doesn't support mixing group and non group reads. Defer
853-
* it to later.
854-
* Don't close here because we're in the wrong affinity.
855-
*/
856-
if ((open_err == EINVAL || open_err == EBADF) &&
857-
evsel__leader(counter) != counter &&
858-
counter->weak_group) {
859-
evlist__reset_weak_group(evsel_list, counter, false);
860-
assert(counter->reset_group);
861-
counter->supported = true;
862-
second_pass = true;
863-
break;
846+
if (stat_handle_error(counter, open_err) != COUNTER_RETRY)
847+
break;
864848
}
865-
866-
if (stat_handle_error(counter, open_err) != COUNTER_RETRY)
867-
break;
868849
}
869850
}
870-
871851
if (second_pass) {
872852
/*
873853
* Now redo all the weak group after closing them,
874854
* and also close errored counters.
875855
*/
876856

877857
/* First close errored or weak retry */
878-
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
858+
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
879859
counter = evlist_cpu_itr.evsel;
880860

881861
if (!counter->reset_group && counter->supported)
@@ -884,7 +864,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
884864
perf_evsel__close_cpu(&counter->core, evlist_cpu_itr.cpu_map_idx);
885865
}
886866
/* Now reopen weak */
887-
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
867+
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
888868
counter = evlist_cpu_itr.evsel;
889869

890870
if (!counter->reset_group)
@@ -893,17 +873,18 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
893873
while (true) {
894874
pr_debug2("reopening weak %s\n", evsel__name(counter));
895875
if (create_perf_stat_counter(counter, &stat_config,
896-
evlist_cpu_itr.cpu_map_idx) == 0)
876+
evlist_cpu_itr.cpu_map_idx) == 0) {
877+
evlist_cpu_iterator__exit(&evlist_cpu_itr);
897878
break;
898-
879+
}
899880
open_err = errno;
900-
if (stat_handle_error(counter, open_err) != COUNTER_RETRY)
881+
if (stat_handle_error(counter, open_err) != COUNTER_RETRY) {
882+
evlist_cpu_iterator__exit(&evlist_cpu_itr);
901883
break;
884+
}
902885
}
903886
}
904887
}
905-
affinity__cleanup(affinity);
906-
affinity = NULL;
907888

908889
has_supported_counters = false;
909890
evlist__for_each_entry(evsel_list, counter) {
@@ -1065,7 +1046,6 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
10651046
if (forks)
10661047
evlist__cancel_workload(evsel_list);
10671048

1068-
affinity__cleanup(affinity);
10691049
return err;
10701050
}
10711051

0 commit comments

Comments
 (0)