Commit 9a3b71bb by Tobias Fuchs

algorithms_cpp: using block size partitioner in Reduce and Count

parent 81fd4c05
...@@ -37,42 +37,47 @@ namespace internal { ...@@ -37,42 +37,47 @@ namespace internal {
template<typename ValueType> template<typename ValueType>
class ValueComparisonFunction{ class ValueComparisonFunction{
public: public:
explicit ValueComparisonFunction(const ValueType &value) explicit ValueComparisonFunction(const ValueType& value)
:value_(value) {} : value_(value) {}
ValueComparisonFunction(const ValueComparisonFunction &other) ValueComparisonFunction(const ValueComparisonFunction& other)
:value_(other.value_) {} : value_(other.value_) {}
template<typename ElementType> template<typename ElementType>
int operator()(ElementType element) { int operator()(ElementType element) {
if(element == value_) if (element == value_) {
return 1; return 1;
else }
else {
return 0; return 0;
}
} }
private: private:
const ValueType &value_; const ValueType &value_;
ValueComparisonFunction &operator=(const ValueComparisonFunction &other); ValueComparisonFunction &operator=(
const ValueComparisonFunction& other);
}; };
template<typename Function> template<typename Function>
class FunctionComparisonFunction{ class FunctionComparisonFunction{
public: public:
explicit FunctionComparisonFunction(Function function) explicit FunctionComparisonFunction(Function function)
:function_(function) {} : function_(function) {}
FunctionComparisonFunction(const FunctionComparisonFunction &other) FunctionComparisonFunction(const FunctionComparisonFunction &other)
:function_(other.function_) {} : function_(other.function_) {}
template<typename ElementType> template<typename ElementType>
int operator()(ElementType element) { int operator()(ElementType element) {
if(function_(element)) if (function_(element)) {
return 1; return 1;
else }
else {
return 0; return 0;
}
} }
private: private:
Function function_; Function function_;
FunctionComparisonFunction &operator=(const FunctionComparisonFunction & FunctionComparisonFunction &operator=(
other); const FunctionComparisonFunction& other);
}; };
} // namespace internal } // namespace internal
......
...@@ -77,15 +77,15 @@ class ForEachFunctor { ...@@ -77,15 +77,15 @@ class ForEachFunctor {
mtapi::Task task_l = mtapi::Node::GetInstance().Spawn( mtapi::Task task_l = mtapi::Node::GetInstance().Spawn(
mtapi::Action( mtapi::Action(
base::MakeFunction( base::MakeFunction(
functor_l, &ForEachFunctor<RAI, Function>::Action), functor_l, &self_t::Action),
policy_)); policy_));
mtapi::Task task_r = mtapi::Node::GetInstance().Spawn( mtapi::Task task_r = mtapi::Node::GetInstance().Spawn(
mtapi::Action( mtapi::Action(
base::MakeFunction( base::MakeFunction(
functor_r, &ForEachFunctor<RAI, Function>::Action), functor_r, &self_t::Action),
policy_)); policy_));
task_r.Wait(MTAPI_INFINITE);
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
} }
} }
...@@ -118,7 +118,6 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ...@@ -118,7 +118,6 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
block_size = 1; block_size = 1;
} }
} }
// Perform check of task number sufficiency // Perform check of task number sufficiency
if (((distance / block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) { if (((distance / block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException, "Not enough MTAPI tasks available " EMBB_THROW(embb::base::ErrorException, "Not enough MTAPI tasks available "
......
...@@ -41,64 +41,75 @@ namespace internal { ...@@ -41,64 +41,75 @@ namespace internal {
template<typename RAI, typename ReturnType, typename ReductionFunction, template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction> typename TransformationFunction>
class ReduceFunctor { class ReduceFunctor {
private:
typedef ReduceFunctor<RAI, ReturnType,
ReductionFunction,
TransformationFunction> self_t;
public: public:
ReduceFunctor(RAI first, RAI last, ReturnType neutral, ReduceFunctor(size_t chunk_first, size_t chunk_last,
ReturnType neutral,
ReductionFunction reduction, ReductionFunction reduction,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy &policy, size_t block_size, const embb::mtapi::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner,
ReturnType& result) ReturnType& result)
: : chunk_first_(chunk_first), chunk_last_(chunk_last), neutral_(neutral),
first_(first), last_(last), neutral_(neutral), reduction_(reduction), reduction_(reduction), transformation_(transformation), policy_(policy),
transformation_(transformation), policy_(policy), partitioner_(partitioner), result_(result) {
block_size_(block_size), result_(result) {
} }
void Action(mtapi::TaskContext& context) { void Action(mtapi::TaskContext&) {
if (first_ == last_) { if (chunk_first_ == chunk_last_) {
return; // Leaf case, recursed to single chunk. Do work on chunk:
} ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_];
size_t distance = static_cast<size_t>(std::distance(first_, last_)); RAI first = chunk.GetFirst();
if (distance <= block_size_) { // leaf case -> do work RAI last = chunk.GetLast();
ReturnType result(neutral_); ReturnType result(neutral_);
for (RAI iter = first_; iter != last_; ++iter) { for (RAI it = first; it != last; ++it) {
result = reduction_(result, transformation_(*iter)); result = reduction_(result, transformation_(*it));
} }
result_ = result; result_ = result;
} else { // recurse further }
internal::ChunkPartitioner<RAI> partitioner(first_, last_, 2); else {
ChunkDescriptor<RAI> chunk_l = partitioner[0]; // Recurse further:
ChunkDescriptor<RAI> chunk_r = partitioner[1]; size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2;
// Split chunks into left / right branches:
ReturnType result_l(neutral_); ReturnType result_l(neutral_);
ReturnType result_r(neutral_); ReturnType result_r(neutral_);
ReduceFunctor functor_l(chunk_l.GetFirst(), self_t functor_l(chunk_first_,
chunk_l.GetLast(), chunk_split_index,
neutral_, reduction_, transformation_, policy_, neutral_, reduction_, transformation_, policy_,
block_size_, result_l); partitioner_,
ReduceFunctor functor_r(chunk_r.GetFirst(), result_l);
chunk_r.GetLast(), self_t functor_r(chunk_split_index + 1,
neutral_, reduction_, transformation_, policy_, chunk_last_,
block_size_, result_r); neutral_, reduction_, transformation_, policy_,
// Spawn tasks for right partition first: partitioner_,
result_r);
mtapi::Task task_l = mtapi::Node::GetInstance().Spawn(
mtapi::Action(
base::MakeFunction(
functor_l, &self_t::Action),
policy_));
mtapi::Task task_r = mtapi::Node::GetInstance().Spawn( mtapi::Task task_r = mtapi::Node::GetInstance().Spawn(
mtapi::Action(base::MakeFunction( mtapi::Action(
functor_r, &ReduceFunctor::Action), base::MakeFunction(
functor_r, &self_t::Action),
policy_)); policy_));
// Recurse on left partition: task_l.Wait(MTAPI_INFINITE);
functor_l.Action(context);
// Wait for tasks on right partition to complete:
task_r.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE);
result_ = reduction_(result_l, result_r); result_ = reduction_(result_l, result_r);
} }
} }
private: private:
RAI first_; size_t chunk_first_;
RAI last_; size_t chunk_last_;
ReturnType neutral_; ReturnType neutral_;
ReductionFunction reduction_; ReductionFunction reduction_;
TransformationFunction transformation_; TransformationFunction transformation_;
const embb::mtapi::ExecutionPolicy& policy_; const embb::mtapi::ExecutionPolicy& policy_;
size_t block_size_; const BlockSizePartitioner<RAI>& partitioner_;
ReturnType& result_; ReturnType& result_;
/** /**
...@@ -120,25 +131,34 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, ...@@ -120,25 +131,34 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
if (distance == 0) { if (distance == 0) {
EMBB_THROW(embb::base::ErrorException, "Distance for Reduce is 0"); EMBB_THROW(embb::base::ErrorException, "Distance for Reduce is 0");
} }
// Determine actually used block size
mtapi::Node& node = mtapi::Node::GetInstance(); mtapi::Node& node = mtapi::Node::GetInstance();
size_t used_block_size = block_size; // Determine actually used block size
if (used_block_size == 0) { if (block_size == 0) {
used_block_size = static_cast<size_t>(distance) / node.GetCoreCount(); block_size = (static_cast<size_t>(distance) / node.GetCoreCount());
if (used_block_size == 0) used_block_size = 1; if (block_size == 0) {
block_size = 1;
}
} }
// Perform check of task number sufficiency // Perform check of task number sufficiency
if (((distance / used_block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) { if (((distance / block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException, EMBB_THROW(embb::base::ErrorException,
"Number of computation tasks required in reduction would " "Number of computation tasks required in reduction would "
"exceed MTAPI maximum number of tasks"); "exceed MTAPI maximum number of tasks");
} }
ReturnType result = neutral;
typedef ReduceFunctor<RAI, ReturnType, ReductionFunction, typedef ReduceFunctor<RAI, ReturnType, ReductionFunction,
TransformationFunction> Functor; TransformationFunction> Functor;
Functor functor(first, last, neutral, reduction, transformation, policy, BlockSizePartitioner<RAI> partitioner(first, last, block_size);
used_block_size, result); ReturnType result = neutral;
mtapi::Task task = node.Spawn(mtapi::Action(base::MakeFunction( Functor functor(0,
partitioner.Size() - 1,
neutral,
reduction, transformation,
policy,
partitioner,
result);
mtapi::Task task = node.Spawn(
mtapi::Action(base::MakeFunction(
functor, &Functor::Action), policy)); functor, &Functor::Action), policy));
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
return result; return result;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment