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