111 lines
3.1 KiB
C
111 lines
3.1 KiB
C
|
#ifndef ALSK_ALSK_EXECUTOR_IMPL_STATICPOOLID_H
|
||
|
#define ALSK_ALSK_EXECUTOR_IMPL_STATICPOOLID_H
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <cmath>
|
||
|
#include <future>
|
||
|
#include <list>
|
||
|
#include <set>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "../executorbase.h"
|
||
|
#include "../executorstate.h"
|
||
|
#include "../../skeleton/traits.h"
|
||
|
|
||
|
#include "../utility/staticpool.h"
|
||
|
|
||
|
namespace alsk {
|
||
|
namespace exec {
|
||
|
|
||
|
template<typename S>
|
||
|
struct StaticPoolId: ExecutorBase {
|
||
|
using Tag = alsk::tag::Parallel;
|
||
|
|
||
|
private:
|
||
|
template<typename Impl>
|
||
|
void buildSplit(Impl& impl) {
|
||
|
typename Impl::State& state = impl.state;
|
||
|
auto& split = state.executor.split;
|
||
|
|
||
|
split.clear();
|
||
|
split.insert(0);
|
||
|
|
||
|
auto const n = static_cast<double>(state.executor.upperId);
|
||
|
for(auto cores: repeatability.coresList)
|
||
|
for(std::size_t i = 1; i < cores; ++i)
|
||
|
split.insert(std::ceil(n/cores * i));
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
template<typename Impl>
|
||
|
void config(Impl& impl) {
|
||
|
typename Impl::State& state = impl.state;
|
||
|
state.executor.config(cores);
|
||
|
state.executor.upperId = impl.parallelTasksCount();
|
||
|
buildSplit(impl);
|
||
|
}
|
||
|
|
||
|
template<typename Impl>
|
||
|
std::size_t contextIdCount(Impl& impl, std::size_t) {
|
||
|
typename Impl::State& state = impl.state;
|
||
|
return state.executor.split.size();
|
||
|
}
|
||
|
|
||
|
template<typename Impl>
|
||
|
std::size_t contextId(Impl& impl, std::size_t id) { // O(log(n))
|
||
|
typename Impl::State& state = impl.state;
|
||
|
auto& split = state.executor.split;
|
||
|
return std::distance(std::begin(split), split.upper_bound(id)) - 1;
|
||
|
}
|
||
|
|
||
|
template<typename Task, typename Impl, typename BTask, typename Parameters>
|
||
|
void executeParallel(Impl& impl, BTask& task, Parameters const& parameters, std::size_t n) {
|
||
|
std::list<std::future<void>> futures;
|
||
|
typename Impl::State& state = impl.state;
|
||
|
|
||
|
for(std::size_t i = 0; i < n; ++i) {
|
||
|
std::size_t thNum = cores * (impl.id + impl.skeleton.step * i) / state.executor.upperId;
|
||
|
|
||
|
auto thTask = [&, i]{ Task::execute(impl, task, i, Info{}, parameters, std::tuple<>{}); };
|
||
|
futures.emplace_back(state.executor.run(thNum, std::move(thTask)));
|
||
|
}
|
||
|
|
||
|
state.executor.wait(futures);
|
||
|
}
|
||
|
|
||
|
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) {
|
||
|
Value best{};
|
||
|
std::vector<Value> bests(n);
|
||
|
|
||
|
std::list<std::future<void>> futures;
|
||
|
typename Impl::State& state = impl.state;
|
||
|
|
||
|
for(std::size_t i = 0; i < n; ++i) {
|
||
|
std::size_t thNum = cores * (impl.id + impl.skeleton.step * i) / state.executor.upperId;
|
||
|
|
||
|
auto thTask = [&, &best = bests[i], i]{ best = Task::execute(impl, task, i, Info{}, parameters, std::tuple<>{}); };
|
||
|
futures.emplace_back(state.executor.run(thNum, std::move(thTask)));
|
||
|
}
|
||
|
|
||
|
state.executor.wait(futures);
|
||
|
|
||
|
if(n) best = std::move(bests[0]);
|
||
|
for(std::size_t i = 1; i < n; ++i)
|
||
|
best = Select::execute(impl, select, i, impl.executorInfo, parameters, std::tuple<>{}, std::move(bests[i]), std::move(best));
|
||
|
|
||
|
return best;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename S>
|
||
|
struct ExecutorState<StaticPoolId<S>>: util::StaticPool {
|
||
|
std::size_t upperId;
|
||
|
std::set<std::size_t> split;
|
||
|
};
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|