From 9c65aebb266f35b035c5d2a46a19b795d6bf23c8 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 24 Aug 2023 11:04:09 +0200 Subject: [PATCH] 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 --- src/perf_counters.cc | 15 ++++++++++++++- 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 3980ea05..417acdb1 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -57,9 +57,18 @@ size_t PerfCounterValues::Read(const std::vector& 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& counter_names) { + if (!counter_names.empty()) { + Initialize(); + } + // Valid counters will populate these arrays but we start empty std::vector valid_names; std::vector counter_ids; diff --git a/src/perf_counters.h b/src/perf_counters.h index 152a6f25..bf5eb6bc 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