-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathCelero.h
313 lines (289 loc) · 17.6 KB
/
Celero.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#pragma once
///
/// \namespace celero
///
/// \author John Farrier
///
/// \copyright Copyright 2015-2023 John Farrier
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Special thanks to the bands "3" and "Coheed and Cambria" for providing the development soundtrack.
///
/// "Iterations" refers to how many loops of the test function are measured as a time.
/// For very fast code, many iterations would help amoratize measurement error.
///
/// "Samples" refers to how many sets of "Iterations" will be performed. Each "sample" is
/// a single measurement.
///
/// It is highly encouraged to only run this code compiled in a "Release" mode to use all available optimizations.
///
#ifdef _WIN32
#include <process.h>
#endif
#include <celero/Benchmark.h>
#include <celero/GenericFactory.h>
#include <celero/TestFixture.h>
#include <celero/ThreadTestFixture.h>
#include <celero/UserDefinedMeasurementCollector.h>
#include <celero/UserDefinedMeasurementTemplate.h>
#include <celero/Utilities.h>
namespace celero
{
///
/// \brief Adds a new test to the list of tests to be executed.
///
/// All tests must be registered prior to calling celer::Run().
///
/// \param groupName The name of the Test Group. Used for retrieving the associated baseline.
/// \param benchmarkName A unique name for a specific test within a Test Group.
/// \param samples The total number of times to execute the Test. (Each test contains iterations.)
/// \param iterations The total number of iterations per Test.
/// \param threads The total number of threads per Test sample.
/// \param experimentFactory The factory implementation for the test.
///
/// \returns a pointer to a Benchmark instance representing the given test.
///
CELERO_EXPORT std::shared_ptr<celero::Benchmark> RegisterTest(const char* groupName, const char* benchmarkName, const uint64_t samples,
const uint64_t iterations, const uint64_t threads,
std::shared_ptr<celero::Factory> experimentFactory, const double target = -1);
///
/// \brief Adds a new test baseline to the list of test baseliness to be executed.
///
/// All test baselines must be registered prior to calling celer::Run().
///
/// \param groupName The name of the Test Group that the baseline is associated with.
/// \param benchmarkName A unique name for a specific test baseline within a Test Group.
/// \param samples The total number of times to execute the Test baseline. (Each sample contains one or more iterations.)
/// \param iterations The total number of iterations per Test baseline sample.
/// \param threads The total number of threads per Test baseline.
/// \param experimentFactory The factory implementation for the test baseline.
///
/// \returns a pointer to a Benchmark instance representing the given test.
///
CELERO_EXPORT std::shared_ptr<Benchmark> RegisterBaseline(const char* groupName, const char* benchmarkName, const uint64_t samples,
const uint64_t iterations, const uint64_t threads,
std::shared_ptr<Factory> experimentFactory);
///
/// \brief Builds a distribution of total system measurement error.
///
/// The result vector contains microseconds for each trivial timer sample.
/// The purpose is to be able to characterize the generic distribution of results
/// on a given system.
///
/// This is just an attempt to characterize the distribution, not quantify it.
///
CELERO_EXPORT std::vector<uint64_t> BuildDistribution(uint64_t numberOfSamples, uint64_t iterationsPerSample);
///
/// \brief The main test executor.
///
CELERO_EXPORT void Run(int argc, char** argv);
} // namespace celero
///
/// \define CELERO_MAIN
///
/// \brief A macro to build the most basic main() required to run the benchmark tests.
///
#define CELERO_MAIN \
int main(int argc, char** argv) \
{ \
celero::Run(argc, argv); \
return 0; \
}
///
/// \define BENCHMARK_CLASS_NAME
///
/// \brief A macro to build a class name based on the test groupo and benchmark names.
///
#define BENCHMARK_CLASS_NAME(groupName, benchmarkName) CeleroUserBenchmark##_##groupName##_##benchmarkName
///
/// \define BENCHMARK_IMPL
///
/// A macro to create a class of a unique name which can be used to register and execute a benchmark test.
///
#define BENCHMARK_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads) \
class BENCHMARK_CLASS_NAME(groupName, benchmarkName) : public fixtureName \
{ \
public: \
BENCHMARK_CLASS_NAME(groupName, benchmarkName)() : fixtureName() \
{ \
} \
\
protected: \
void UserBenchmark() override; \
\
private: \
static const std::shared_ptr<::celero::Benchmark> info; \
}; \
\
const std::shared_ptr<::celero::Benchmark> BENCHMARK_CLASS_NAME(groupName, benchmarkName)::info = \
::celero::RegisterTest(#groupName, #benchmarkName, samples, iterations, threads, \
std::make_shared<::celero::GenericFactory<BENCHMARK_CLASS_NAME(groupName, benchmarkName)>>()); \
\
void BENCHMARK_CLASS_NAME(groupName, benchmarkName)::UserBenchmark()
///
/// \define BENCHMARK_TEST_IMPL
///
/// A macro to create a class of a unique name which can be used to register and execute a benchmark test.
///
#define BENCHMARK_TEST_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads, target) \
class BENCHMARK_CLASS_NAME(groupName, benchmarkName) : public fixtureName \
{ \
public: \
BENCHMARK_CLASS_NAME(groupName, benchmarkName)() : fixtureName() \
{ \
} \
\
protected: \
void UserBenchmark() override; \
\
private: \
static const std::shared_ptr<::celero::Benchmark> info; \
}; \
\
const std::shared_ptr<::celero::Benchmark> BENCHMARK_CLASS_NAME(groupName, benchmarkName)::info = \
::celero::RegisterTest(#groupName, #benchmarkName, samples, iterations, threads, \
std::make_shared<::celero::GenericFactory<BENCHMARK_CLASS_NAME(groupName, benchmarkName)>>(), target); \
\
void BENCHMARK_CLASS_NAME(groupName, benchmarkName)::UserBenchmark()
///
/// \define BENCHMARK_F
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a test fixture.
///
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BENCHMARK_F(groupName, benchmarkName, fixtureName, samples, iterations) \
BENCHMARK_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, 1)
///
/// \define BENCHMARK_T
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a threaded test fixture.
///
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BENCHMARK_T(groupName, benchmarkName, fixtureName, samples, iterations, threads) \
BENCHMARK_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads)
///
/// \define BENCHMARK_TEST_F
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a test fixture.
///
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BENCHMARK_TEST_F(groupName, benchmarkName, fixtureName, samples, iterations, target) \
BENCHMARK_TEST_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, 1, target)
///
/// \define BENCHMARK_TEST_T
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a threaded test fixture.
///
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BENCHMARK_TEST_T(groupName, benchmarkName, fixtureName, samples, iterations, threads, target) \
BENCHMARK_TEST_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads, target)
///
/// \define BENCHMARK
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark.
///
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BENCHMARK(groupName, benchmarkName, samples, iterations) \
BENCHMARK_IMPL(groupName, benchmarkName, ::celero::TestFixture, samples, iterations, 1)
///
/// \define BENCHMARK
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark.
///
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BENCHMARK_TEST(groupName, benchmarkName, samples, iterations, target) \
BENCHMARK_TEST_IMPL(groupName, benchmarkName, ::celero::TestFixture, samples, iterations, 1, target)
///
/// \define BASELINE_CLASS_NAME
///
/// \brief A macro to build a class name based on the test group and baseline names.
///
#define BASELINE_CLASS_NAME(groupName, baselineName) CeleroUserBaseline##_##groupName##_##baselineName
///
/// \define BASELINE_IMPL
///
/// A macro to create a class of a unique name which can be used to register and execute a baseline benchmark test.
///
#define BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, threads, useconds) \
class BASELINE_CLASS_NAME(groupName, baselineName) : public fixtureName \
{ \
public: \
BASELINE_CLASS_NAME(groupName, baselineName)() : fixtureName() \
{ \
} \
\
protected: \
void UserBenchmark() override; \
uint64_t HardCodedMeasurement() const override \
{ \
return uint64_t(useconds); \
} \
\
private: \
static const std::shared_ptr<::celero::Benchmark> info; \
}; \
\
const std::shared_ptr<::celero::Benchmark> BASELINE_CLASS_NAME(groupName, baselineName)::info = \
::celero::RegisterBaseline(#groupName, #baselineName, samples, iterations, threads, \
std::make_shared<::celero::GenericFactory<BASELINE_CLASS_NAME(groupName, baselineName)>>()); \
\
void BASELINE_CLASS_NAME(groupName, baselineName)::UserBenchmark()
///
/// \define BASELINE_F
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a test fixture.
///
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BASELINE_F(groupName, baselineName, fixtureName, samples, iterations) \
BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, 1, 0)
///
/// \define BASELINE_T
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a threaded test fixture.
///
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BASELINE_T(groupName, baselineName, fixtureName, samples, iterations, threads) \
BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, threads, 0)
///
/// \define BASELINE
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark.
///
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BASELINE(groupName, baselineName, samples, iterations) \
BASELINE_IMPL(groupName, baselineName, ::celero::TestFixture, samples, iterations, 1, 0)
///
/// \define BASELINE_FIXED
///
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark with a hard-coded timing.
///
/// This will NOT perform any timing measurments but will instead use the number of microseconds passed in as the measured time.
///
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
///
#define BASELINE_FIXED(groupName, baselineName, iterations, useconds) \
BASELINE_IMPL(groupName, baselineName, ::celero::TestFixture, 1, iterations, 1, useconds)
#define BASELINE_FIXED_F(groupName, baselineName, fixtureName, iterations, useconds) \
BASELINE_IMPL(groupName, baselineName, fixtureName, 1, iterations, 1, useconds)
#define BASELINE_FIXED_T(groupName, baselineName, fixtureName, iterations, threads, useconds) \
BASELINE_IMPL(groupName, baselineName, fixtureName, 1, iterations, threads, useconds)