124 lines
3.7 KiB
C
124 lines
3.7 KiB
C
|
#ifndef ALSK_ALSK_EXECUTOR_IMPL_DYNAMICPOOL_H
|
||
|
#define ALSK_ALSK_EXECUTOR_IMPL_DYNAMICPOOL_H
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <future>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "../executorbase.h"
|
||
|
#include "../executorstate.h"
|
||
|
#include "../../skeleton/traits.h"
|
||
|
|
||
|
#include "../utility/pool.h"
|
||
|
|
||
|
namespace alsk {
|
||
|
namespace exec {
|
||
|
|
||
|
template<typename S>
|
||
|
struct DynamicPool: ExecutorBase {
|
||
|
using Tag = alsk::tag::Parallel;
|
||
|
|
||
|
public:
|
||
|
std::size_t maxTaskCount = 1'000;
|
||
|
|
||
|
public:
|
||
|
template<typename Impl>
|
||
|
void config(Impl& impl) {
|
||
|
impl.state.executor.config(cores);
|
||
|
}
|
||
|
|
||
|
template<typename Task, typename Impl, typename BTask, typename Parameters>
|
||
|
void executeParallel(Impl& impl, BTask& task, Parameters const& parameters, std::size_t n) {
|
||
|
std::size_t taskCount = std::min(maxTaskCount, n);
|
||
|
|
||
|
if(cores > 1 && taskCount > 1) {
|
||
|
Info info;
|
||
|
std::vector<std::future<void>> futures(taskCount);
|
||
|
std::size_t const step = n/taskCount;
|
||
|
std::size_t const remain = n - step*(taskCount-1);
|
||
|
|
||
|
typename Impl::State& state = impl.state;
|
||
|
|
||
|
auto run = [&](std::size_t b, std::size_t k) {
|
||
|
for(std::size_t i = 0; i < k; ++i)
|
||
|
Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||
|
};
|
||
|
|
||
|
for(std::size_t i = 0; i < taskCount-1; ++i)
|
||
|
futures[i] = state.executor.run([&, b=i*step, k=step]{ run(b, k); });
|
||
|
futures[taskCount-1] = state.executor.run([&, b=(taskCount-1)*step, k=remain]{ run(b, k); });
|
||
|
|
||
|
state.executor.wait(futures);
|
||
|
} else {
|
||
|
Info info;
|
||
|
for(std::size_t i = 0; i < n; ++i)
|
||
|
Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<typename Value, typename Task, typename Select, typename Impl, typename BTask, typename BSelect, typename Parameters>
|
||
|
Value executeParallelAccumulate(Impl& impl, BTask& task, BSelect& select, Parameters const& parameters, std::size_t n) {
|
||
|
std::size_t taskCount = std::min(maxTaskCount, n);
|
||
|
|
||
|
Value best{};
|
||
|
|
||
|
if(cores > 1 && taskCount > 1) {
|
||
|
Info info;
|
||
|
std::vector<std::future<void>> futures(taskCount);
|
||
|
std::size_t const step = n/taskCount;
|
||
|
std::size_t const remainBase = n - step*taskCount;
|
||
|
std::size_t remain = remainBase;
|
||
|
|
||
|
typename Impl::State& state = impl.state;
|
||
|
|
||
|
auto run = [&](Value& out, std::size_t b, std::size_t k) {
|
||
|
Value best{};
|
||
|
|
||
|
if(k)
|
||
|
best = Task::execute(impl, task, b+0, info, parameters, std::tuple<>{});
|
||
|
for(std::size_t i = 1; i < k; ++i) {
|
||
|
Value current = Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||
|
best = Select::execute(impl, select, b+i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||
|
}
|
||
|
|
||
|
out = std::move(best);
|
||
|
};
|
||
|
|
||
|
std::size_t start{};
|
||
|
std::vector<Value> bests(taskCount);
|
||
|
for(std::size_t i = 0; i < taskCount-1; ++i) {
|
||
|
std::size_t offset = !!remain;
|
||
|
remain -= offset;
|
||
|
futures[i] = state.executor.run([&, &best=bests[i], b=start, k=step+offset] { run(best, b, k); });
|
||
|
start += step+offset;
|
||
|
}
|
||
|
|
||
|
futures[taskCount-1] = state.executor.run([&, &best=bests[taskCount-1], b=start, k=step] { run(best, b, k); });
|
||
|
|
||
|
state.executor.wait(futures);
|
||
|
|
||
|
if(taskCount) best = std::move(bests[0]);
|
||
|
for(std::size_t i = 1; i < taskCount; ++i)
|
||
|
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(bests[i]), std::move(best));
|
||
|
} else {
|
||
|
Info info;
|
||
|
if(n)
|
||
|
best = Task::execute(impl, task, 0, info, parameters, std::tuple<>{});
|
||
|
for(std::size_t i = 1; i < n; ++i) {
|
||
|
Value current = Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||
|
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return best;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename S>
|
||
|
struct ExecutorState<DynamicPool<S>>: util::Pool {};
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|