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
|
#pragma once
#include "benchmark.hpp"
#include "report.hpp"
#include "workload.hpp"
#include <tao/config/value.hpp>
#include <atomic>
#include <cstdint>
#include <memory>
#include <random>
#include <thread>
#include <vector>
enum class execution_state {
starting,
preparing,
initializing,
running,
stopped
};
enum class thread_state {
starting,
running,
ready,
finished
};
struct initialization_failure : std::exception {
const char* what() const noexcept override {
return "Failed to initialize data structure under test-";
}
};
struct execution;
struct execution_thread {
execution_thread(std::uint32_t id, const execution& exec);
virtual ~execution_thread() = default;
virtual void setup(const tao::config::value& config);
virtual void run() = 0;
virtual void initialize(std::uint32_t /*num_threads*/) {}
virtual thread_report report() const { return { {}, 0 }; }
std::uint32_t id() const { return _id; }
private:
const execution& _execution;
std::shared_ptr<workload_simulator> _workload;
protected:
void simulate_workload();
const std::uint32_t _id;
std::atomic<thread_state> _state{thread_state::starting};
std::mt19937_64 _randomizer{};
std::thread _thread{};
std::chrono::duration<double, std::milli> _runtime{};
private:
friend struct execution;
void thread_func();
void do_run();
void wait_until_all_threads_are_started();
void wait_until_initialization();
void wait_until_benchmark_starts();
};
struct execution {
static constexpr std::uint32_t thread_id_bits = 16;
static constexpr std::uint32_t thread_id_mask = (1 << thread_id_bits) - 1;
execution(std::uint32_t round, std::uint32_t runtime, std::shared_ptr<benchmark> benchmark);
~execution();
void create_threads(const tao::config::value& config);
round_report run();
execution_state state(std::memory_order order = std::memory_order_relaxed) const;
std::uint32_t num_threads() const { return static_cast<std::uint32_t>(_threads.size()); }
private:
void wait_until_all_threads_are(thread_state state);
void wait_until_running(const execution_thread& thread) const;
void wait_until_finished(const execution_thread& thread) const;
void wait_until_thread_state_is(const execution_thread& thread, thread_state expected) const;
round_report build_report(double runtime);
std::atomic<execution_state> _state;
std::uint32_t _round;
std::uint32_t _runtime;
std::shared_ptr<benchmark> _benchmark;
std::vector<std::unique_ptr<execution_thread>> _threads;
};
|