// Primera medición: un reloj, una suma, varias repeticiones.
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <cstdio>
#include <numeric>
#include <vector>

#include "bench.h"

long long sum_values(const std::vector<int>& values) {
    long long total = 0;
    for (int value : values) {
        total += value;
    }
    return total;
}

// El salto más pequeño que se alcanza a ver entre dos lecturas seguidas del reloj.
double smallest_tick() {
    double smallest = 1.0;
    for (int i = 0; i < 100000; i++) {
        auto first = std::chrono::steady_clock::now();
        auto second = std::chrono::steady_clock::now();
        while (second == first) {
            second = std::chrono::steady_clock::now();
        }
        smallest = std::min(smallest, std::chrono::duration<double>(second - first).count());
    }
    return smallest;
}

int main() {
    const std::size_t n = 1000000;
    std::vector<int> values(n);
    std::iota(values.begin(), values.end(), 0);

    auto start = std::chrono::steady_clock::now();
    long long total = sum_values(values);
    auto stop = std::chrono::steady_clock::now();
    keep(total);
    double seconds = std::chrono::duration<double>(stop - start).count();
    std::printf("una medicion: %.0f us\n", seconds * 1e6);

    std::vector<double> times;
    for (int i = 0; i < 9; i++) {
        times.push_back(median_seconds(1, [&] { keep(sum_values(values)); }));
    }
    double mean = std::accumulate(times.begin(), times.end(), 0.0) / static_cast<double>(times.size());
    std::printf("nueve mediciones (us):");
    for (double time : times) {
        std::printf(" %.0f", time * 1e6);
    }
    std::printf("\nmedia %.0f us, mediana %.0f us\n", mean * 1e6, median_of(times) * 1e6);
    std::printf("salto minimo del reloj: %.0f ns\n", smallest_tick() * 1e9);
    return 0;
}
