Initial commit
This commit is contained in:
commit
4f4397b3e1
48 changed files with 2002 additions and 0 deletions
69
VectorFiller/atlas/bootstrap/bootstrap.h
Normal file
69
VectorFiller/atlas/bootstrap/bootstrap.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include "../collection/decorator/MeasuredVectorFactory.h"
|
||||
#include "../collection/impl/AutoThreadedVectorFactory.h"
|
||||
#include "../collection/impl/MultiThreadedVectorFactory.h"
|
||||
#include "../collection/impl/SingleThreadedVectorFactory.h"
|
||||
#include "../generator/impl/RandomIntGenerator.h"
|
||||
#include "../time/impl/HighResolutionTimer.h"
|
||||
#include <charconv>
|
||||
#include <limits>
|
||||
|
||||
namespace atlas::bootstrap {
|
||||
class Bootstrap {
|
||||
public:
|
||||
auto run(int argc, char* argv[]) const -> int
|
||||
{
|
||||
constexpr size_t size { std::numeric_limits<int>::max() / 2 };
|
||||
|
||||
if (argc > 1) {
|
||||
std::size_t i;
|
||||
std::string_view arg { argv[1] };
|
||||
if (auto const [ptr, ec] = std::from_chars(arg.data(), arg.data() + arg.size(), i); ec == std::errc {}) {
|
||||
return benchmark(size, { i });
|
||||
}
|
||||
}
|
||||
|
||||
return benchmark(size, { 0, 1, 2, 4, 8, 16 });
|
||||
}
|
||||
|
||||
private:
|
||||
auto benchmark(size_t const size, std::vector<size_t> const& threads) const -> int
|
||||
{
|
||||
for (auto const i : threads) {
|
||||
run(size, i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto run(size_t const size, size_t const nthreads) const -> int
|
||||
{
|
||||
std::cout << "Running with " << nthreads << " threads\n";
|
||||
auto factory { make_measured(make_factory(nthreads)) };
|
||||
auto result { factory->createAndFillVector(size) };
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<collection::VectorFactory<int>> make_factory(size_t nthreads) const
|
||||
{
|
||||
switch (nthreads) {
|
||||
case 0:
|
||||
return std::make_unique<collection::AutoThreadedVectorFactory<int>>([this] { return make_generator(); });
|
||||
case 1:
|
||||
return std::make_unique<collection::SingleThreadedVectorFactory<int>>(make_generator());
|
||||
default:
|
||||
return std::make_unique<collection::MultiThreadedVectorFactory<int>>([this] { return make_generator(); }, nthreads);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<collection::VectorFactory<int>> make_measured(std::unique_ptr<collection::VectorFactory<int>> other) const
|
||||
{
|
||||
return std::make_unique<collection::decorator::MeasuredVectorFactory<int>>(std::make_unique<time::HighResolutionTimer>(), std::move(other));
|
||||
}
|
||||
|
||||
std::unique_ptr<generator::Generator<int>> make_generator() const
|
||||
{
|
||||
return std::make_unique<generator::RandomIntGenerator>();
|
||||
}
|
||||
};
|
||||
}
|
||||
0
VectorFiller/atlas/client/x
Normal file
0
VectorFiller/atlas/client/x
Normal file
20
VectorFiller/atlas/collection/VectorFactory.h
Normal file
20
VectorFiller/atlas/collection/VectorFactory.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace atlas::collection {
|
||||
template <typename T>
|
||||
class VectorFactory {
|
||||
public:
|
||||
using base_type = VectorFactory<T>;
|
||||
using value_type = std::vector<T>;
|
||||
using product_type = std::shared_ptr<value_type>;
|
||||
|
||||
virtual ~VectorFactory() = default;
|
||||
|
||||
[[nodiscard]] virtual auto createAndFillVector(size_t const) -> product_type = 0;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../time/time.h"
|
||||
#include "../VectorFactory.h"
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
namespace atlas::collection::decorator {
|
||||
template <typename T>
|
||||
class MeasuredVectorFactory : public VectorFactory<T> {
|
||||
public:
|
||||
using decorated_type = VectorFactory<T>;
|
||||
using decorated_ptr = std::unique_ptr<decorated_type>;
|
||||
using stopwatch_ptr = std::unique_ptr<time::Timer<std::chrono::milliseconds>>;
|
||||
|
||||
MeasuredVectorFactory(stopwatch_ptr stopwatch, decorated_ptr decorated)
|
||||
: m_stopwatch { std::move(stopwatch) }
|
||||
, m_decorated { std::move(decorated) }
|
||||
{
|
||||
}
|
||||
|
||||
auto createAndFillVector(size_t const size) -> typename decorated_type::product_type override final
|
||||
{
|
||||
return logTimerResult(m_stopwatch->measure(
|
||||
[this, size] { return m_decorated->createAndFillVector(size); }));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Result>
|
||||
auto logTimerResult(Result&& result) const
|
||||
{
|
||||
std::cout << "Duration: " << result.duration.count() << "ms\n";
|
||||
return result.value;
|
||||
}
|
||||
|
||||
stopwatch_ptr m_stopwatch;
|
||||
decorated_ptr m_decorated;
|
||||
};
|
||||
}
|
||||
21
VectorFiller/atlas/collection/impl/AbstractVectorFactory.h
Normal file
21
VectorFiller/atlas/collection/impl/AbstractVectorFactory.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "../VectorFactory.h"
|
||||
|
||||
namespace atlas::collection {
|
||||
template <typename T>
|
||||
class AbstractVectorFactory : public VectorFactory<T> {
|
||||
|
||||
public:
|
||||
using base_type = VectorFactory<T>;
|
||||
|
||||
auto createAndFillVector(size_t const size) -> typename base_type::product_type override final
|
||||
{
|
||||
auto result = std::make_shared<std::vector<T>>(size);
|
||||
fill(*result);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void fill(std::vector<T>&) = 0;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../generator/generator.h"
|
||||
#include "AbstractVectorFactory.h"
|
||||
#include <algorithm>
|
||||
#include <execution>
|
||||
|
||||
namespace atlas::collection {
|
||||
template <typename T>
|
||||
class AutoThreadedVectorFactory : public AbstractVectorFactory<T> {
|
||||
|
||||
public:
|
||||
AutoThreadedVectorFactory(std::function<std::unique_ptr<generator::Generator<T>>()> generator_factory)
|
||||
: m_gen { std::move(generator_factory) }
|
||||
{
|
||||
}
|
||||
|
||||
AutoThreadedVectorFactory(AutoThreadedVectorFactory const&) = delete;
|
||||
AutoThreadedVectorFactory(AutoThreadedVectorFactory&&) = delete;
|
||||
AutoThreadedVectorFactory& operator=(AutoThreadedVectorFactory const&) = delete;
|
||||
AutoThreadedVectorFactory& operator=(AutoThreadedVectorFactory&&) = delete;
|
||||
|
||||
auto fill(std::vector<T>& v) -> void override final
|
||||
{
|
||||
std::for_each(std::execution::par_unseq, v.begin(), v.end(), [this](auto& v) {
|
||||
static thread_local auto gen { m_gen() };
|
||||
v = gen->next();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<std::unique_ptr<generator::Generator<T>>()> m_gen;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../generator/generator.h"
|
||||
#include "AbstractVectorFactory.h"
|
||||
#include "fill_with.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
namespace atlas::collection {
|
||||
namespace {
|
||||
void join_thread(std::thread& t)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class MultiThreadedVectorFactory : public AbstractVectorFactory<T> {
|
||||
|
||||
public:
|
||||
using Self = MultiThreadedVectorFactory<T>;
|
||||
|
||||
MultiThreadedVectorFactory(std::function<std::unique_ptr<generator::Generator<T>>()> generator_factory, size_t const nthreads)
|
||||
: m_gen { std::move(generator_factory) }
|
||||
, m_threads { nthreads }
|
||||
{
|
||||
}
|
||||
|
||||
MultiThreadedVectorFactory(MultiThreadedVectorFactory const&) = delete;
|
||||
MultiThreadedVectorFactory(MultiThreadedVectorFactory&&) = delete;
|
||||
MultiThreadedVectorFactory& operator=(MultiThreadedVectorFactory const&) = delete;
|
||||
MultiThreadedVectorFactory& operator=(MultiThreadedVectorFactory&&) = delete;
|
||||
|
||||
auto fill(std::vector<T>& v) -> void override final
|
||||
{
|
||||
std::vector<std::thread> threads;
|
||||
size_t const slice { v.size() / m_threads };
|
||||
auto pos = v.begin();
|
||||
for (size_t i = 0; i < m_threads; ++i, pos += slice) {
|
||||
threads.emplace_back([this, from = pos, to = pos + slice] { this->worker(from, to); });
|
||||
}
|
||||
worker(pos, v.end());
|
||||
|
||||
std::for_each(threads.begin(), threads.end(), join_thread);
|
||||
}
|
||||
|
||||
private:
|
||||
void worker(std::vector<int>::iterator from, std::vector<int>::iterator to)
|
||||
{
|
||||
detail::fill_with(from, to, [g = m_gen()]() { return g->next(); });
|
||||
}
|
||||
|
||||
std::function<std::unique_ptr<generator::Generator<T>>()> m_gen;
|
||||
size_t m_threads;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../generator/generator.h"
|
||||
#include "AbstractVectorFactory.h"
|
||||
#include "fill_with.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace atlas::collection {
|
||||
template <typename T>
|
||||
class SingleThreadedVectorFactory : public AbstractVectorFactory<T> {
|
||||
|
||||
public:
|
||||
SingleThreadedVectorFactory(std::unique_ptr<generator::Generator<T>> generator)
|
||||
: m_gen { std::move(generator) }
|
||||
{
|
||||
}
|
||||
|
||||
SingleThreadedVectorFactory(SingleThreadedVectorFactory const&) = delete;
|
||||
SingleThreadedVectorFactory(SingleThreadedVectorFactory&&) = delete;
|
||||
SingleThreadedVectorFactory& operator=(SingleThreadedVectorFactory const&) = delete;
|
||||
SingleThreadedVectorFactory& operator=(SingleThreadedVectorFactory&&) = delete;
|
||||
|
||||
auto fill(std::vector<T>& v) -> void override final
|
||||
{
|
||||
detail::fill_with(v.begin(), v.end(), [this]() { return m_gen->next(); });
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<generator::Generator<T>> m_gen;
|
||||
};
|
||||
}
|
||||
12
VectorFiller/atlas/collection/impl/fill_with.h
Normal file
12
VectorFiller/atlas/collection/impl/fill_with.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace atlas::collection::detail {
|
||||
template <typename Iter, typename F>
|
||||
void fill_with(Iter start, Iter end, F f)
|
||||
{
|
||||
std::for_each(start, end, [g = std::move(f)](auto& v) { v = g(); });
|
||||
}
|
||||
|
||||
}
|
||||
14
VectorFiller/atlas/generator/generator.h
Normal file
14
VectorFiller/atlas/generator/generator.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace atlas::generator {
|
||||
template <typename T>
|
||||
class Generator {
|
||||
public:
|
||||
virtual ~Generator() = default;
|
||||
|
||||
using value_type = T;
|
||||
virtual auto next() -> value_type = 0;
|
||||
};
|
||||
}
|
||||
30
VectorFiller/atlas/generator/impl/RandomIntGenerator.h
Normal file
30
VectorFiller/atlas/generator/impl/RandomIntGenerator.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../generator.h"
|
||||
#include <random>
|
||||
|
||||
namespace atlas::generator {
|
||||
class RandomIntGenerator : public Generator<int> {
|
||||
public:
|
||||
RandomIntGenerator()
|
||||
: RandomIntGenerator(rand())
|
||||
{
|
||||
}
|
||||
|
||||
RandomIntGenerator(int const seed)
|
||||
: m_device(seed)
|
||||
{
|
||||
}
|
||||
|
||||
auto next() -> value_type override
|
||||
{
|
||||
return m_gen(m_device);
|
||||
}
|
||||
|
||||
private:
|
||||
std::mt19937 m_device;
|
||||
std::uniform_int_distribution<> m_gen;
|
||||
};
|
||||
}
|
||||
26
VectorFiller/atlas/time/impl/HighResolutionTimer.h
Normal file
26
VectorFiller/atlas/time/impl/HighResolutionTimer.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../time.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace atlas::time {
|
||||
class HighResolutionTimer : public Timer<std::chrono::milliseconds> {
|
||||
public:
|
||||
void start() override
|
||||
{
|
||||
m_start = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
auto elapsed() const -> duration_type override
|
||||
{
|
||||
return std::chrono::duration_cast<duration_type>(std::chrono::high_resolution_clock::now() - m_start);
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::high_resolution_clock::time_point m_start;
|
||||
};
|
||||
|
||||
}
|
||||
29
VectorFiller/atlas/time/time.h
Normal file
29
VectorFiller/atlas/time/time.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace atlas::time {
|
||||
template <typename Duration>
|
||||
class Timer {
|
||||
public:
|
||||
using duration_type = Duration;
|
||||
|
||||
virtual ~Timer() = default;
|
||||
virtual auto start() -> void = 0;
|
||||
virtual auto elapsed() const -> duration_type;
|
||||
|
||||
template <typename T>
|
||||
struct TimerResult {
|
||||
T value;
|
||||
duration_type duration;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
[[nodiscard]] auto measure(F&& f) -> TimerResult<decltype(f())>
|
||||
{
|
||||
start();
|
||||
auto v = f();
|
||||
return { v, elapsed() };
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue