Commit 9a3b71bb by Tobias Fuchs

algorithms_cpp: using block size partitioner in Reduce and Count

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