view lib/exec.h @ 16:d6798d2acfb3

Improve timeit_f for void functions
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 01 Apr 2023 19:35:47 +0200
parents c8e1da3603ea
children
line wrap: on
line source


#include <fmt/core.h>
#include <fmt/ranges.h>


#include <chrono>
#include <functional>
#include <string>
void timeit(std::function<void()> f, std::string name = std::string());

void benchmarkit(std::function<void()> f, std::string name = std::string(), std::function<void()> setup = [](){});

using std::function, std::string, std::chrono::high_resolution_clock;

template<typename Func>
concept is_void_function = std::is_void_v<std::invoke_result_t<Func>>;

template<typename F> requires is_void_function<F>
void timeit_f(F f, string name = string()) {
    auto begin = high_resolution_clock::now();

    f();

    auto after = high_resolution_clock::now();

    auto d = after - begin;
    decltype(d)::rep count = d.count();
    decltype(d)::period p;

    fmt::print("(void) {} :: {} s\n", name, static_cast<double>(p.num)/p.den * count); 
    return;
}

template<typename F> requires (!is_void_function<F>)
auto timeit_f(F f, string name = string()) -> decltype(f()) {
    auto begin = high_resolution_clock::now();

    auto result = f();

    auto after = high_resolution_clock::now();

    auto d = after - begin;
    decltype(d)::rep count = d.count();
    decltype(d)::period p;

    fmt::print("{} :: {} s\n", name, static_cast<double>(p.num)/p.den * count); 
    return result;
}

template<typename F>
void benchmarkit_f(F f, const string& name, function<void()> setup = []() {}) {
    int n = 1;
    const double min_duration = 0.1;

    while (true) {
        setup();
     
        fmt::print("Running {} for {} iterations\n", name, n);

        auto begin = high_resolution_clock::now();

        for (unsigned int i = 0; i < n; i += 1)
            f();

        auto end = high_resolution_clock::now();
        decltype(end-begin)::period p;
        auto seconds = (end-begin).count() * static_cast<double>(p.num)/p.den;
        if (seconds < min_duration) {
            n *= 2;
        } else {
            fmt::print("{} iterations took {} seconds ({} s/iter)\n", n, seconds, seconds/n);
            break;
        }
    }
}