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
 |