xref: /aosp_15_r20/external/google-benchmark/src/perf_counters.h (revision dbb99499c3810fa1611fa2242a2fc446be01a57c)
1*dbb99499SAndroid Build Coastguard Worker // Copyright 2021 Google Inc. All rights reserved.
2*dbb99499SAndroid Build Coastguard Worker //
3*dbb99499SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*dbb99499SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*dbb99499SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*dbb99499SAndroid Build Coastguard Worker //
7*dbb99499SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*dbb99499SAndroid Build Coastguard Worker //
9*dbb99499SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*dbb99499SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*dbb99499SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*dbb99499SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*dbb99499SAndroid Build Coastguard Worker // limitations under the License.
14*dbb99499SAndroid Build Coastguard Worker 
15*dbb99499SAndroid Build Coastguard Worker #ifndef BENCHMARK_PERF_COUNTERS_H
16*dbb99499SAndroid Build Coastguard Worker #define BENCHMARK_PERF_COUNTERS_H
17*dbb99499SAndroid Build Coastguard Worker 
18*dbb99499SAndroid Build Coastguard Worker #include <array>
19*dbb99499SAndroid Build Coastguard Worker #include <cstdint>
20*dbb99499SAndroid Build Coastguard Worker #include <cstring>
21*dbb99499SAndroid Build Coastguard Worker #include <memory>
22*dbb99499SAndroid Build Coastguard Worker #include <vector>
23*dbb99499SAndroid Build Coastguard Worker 
24*dbb99499SAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
25*dbb99499SAndroid Build Coastguard Worker #include "check.h"
26*dbb99499SAndroid Build Coastguard Worker #include "log.h"
27*dbb99499SAndroid Build Coastguard Worker #include "mutex.h"
28*dbb99499SAndroid Build Coastguard Worker 
29*dbb99499SAndroid Build Coastguard Worker #ifndef BENCHMARK_OS_WINDOWS
30*dbb99499SAndroid Build Coastguard Worker #include <unistd.h>
31*dbb99499SAndroid Build Coastguard Worker #endif
32*dbb99499SAndroid Build Coastguard Worker 
33*dbb99499SAndroid Build Coastguard Worker #if defined(_MSC_VER)
34*dbb99499SAndroid Build Coastguard Worker #pragma warning(push)
35*dbb99499SAndroid Build Coastguard Worker // C4251: <symbol> needs to have dll-interface to be used by clients of class
36*dbb99499SAndroid Build Coastguard Worker #pragma warning(disable : 4251)
37*dbb99499SAndroid Build Coastguard Worker #endif
38*dbb99499SAndroid Build Coastguard Worker 
39*dbb99499SAndroid Build Coastguard Worker namespace benchmark {
40*dbb99499SAndroid Build Coastguard Worker namespace internal {
41*dbb99499SAndroid Build Coastguard Worker 
42*dbb99499SAndroid Build Coastguard Worker // Typically, we can only read a small number of counters. There is also a
43*dbb99499SAndroid Build Coastguard Worker // padding preceding counter values, when reading multiple counters with one
44*dbb99499SAndroid Build Coastguard Worker // syscall (which is desirable). PerfCounterValues abstracts these details.
45*dbb99499SAndroid Build Coastguard Worker // The implementation ensures the storage is inlined, and allows 0-based
46*dbb99499SAndroid Build Coastguard Worker // indexing into the counter values.
47*dbb99499SAndroid Build Coastguard Worker // The object is used in conjunction with a PerfCounters object, by passing it
48*dbb99499SAndroid Build Coastguard Worker // to Snapshot(). The Read() method relocates individual reads, discarding
49*dbb99499SAndroid Build Coastguard Worker // the initial padding from each group leader in the values buffer such that
50*dbb99499SAndroid Build Coastguard Worker // all user accesses through the [] operator are correct.
51*dbb99499SAndroid Build Coastguard Worker class BENCHMARK_EXPORT PerfCounterValues {
52*dbb99499SAndroid Build Coastguard Worker  public:
PerfCounterValues(size_t nr_counters)53*dbb99499SAndroid Build Coastguard Worker   explicit PerfCounterValues(size_t nr_counters) : nr_counters_(nr_counters) {
54*dbb99499SAndroid Build Coastguard Worker     BM_CHECK_LE(nr_counters_, kMaxCounters);
55*dbb99499SAndroid Build Coastguard Worker   }
56*dbb99499SAndroid Build Coastguard Worker 
57*dbb99499SAndroid Build Coastguard Worker   // We are reading correctly now so the values don't need to skip padding
58*dbb99499SAndroid Build Coastguard Worker   uint64_t operator[](size_t pos) const { return values_[pos]; }
59*dbb99499SAndroid Build Coastguard Worker 
60*dbb99499SAndroid Build Coastguard Worker   // Increased the maximum to 32 only since the buffer
61*dbb99499SAndroid Build Coastguard Worker   // is std::array<> backed
62*dbb99499SAndroid Build Coastguard Worker   static constexpr size_t kMaxCounters = 32;
63*dbb99499SAndroid Build Coastguard Worker 
64*dbb99499SAndroid Build Coastguard Worker  private:
65*dbb99499SAndroid Build Coastguard Worker   friend class PerfCounters;
66*dbb99499SAndroid Build Coastguard Worker   // Get the byte buffer in which perf counters can be captured.
67*dbb99499SAndroid Build Coastguard Worker   // This is used by PerfCounters::Read
get_data_buffer()68*dbb99499SAndroid Build Coastguard Worker   std::pair<char*, size_t> get_data_buffer() {
69*dbb99499SAndroid Build Coastguard Worker     return {reinterpret_cast<char*>(values_.data()),
70*dbb99499SAndroid Build Coastguard Worker             sizeof(uint64_t) * (kPadding + nr_counters_)};
71*dbb99499SAndroid Build Coastguard Worker   }
72*dbb99499SAndroid Build Coastguard Worker 
73*dbb99499SAndroid Build Coastguard Worker   // This reading is complex and as the goal of this class is to
74*dbb99499SAndroid Build Coastguard Worker   // abstract away the intrincacies of the reading process, this is
75*dbb99499SAndroid Build Coastguard Worker   // a better place for it
76*dbb99499SAndroid Build Coastguard Worker   size_t Read(const std::vector<int>& leaders);
77*dbb99499SAndroid Build Coastguard Worker 
78*dbb99499SAndroid Build Coastguard Worker   // Move the padding to 2 due to the reading algorithm (1st padding plus a
79*dbb99499SAndroid Build Coastguard Worker   // current read padding)
80*dbb99499SAndroid Build Coastguard Worker   static constexpr size_t kPadding = 2;
81*dbb99499SAndroid Build Coastguard Worker   std::array<uint64_t, kPadding + kMaxCounters> values_;
82*dbb99499SAndroid Build Coastguard Worker   const size_t nr_counters_;
83*dbb99499SAndroid Build Coastguard Worker };
84*dbb99499SAndroid Build Coastguard Worker 
85*dbb99499SAndroid Build Coastguard Worker // Collect PMU counters. The object, once constructed, is ready to be used by
86*dbb99499SAndroid Build Coastguard Worker // calling read(). PMU counter collection is enabled from the time create() is
87*dbb99499SAndroid Build Coastguard Worker // called, to obtain the object, until the object's destructor is called.
88*dbb99499SAndroid Build Coastguard Worker class BENCHMARK_EXPORT PerfCounters final {
89*dbb99499SAndroid Build Coastguard Worker  public:
90*dbb99499SAndroid Build Coastguard Worker   // True iff this platform supports performance counters.
91*dbb99499SAndroid Build Coastguard Worker   static const bool kSupported;
92*dbb99499SAndroid Build Coastguard Worker 
93*dbb99499SAndroid Build Coastguard Worker   // Returns an empty object
NoCounters()94*dbb99499SAndroid Build Coastguard Worker   static PerfCounters NoCounters() { return PerfCounters(); }
95*dbb99499SAndroid Build Coastguard Worker 
~PerfCounters()96*dbb99499SAndroid Build Coastguard Worker   ~PerfCounters() { CloseCounters(); }
97*dbb99499SAndroid Build Coastguard Worker   PerfCounters() = default;
98*dbb99499SAndroid Build Coastguard Worker   PerfCounters(PerfCounters&&) = default;
99*dbb99499SAndroid Build Coastguard Worker   PerfCounters(const PerfCounters&) = delete;
100*dbb99499SAndroid Build Coastguard Worker   PerfCounters& operator=(PerfCounters&&) noexcept;
101*dbb99499SAndroid Build Coastguard Worker   PerfCounters& operator=(const PerfCounters&) = delete;
102*dbb99499SAndroid Build Coastguard Worker 
103*dbb99499SAndroid Build Coastguard Worker   // Platform-specific implementations may choose to do some library
104*dbb99499SAndroid Build Coastguard Worker   // initialization here.
105*dbb99499SAndroid Build Coastguard Worker   static bool Initialize();
106*dbb99499SAndroid Build Coastguard Worker 
107*dbb99499SAndroid Build Coastguard Worker   // Check if the given counter is supported, if the app wants to
108*dbb99499SAndroid Build Coastguard Worker   // check before passing
109*dbb99499SAndroid Build Coastguard Worker   static bool IsCounterSupported(const std::string& name);
110*dbb99499SAndroid Build Coastguard Worker 
111*dbb99499SAndroid Build Coastguard Worker   // Return a PerfCounters object ready to read the counters with the names
112*dbb99499SAndroid Build Coastguard Worker   // specified. The values are user-mode only. The counter name format is
113*dbb99499SAndroid Build Coastguard Worker   // implementation and OS specific.
114*dbb99499SAndroid Build Coastguard Worker   // In case of failure, this method will in the worst case return an
115*dbb99499SAndroid Build Coastguard Worker   // empty object whose state will still be valid.
116*dbb99499SAndroid Build Coastguard Worker   static PerfCounters Create(const std::vector<std::string>& counter_names);
117*dbb99499SAndroid Build Coastguard Worker 
118*dbb99499SAndroid Build Coastguard Worker   // Take a snapshot of the current value of the counters into the provided
119*dbb99499SAndroid Build Coastguard Worker   // valid PerfCounterValues storage. The values are populated such that:
120*dbb99499SAndroid Build Coastguard Worker   // names()[i]'s value is (*values)[i]
Snapshot(PerfCounterValues * values)121*dbb99499SAndroid Build Coastguard Worker   BENCHMARK_ALWAYS_INLINE bool Snapshot(PerfCounterValues* values) const {
122*dbb99499SAndroid Build Coastguard Worker #ifndef BENCHMARK_OS_WINDOWS
123*dbb99499SAndroid Build Coastguard Worker     assert(values != nullptr);
124*dbb99499SAndroid Build Coastguard Worker     return values->Read(leader_ids_) == counter_ids_.size();
125*dbb99499SAndroid Build Coastguard Worker #else
126*dbb99499SAndroid Build Coastguard Worker     (void)values;
127*dbb99499SAndroid Build Coastguard Worker     return false;
128*dbb99499SAndroid Build Coastguard Worker #endif
129*dbb99499SAndroid Build Coastguard Worker   }
130*dbb99499SAndroid Build Coastguard Worker 
names()131*dbb99499SAndroid Build Coastguard Worker   const std::vector<std::string>& names() const { return counter_names_; }
num_counters()132*dbb99499SAndroid Build Coastguard Worker   size_t num_counters() const { return counter_names_.size(); }
133*dbb99499SAndroid Build Coastguard Worker 
134*dbb99499SAndroid Build Coastguard Worker  private:
PerfCounters(const std::vector<std::string> & counter_names,std::vector<int> && counter_ids,std::vector<int> && leader_ids)135*dbb99499SAndroid Build Coastguard Worker   PerfCounters(const std::vector<std::string>& counter_names,
136*dbb99499SAndroid Build Coastguard Worker                std::vector<int>&& counter_ids, std::vector<int>&& leader_ids)
137*dbb99499SAndroid Build Coastguard Worker       : counter_ids_(std::move(counter_ids)),
138*dbb99499SAndroid Build Coastguard Worker         leader_ids_(std::move(leader_ids)),
139*dbb99499SAndroid Build Coastguard Worker         counter_names_(counter_names) {}
140*dbb99499SAndroid Build Coastguard Worker 
141*dbb99499SAndroid Build Coastguard Worker   void CloseCounters() const;
142*dbb99499SAndroid Build Coastguard Worker 
143*dbb99499SAndroid Build Coastguard Worker   std::vector<int> counter_ids_;
144*dbb99499SAndroid Build Coastguard Worker   std::vector<int> leader_ids_;
145*dbb99499SAndroid Build Coastguard Worker   std::vector<std::string> counter_names_;
146*dbb99499SAndroid Build Coastguard Worker };
147*dbb99499SAndroid Build Coastguard Worker 
148*dbb99499SAndroid Build Coastguard Worker // Typical usage of the above primitives.
149*dbb99499SAndroid Build Coastguard Worker class BENCHMARK_EXPORT PerfCountersMeasurement final {
150*dbb99499SAndroid Build Coastguard Worker  public:
151*dbb99499SAndroid Build Coastguard Worker   PerfCountersMeasurement(const std::vector<std::string>& counter_names);
152*dbb99499SAndroid Build Coastguard Worker 
num_counters()153*dbb99499SAndroid Build Coastguard Worker   size_t num_counters() const { return counters_.num_counters(); }
154*dbb99499SAndroid Build Coastguard Worker 
names()155*dbb99499SAndroid Build Coastguard Worker   std::vector<std::string> names() const { return counters_.names(); }
156*dbb99499SAndroid Build Coastguard Worker 
Start()157*dbb99499SAndroid Build Coastguard Worker   BENCHMARK_ALWAYS_INLINE bool Start() {
158*dbb99499SAndroid Build Coastguard Worker     if (num_counters() == 0) return true;
159*dbb99499SAndroid Build Coastguard Worker     // Tell the compiler to not move instructions above/below where we take
160*dbb99499SAndroid Build Coastguard Worker     // the snapshot.
161*dbb99499SAndroid Build Coastguard Worker     ClobberMemory();
162*dbb99499SAndroid Build Coastguard Worker     valid_read_ &= counters_.Snapshot(&start_values_);
163*dbb99499SAndroid Build Coastguard Worker     ClobberMemory();
164*dbb99499SAndroid Build Coastguard Worker 
165*dbb99499SAndroid Build Coastguard Worker     return valid_read_;
166*dbb99499SAndroid Build Coastguard Worker   }
167*dbb99499SAndroid Build Coastguard Worker 
Stop(std::vector<std::pair<std::string,double>> & measurements)168*dbb99499SAndroid Build Coastguard Worker   BENCHMARK_ALWAYS_INLINE bool Stop(
169*dbb99499SAndroid Build Coastguard Worker       std::vector<std::pair<std::string, double>>& measurements) {
170*dbb99499SAndroid Build Coastguard Worker     if (num_counters() == 0) return true;
171*dbb99499SAndroid Build Coastguard Worker     // Tell the compiler to not move instructions above/below where we take
172*dbb99499SAndroid Build Coastguard Worker     // the snapshot.
173*dbb99499SAndroid Build Coastguard Worker     ClobberMemory();
174*dbb99499SAndroid Build Coastguard Worker     valid_read_ &= counters_.Snapshot(&end_values_);
175*dbb99499SAndroid Build Coastguard Worker     ClobberMemory();
176*dbb99499SAndroid Build Coastguard Worker 
177*dbb99499SAndroid Build Coastguard Worker     for (size_t i = 0; i < counters_.names().size(); ++i) {
178*dbb99499SAndroid Build Coastguard Worker       double measurement = static_cast<double>(end_values_[i]) -
179*dbb99499SAndroid Build Coastguard Worker                            static_cast<double>(start_values_[i]);
180*dbb99499SAndroid Build Coastguard Worker       measurements.push_back({counters_.names()[i], measurement});
181*dbb99499SAndroid Build Coastguard Worker     }
182*dbb99499SAndroid Build Coastguard Worker 
183*dbb99499SAndroid Build Coastguard Worker     return valid_read_;
184*dbb99499SAndroid Build Coastguard Worker   }
185*dbb99499SAndroid Build Coastguard Worker 
186*dbb99499SAndroid Build Coastguard Worker  private:
187*dbb99499SAndroid Build Coastguard Worker   PerfCounters counters_;
188*dbb99499SAndroid Build Coastguard Worker   bool valid_read_ = true;
189*dbb99499SAndroid Build Coastguard Worker   PerfCounterValues start_values_;
190*dbb99499SAndroid Build Coastguard Worker   PerfCounterValues end_values_;
191*dbb99499SAndroid Build Coastguard Worker };
192*dbb99499SAndroid Build Coastguard Worker 
193*dbb99499SAndroid Build Coastguard Worker }  // namespace internal
194*dbb99499SAndroid Build Coastguard Worker }  // namespace benchmark
195*dbb99499SAndroid Build Coastguard Worker 
196*dbb99499SAndroid Build Coastguard Worker #if defined(_MSC_VER)
197*dbb99499SAndroid Build Coastguard Worker #pragma warning(pop)
198*dbb99499SAndroid Build Coastguard Worker #endif
199*dbb99499SAndroid Build Coastguard Worker 
200*dbb99499SAndroid Build Coastguard Worker #endif  // BENCHMARK_PERF_COUNTERS_H
201