18 #include <type_traits>
122 __asm__
volatile(
"" : :
"g"(&clobber) :
"memory");
127 template <
typename T>
140 static_assert(
false,
"No optimization barrier available for this compiler");
150 template <
typename T>
166 template <
typename T>
184 using Duration = std::chrono::duration<double, std::nano>;
229 std::vector<Duration> sorted_timings =
run_timings;
230 std::sort(sorted_timings.begin(), sorted_timings.end());
231 return sorted_timings;
238 const size_t midpoint = sorted_timings.size() / 2;
239 if (sorted_timings.size() % 2 == 0) {
240 return (sorted_timings[midpoint - 1] + sorted_timings[midpoint]) / 2;
242 return sorted_timings[midpoint];
264 const size_t first_point = (sorted_timings.size() - 2) / 4;
265 const size_t offset = (sorted_timings.size() - 2) % 4;
266 const size_t third_point = (sorted_timings.size() - 1) - first_point;
268 return {sorted_timings[first_point], sorted_timings[third_point]};
270 const auto first_quartile = ((4 -
offset) * sorted_timings[first_point] +
271 offset * sorted_timings[first_point + 1]) /
273 const auto third_quartile = ((4 -
offset) * sorted_timings[third_point] +
274 offset * sorted_timings[third_point - 1]) /
276 return {first_quartile, third_quartile};
289 return (thirdq - firstq) / (2. * std::sqrt(2.) * 0.4769362762044698733814);
295 auto old_precision = os.precision();
296 auto old_flags = os.flags();
297 os << std::fixed << res.
run_timings.size() <<
" runs of "
298 << res.
iters_per_run <<
" iteration(s), " << std::setprecision(1)
299 << res.
totalTime().count() / 1
'000'000 <<
"ms total, "
300 << std::setprecision(4) << res.
runTimeMedian().count() / 1
'000 << "+/-"
301 << res.runTimeRobustStddev().count() / 1'000 <<
"µs per run, "
304 os.precision(old_precision);
311 namespace benchmark_tools_internal {
314 template <
typename Callable,
typename Input,
typename Result>
316 static inline void iter(
const Callable& iteration,
const Input& input) {
319 const auto result = iteration(input);
325 template <
typename Callable,
typename Input>
327 static inline void iter(
const Callable& iteration,
const Input& input) {
335 template <
typename Callable,
typename Result>
337 static inline void iter(
const Callable& iteration) {
339 const auto result = iteration();
345 template <
typename Callable>
347 static inline void iter(
const Callable& iteration) {
353 template <
typename T,
typename I>
356 template <
typename T>
361 template <
typename Callable,
typename Input =
void>
364 concept ::exists<call_with_input_t, Callable, Input>;
365 static inline void iter(
const Callable& iteration,
const Input* input) {
366 static_assert(
is_callable,
"Gave callable that is not callable with input");
368 using Result = std::invoke_result_t<Callable, const Input&>;
376 template <
typename Callable>
379 concept ::exists<call_without_input_t, Callable>;
381 static inline void iter(
const Callable& iteration,
const void* =
nullptr) {
383 "Gave callable that is not callable without input");
385 using Result = std::invoke_result_t<Callable>;
392 template <
typename Callable>
395 std::chrono::milliseconds warmup_time) {
396 using Clock = std::chrono::steady_clock;
402 const auto warmup_start = Clock::now();
403 while (Clock::now() - warmup_start < warmup_time) {
407 for (
size_t i = 0; i < num_runs; ++i) {
408 const auto start = Clock::now();
474 template <
typename Callable>
476 Callable&& iteration,
size_t iters_per_run,
size_t num_runs = 20000,
477 std::chrono::milliseconds warmup_time = std::chrono::milliseconds(2000)) {
480 for (
size_t iter = 0; iter < iters_per_run; ++iter) {
485 iters_per_run, num_runs, warmup_time);
494 template <
typename Callable,
typename Input>
496 Callable&& iterationWithInput,
const std::vector<Input>& inputs,
497 size_t num_runs = 20000,
498 std::chrono::milliseconds warmup_time = std::chrono::milliseconds(2000)) {
501 for (
const auto& input : inputs) {
503 iterationWithInput, &input);
506 inputs.size(), num_runs, warmup_time);