From 81fd4c05214b7660ad287dc964b3640e127b83a8 Mon Sep 17 00:00:00 2001 From: Tobias Fuchs Date: Mon, 23 Feb 2015 17:14:50 +0100 Subject: [PATCH] algorithms_cpp: using block size partitioner in ForEach --- algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h | 65 ++++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h b/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h index c1d0c6c..d14dc87 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h @@ -47,48 +47,54 @@ class ForEachFunctor { /** * Constructs a for-each functor with arguments. */ - ForEachFunctor(RAI first, RAI last, Function unary, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) - : first_(first), last_(last), unary_(unary), policy_(policy), - block_size_(block_size) { + ForEachFunctor(size_t chunk_first, size_t chunk_last, Function unary, + const embb::mtapi::ExecutionPolicy& policy, + const BlockSizePartitioner& partitioner) + : chunk_first_(chunk_first), chunk_last_(chunk_last), + unary_(unary), policy_(policy), partitioner_(partitioner) { } - void Action(mtapi::TaskContext& context) { - size_t distance = static_cast(std::distance(first_, last_)); - if (distance == 0) return; - if (distance <= block_size_) { // leaf case -> do work - for (RAI it = first_; it != last_; ++it) { + void Action(mtapi::TaskContext&) { + if (chunk_first_ == chunk_last_) { + // Leaf case, recursed to single chunk. Do work on chunk: + ChunkDescriptor chunk = partitioner_[chunk_first_]; + RAI first = chunk.GetFirst(); + RAI last = chunk.GetLast(); + for (RAI it = first; it != last; ++it) { unary_(*it); } - } else { // recurse further - ChunkPartitioner partitioner(first_, last_, 2); - ChunkDescriptor chunk_l = partitioner[0]; - ChunkDescriptor chunk_r = partitioner[1]; - self_t functor_l(chunk_l.GetFirst(), - chunk_l.GetLast(), - unary_, policy_, block_size_); - self_t functor_r(chunk_r.GetFirst(), - chunk_r.GetLast(), - unary_, policy_, block_size_); - // Spawn tasks for right partition first: + } + else { + // Recurse further: + size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2; + // Split chunks into left / right branches: + self_t functor_l(chunk_first_, + chunk_split_index, + unary_, policy_, partitioner_); + self_t functor_r(chunk_split_index + 1, + chunk_last_, + unary_, policy_, partitioner_); + mtapi::Task task_l = mtapi::Node::GetInstance().Spawn( + mtapi::Action( + base::MakeFunction( + functor_l, &ForEachFunctor::Action), + policy_)); mtapi::Task task_r = mtapi::Node::GetInstance().Spawn( mtapi::Action( base::MakeFunction( functor_r, &ForEachFunctor::Action), policy_)); - // Recurse on left partition: - functor_l.Action(context); - // Wait for tasks on right partition to complete: task_r.Wait(MTAPI_INFINITE); + task_l.Wait(MTAPI_INFINITE); } } private: - RAI first_; - RAI last_; + size_t chunk_first_; + size_t chunk_last_; Function unary_; const embb::mtapi::ExecutionPolicy& policy_; - size_t block_size_; + const BlockSizePartitioner& partitioner_; /** * Disables assignment. @@ -112,12 +118,17 @@ void ForEachRecursive(RAI first, RAI last, Function unary, block_size = 1; } } + // Perform check of task number sufficiency if (((distance / block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) { EMBB_THROW(embb::base::ErrorException, "Not enough MTAPI tasks available " "to perform the parallel foreach loop"); } - ForEachFunctor functor(first, last, unary, policy, block_size); + + BlockSizePartitioner partitioner(first, last, block_size); + ForEachFunctor functor(0, + partitioner.Size() - 1, + unary, policy, partitioner); mtapi::Task task = node.Spawn(mtapi::Action( base::MakeFunction(functor, &ForEachFunctor::Action), -- libgit2 0.26.0