#ifndef ALSK_ALSK_EXECUTOR_IMPL_DYNAMICPOOL_H #define ALSK_ALSK_EXECUTOR_IMPL_DYNAMICPOOL_H #include #include #include #include "../executorbase.h" #include "../executorstate.h" #include "../../skeleton/traits.h" #include "../utility/pool.h" namespace alsk { namespace exec { template struct DynamicPool: ExecutorBase { using Tag = alsk::tag::Parallel; public: std::size_t maxTaskCount = 1'000; public: template void config(Impl& impl) { impl.state.executor.config(cores); } template 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> 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 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> 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 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 struct ExecutorState>: util::Pool {}; } } #endif