#include "tile/base/internal/time_keeper.h"

#include "benchmark/benchmark.h"

#include <thread>

namespace tile {
namespace internal {

// constexpr auto kTimerCount = 10000;
constexpr auto kInterval = std::chrono::microseconds(10);

void
Benchmark_TimeKeeperTimer(benchmark::State &state)
{
    std::atomic<int> expires_count{0};

    std::vector<TimerID> timer_ids;
    auto kTimerCount = state.range(1);
    for (int i = 0; i != kTimerCount; ++i) {
        timer_ids.push_back(TimeKeeper::Instance()->AddTimer(
            ReadCoarseSteadyClock(), kInterval, [&](TimerID) { expires_count.fetch_add(1, std::memory_order_acq_rel); },
            state.range(0)));
    }

    while (state.KeepRunning()) {
        while (expires_count.load(std::memory_order_relaxed) < kTimerCount) { std::this_thread::yield(); }
        expires_count.fetch_sub(kTimerCount, std::memory_order_acq_rel);
    }

    for (auto &&e : timer_ids) { TimeKeeper::Instance()->KillTimer(e); }

    state.counters["expires_count"] = expires_count.load(std::memory_order_relaxed);
}

static void
CustomArguments(benchmark::internal::Benchmark *b)
{
    b->ArgNames({"is_slow_cb", "timer"});
    static constexpr auto kMaxTimerCount = 100000;
    for (int timer_count = 100; timer_count <= kMaxTimerCount; timer_count *= 10) { b->Args({false, timer_count}); }

    for (int timer_count = 100; timer_count <= kMaxTimerCount; timer_count *= 10) { b->Args({true, timer_count}); }
}

BENCHMARK(Benchmark_TimeKeeperTimer)->Threads(5)->Apply(CustomArguments);

}// namespace internal
}// namespace tile
