From cb5fc2d77a58c1e8f93353bf6826dcff22711309 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 24 Aug 2023 07:29:18 +0200 Subject: [PATCH 1/3] 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. --- 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 3980ea053e..a645d16641 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 +static bool InitLibPfmOnce() { + // Function-scope static gets initialized only once on first call. + static bool success = []() { return pfm_initialize() == PFM_SUCCESS; }(); + return success; +} + +bool PerfCounters::Initialize() { return InitLibPfmOnce(); } bool PerfCounters::IsCounterSupported(const std::string& name) { + InitLibPfmOnce(); 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()) { + InitLibPfmOnce(); + } + // 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 152a6f2561..bf5eb6bc3a 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 From 71a7d885307332b6ed9eabc190d6a8149c8ed646 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 24 Aug 2023 08:12:33 +0200 Subject: [PATCH 2/3] perf_counters: Make success var const --- src/perf_counters.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index a645d16641..2301b2eb26 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -61,7 +61,9 @@ const bool PerfCounters::kSupported = true; // initialization was successful static bool InitLibPfmOnce() { // Function-scope static gets initialized only once on first call. - static bool success = []() { return pfm_initialize() == PFM_SUCCESS; }(); + static const bool success = []() { + return pfm_initialize() == PFM_SUCCESS; + }(); return success; } From 834b252e677ae37c59f24b035b90f4828ad9c79a Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 24 Aug 2023 10:39:57 +0200 Subject: [PATCH 3/3] InitLibPfmOnce: Inline function --- src/perf_counters.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 2301b2eb26..417acdb18f 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -58,8 +58,8 @@ size_t PerfCounterValues::Read(const std::vector& leaders) { const bool PerfCounters::kSupported = true; // Initializes libpfm only on the first call. Returns whether that single -// initialization was successful -static bool InitLibPfmOnce() { +// 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; @@ -67,10 +67,8 @@ static bool InitLibPfmOnce() { return success; } -bool PerfCounters::Initialize() { return InitLibPfmOnce(); } - bool PerfCounters::IsCounterSupported(const std::string& name) { - InitLibPfmOnce(); + Initialize(); perf_event_attr_t attr; std::memset(&attr, 0, sizeof(attr)); pfm_perf_encode_arg_t arg; @@ -85,7 +83,7 @@ bool PerfCounters::IsCounterSupported(const std::string& name) { PerfCounters PerfCounters::Create( const std::vector& counter_names) { if (!counter_names.empty()) { - InitLibPfmOnce(); + Initialize(); } // Valid counters will populate these arrays but we start empty