diff options
author | Jesse Rosenstock <jmr@google.com> | 2023-08-24 11:04:09 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-24 10:04:09 +0100 |
commit | 9c65aebb266f35b035c5d2a46a19b795d6bf23c8 (patch) | |
tree | b42c4ddfc318e961c4c6069dc462f76178ac74e0 | |
parent | e73915667c21faccd7019c6da8ab083b0264db13 (diff) | |
download | google-benchmark-9c65aebb266f35b035c5d2a46a19b795d6bf23c8.tar.gz |
perf_counters: Initialize once only when needed (#1656)
* perf_counters: Initialize once only when needed
This works around some performance problems running Android under QEMU.
Calling `pfm_initialize` was very slow, and was called during dynamic
initialization (before `main` or when loaded as a shared library).
This happened whenever benchmark was linked, even if no benchmarks
were run.
Instead, call `pfm_initialize` at most once, and only when one of:
1. `PerfCounters::Initialize` is called
2. `PerfCounters::Create` is called with a non-empty counter list
3. `PerfCounters::IsCounterSupported` is called
The return value of the first `pfm_initialize()` is saved and
returned from all subsequent `PerfCounters::Initialize` calls.
* perf_counters: Make success var const
* InitLibPfmOnce: Inline function
-rw-r--r-- | src/perf_counters.cc | 15 | ||||
-rw-r--r-- | src/perf_counters.h | 2 |
2 files changed, 14 insertions, 3 deletions
diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 3980ea0..417acdb 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -57,9 +57,18 @@ size_t PerfCounterValues::Read(const std::vector<int>& leaders) { const bool PerfCounters::kSupported = true; -bool PerfCounters::Initialize() { return pfm_initialize() == PFM_SUCCESS; } +// Initializes libpfm only on the first call. Returns whether that single +// initialization was successful. +bool PerfCounters::Initialize() { + // Function-scope static gets initialized only once on first call. + static const bool success = []() { + return pfm_initialize() == PFM_SUCCESS; + }(); + return success; +} bool PerfCounters::IsCounterSupported(const std::string& name) { + Initialize(); perf_event_attr_t attr; std::memset(&attr, 0, sizeof(attr)); pfm_perf_encode_arg_t arg; @@ -73,6 +82,10 @@ bool PerfCounters::IsCounterSupported(const std::string& name) { PerfCounters PerfCounters::Create( const std::vector<std::string>& counter_names) { + if (!counter_names.empty()) { + Initialize(); + } + // Valid counters will populate these arrays but we start empty std::vector<std::string> valid_names; std::vector<int> counter_ids; diff --git a/src/perf_counters.h b/src/perf_counters.h index 152a6f2..bf5eb6b 100644 --- a/src/perf_counters.h +++ b/src/perf_counters.h @@ -190,8 +190,6 @@ class BENCHMARK_EXPORT PerfCountersMeasurement final { PerfCounterValues end_values_; }; -BENCHMARK_UNUSED static bool perf_init_anchor = PerfCounters::Initialize(); - } // namespace internal } // namespace benchmark |