Skip to content

Commit

Permalink
Merge pull request #69 from SimeonEhrig/endIteratorInterface
Browse files Browse the repository at this point in the history
Extend interface of reduce and transform to allow begin and end pointer
  • Loading branch information
SimeonEhrig authored Jan 19, 2022
2 parents 91028b1 + b455ba5 commit a1252fa
Show file tree
Hide file tree
Showing 4 changed files with 378 additions and 5 deletions.
106 changes: 106 additions & 0 deletions include/vikunja/reduce/reduce.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,62 @@ namespace vikunja
return result[0];
}

/**
* This is a function which transforms the input values and uses a reduce to accumulate the transformed values.
* For example, given the array [1, 2, 3, 4], the transform function (x) -> x + 1, and the reduce function
* (x,y) -> x + y would return 2 + 3 + 4 + 5 = 14.
* @tparam TAcc The alpaka accelerator type to use.
* @tparam WorkDivPolicy The working division policy. Defaults to a templated value depending on the
* accelerator. For the API of this, see workdiv/BlockBasedWorkDiv.hpp
* @tparam MemAccessPolicy The memory access policy. Defaults to a templated value depending on the
* accelerator. For the API of this, see mem/iterator/PolicyBasedBlockIterator
* @tparam TTransformFunc Type of the transform operator.
* @tparam TReduceFunc Type of the reduce operator.
* @tparam TInputIterator Type of the input iterator. Should be a pointer-like type.
* @tparam TDevAcc The type of the alpaka accelerator.
* @tparam TDevHost The type of the alpaka host.
* @tparam TQueue The type of the alpaka queue.
* @tparam TTransformOperator The vikunja::operators type of the transform function.
* @tparam TReduceOperator The vikunja::operators type of the reduce function.
* @tparam TRed The return value of the function.
* @param devAcc The alpaka accelerator.
* @param devHost The alpaka host.
* @param queue The alpaka queue.
* @param bufferBegin The begin pointer of the input buffer.
* @param bufferEnd The end pointer of the input buffer.
* @param transformFunc The transform operator.
* @param reduceFunc The reduce operator.
* @return Value of the combined transform/reduce operation.
*/
template<
typename TAcc,
typename WorkDivPolicy = vikunja::workdiv::BlockBasedPolicy<TAcc>,
typename MemAccessPolicy = vikunja::mem::iterator::MemAccessPolicy<TAcc>,
typename TTransformFunc,
typename TReduceFunc,
typename TInputIterator,
typename TDevAcc,
typename TDevHost,
typename TQueue,
typename TTransformOperator = vikunja::operators::
UnaryOp<TAcc, TTransformFunc, typename std::iterator_traits<TInputIterator>::value_type>,
typename TReduceOperator = vikunja::operators::
BinaryOp<TAcc, TReduceFunc, typename TTransformOperator::TRed, typename TTransformOperator::TRed>,
typename TRed = typename TReduceOperator::TRed>
auto deviceTransformReduce(
TDevAcc& devAcc,
TDevHost& devHost,
TQueue& queue,
TInputIterator const& bufferBegin,
TInputIterator const& bufferEnd,
TTransformFunc const& transformFunc,
TReduceFunc const& reduceFunc) -> TRed
{
assert(bufferEnd >= bufferBegin);
auto size = static_cast<typename alpaka::traits::IdxType<TAcc>::type>(bufferEnd - bufferBegin);
return deviceTransformReduce<TAcc>(devAcc, devHost, queue, size, bufferBegin, transformFunc, reduceFunc);
}

/**
* This is a reduce function, which works exactly like deviceTransformReduce with an identity function for
* the transform operator.
Expand Down Expand Up @@ -270,5 +326,55 @@ namespace vikunja
TQueue,
TIdx>(devAcc, devHost, queue, n, buffer, detail::Identity<TRed>(), func);
}

/**
* This is a reduce function, which works exactly like deviceTransformReduce with an identity function for
* the transform operator.
* @see deviceTransformReduce.
* @tparam TAcc
* @tparam WorkDivPolicy
* @tparam MemAccessPolicy
* @tparam TFunc
* @tparam TInputIterator
* @tparam TDevAcc
* @tparam TDevHost
* @tparam TQueue
* @tparam TReduceOperator The vikunja::operators type of the reduce function.
* @tparam TRed The return value of the function.
* @param devAcc
* @param devHost
* @param queue
* @param bufferBegin The begin pointer of the input buffer.
* @param bufferEnd The end pointer of the input buffer.
* @param func
* @return
*/
template<
typename TAcc,
typename WorkDivPolicy = vikunja::workdiv::BlockBasedPolicy<TAcc>,
typename MemAccessPolicy = vikunja::mem::iterator::MemAccessPolicy<TAcc>,
typename TFunc,
typename TInputIterator,
typename TDevAcc,
typename TDevHost,
typename TQueue,
typename TOperator = vikunja::operators::BinaryOp<
TAcc,
TFunc,
typename std::iterator_traits<TInputIterator>::value_type,
typename std::iterator_traits<TInputIterator>::value_type>,
typename TRed = typename TOperator::TRed>
auto deviceReduce(
TDevAcc& devAcc,
TDevHost& devHost,
TQueue& queue,
TInputIterator const& bufferBegin,
TInputIterator const& bufferEnd,
TFunc const& func) -> TRed
{
assert(bufferEnd >= bufferBegin);
auto size = static_cast<typename alpaka::traits::IdxType<TAcc>::type>(bufferEnd - bufferBegin);
return deviceReduce<TAcc>(devAcc, devHost, queue, size, bufferBegin, func);
}
} // namespace reduce
} // namespace vikunja
97 changes: 97 additions & 0 deletions include/vikunja/transform/transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,54 @@ namespace vikunja
alpaka::exec<TAcc>(queue, multiBlockWorkDiv, kernel, source, destination, n, func);
}

/**
* This is a function that transforms every element of an input iterator to another element in an output
* iterator, i.e. if one has the array [1,2,3,4] and the transform function (x) -> x + 1, the output
* will contain [2,3,4,5].
* Input and output iterator can be the same. The output must be at least as big as the input, otherwise bad
* things are bound to happen.
* @tparam TAcc The alpaka accelerator type.
* @tparam WorkDivPolicy The working division policy. Defaults to a templated value depending on the
* accelerator. For the API of this, see workdiv/BlockBasedWorkDiv.hpp
* @tparam MemAccessPolicy The memory access policy. Defaults to a templated value depending on the
* accelerator. For the API of this, see mem/iterator/PolicyBasedBlockIterator
* @tparam TFunc Type of the transform operator.
* @tparam TInputIterator Type of the input iterator. Should be a pointer-like type.
* @tparam TOutputIterator Type of the output iterator. Should be a pointer-like type.
* @tparam TDevAcc The type of the alpaka accelerator.
* @tparam TQueue The type of the alpaka queue.
* @tparam TOperator The vikunja::operators type of the transform function.
* @param devAcc The alpaka accelerator.
* @param queue The alpaka queue.
* @param sourceBegin The begin pointer of the input buffer.
* @param sourceEnd The end pointer of the input buffer.
* @param destination The output iterator. Should be pointer-like.
* @param func The transform operator.
*/
template<
typename TAcc,
typename WorkDivPolicy = vikunja::workdiv::BlockBasedPolicy<TAcc>,
typename MemAccessPolicy = vikunja::mem::iterator::MemAccessPolicy<TAcc>,
typename TFunc,
typename TInputIterator,
typename TOutputIterator,
typename TDevAcc,
typename TQueue,
typename TOperator
= vikunja::operators::UnaryOp<TAcc, TFunc, typename std::iterator_traits<TInputIterator>::value_type>>
auto deviceTransform(
TDevAcc& devAcc,
TQueue& queue,
TInputIterator const& sourceBegin,
TInputIterator const& sourceEnd,
TOutputIterator const& destination,
TFunc const& func) -> void
{
assert(sourceEnd >= sourceBegin);
auto size = static_cast<typename alpaka::traits::IdxType<TAcc>::type>(sourceEnd - sourceBegin);
deviceTransform<TAcc>(devAcc, queue, size, sourceBegin, destination, func);
}

/**
* A transform similar to the above, except that two input iterators are used in parallel.
* @tparam TAcc
Expand Down Expand Up @@ -182,5 +230,54 @@ namespace vikunja
detail::BlockThreadTransformKernel<blockSize, MemAccessPolicy, TOperator> kernel;
alpaka::exec<TAcc>(queue, multiBlockWorkDiv, kernel, source, sourceSecond, destination, n, func);
}

/**
* A transform similar to the above, except that two input iterators are used in parallel.
* @tparam TAcc
* @tparam WorkDivPolicy
* @tparam MemAccessPolicy
* @tparam TFunc
* @tparam TInputIterator
* @tparam TInputIteratorSecond
* @tparam TOutputIterator
* @tparam TDevAcc
* @tparam TQueue
* @tparam TOperator
* @param devAcc
* @param queue
* @param sourceBegin The begin pointer of the input buffer.
* @param sourceEnd The end pointer of the input buffer.
* @param sourceSecond
* @param destination
* @param func
*/
template<
typename TAcc,
typename WorkDivPolicy = vikunja::workdiv::BlockBasedPolicy<TAcc>,
typename MemAccessPolicy = vikunja::mem::iterator::MemAccessPolicy<TAcc>,
typename TFunc,
typename TInputIterator,
typename TInputIteratorSecond,
typename TOutputIterator,
typename TDevAcc,
typename TQueue,
typename TOperator = vikunja::operators::BinaryOp<
TAcc,
TFunc,
typename std::iterator_traits<TInputIterator>::value_type,
typename std::iterator_traits<TInputIteratorSecond>::value_type>>
auto deviceTransform(
TDevAcc& devAcc,
TQueue& queue,
TInputIterator const& sourceBegin,
TInputIterator const& sourceEnd,
TInputIteratorSecond const& sourceSecond,
TOutputIterator const& destination,
TFunc const& func) -> void
{
assert(sourceEnd >= sourceBegin);
auto size = static_cast<typename alpaka::traits::IdxType<TAcc>::type>(sourceEnd - sourceBegin);
deviceTransform<TAcc>(devAcc, queue, size, sourceBegin, sourceSecond, destination, func);
}
} // namespace transform
} // namespace vikunja
69 changes: 67 additions & 2 deletions test/integ/reduce/src/Reduce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,38 @@ namespace vikunja
};
};

template<
typename TDim,
template<typename, typename>
class TAcc,
typename TData,
typename TDataResult = TData,
typename TIdx = std::uint64_t>
class TestSetupReducePtr : public TestSetupBase<TDim, TAcc, TData, TDataResult, TIdx>
{
public:
using TestSetupBase<TDim, TAcc, TData, TDataResult, TIdx>::TestSetupBase;

using Base = typename vikunja::test::reduce::TestSetupBase<TDim, TAcc, TData, TDataResult, TIdx>;

template<typename TReduceFunctor>
void run(TReduceFunctor reduceFunctor)
{
alpaka::memcpy(Base::Base::queueAcc, Base::m_device_mem, Base::m_host_mem, Base::m_extent);

TData* begin = alpaka::getPtrNative(Base::m_device_mem);
TData* end = begin + Base::m_size;

Base::m_result = vikunja::reduce::deviceReduce<typename Base::Acc>(
Base::devAcc,
Base::devHost,
Base::Base::queueAcc,
begin,
end,
reduceFunctor);
};
};

template<
typename TDim,
template<typename, typename>
Expand Down Expand Up @@ -89,6 +121,39 @@ namespace vikunja
};
};

template<
typename TDim,
template<typename, typename>
class TAcc,
typename TData,
typename TDataResult = TData,
typename TIdx = std::uint64_t>
class TestSetupReduceTransformPtr : public TestSetupBase<TDim, TAcc, TData, TDataResult, TIdx>
{
public:
using TestSetupBase<TDim, TAcc, TData, TDataResult, TIdx>::TestSetupBase;

using Base = typename vikunja::test::reduce::TestSetupBase<TDim, TAcc, TData, TDataResult, TIdx>;

template<typename TReduceFunctor, typename TTransformFunctor>
void run(TReduceFunctor reduceFunctor, TTransformFunctor transformFunctor)
{
alpaka::memcpy(Base::Base::queueAcc, Base::m_device_mem, Base::m_host_mem, Base::m_extent);

TData* begin = alpaka::getPtrNative(Base::m_device_mem);
TData* end = begin + Base::m_size;

Base::m_result = vikunja::reduce::deviceTransformReduce<typename Base::Acc>(
Base::devAcc,
Base::devHost,
Base::Base::queueAcc,
begin,
end,
transformFunctor,
reduceFunctor);
};
};

} // namespace reduce
} // namespace test
} // namespace vikunja
Expand Down Expand Up @@ -220,7 +285,7 @@ TEMPLATE_TEST_CASE(

INFO((vikunja::test::print_acc_info<Dim>(size)));

vikunja::test::reduce::TestSetupReduce<Dim, alpaka::ExampleDefaultAcc, Data> setup(size);
vikunja::test::reduce::TestSetupReducePtr<Dim, alpaka::ExampleDefaultAcc, Data> setup(size);

// setup initial values
Data* const host_mem_ptr = setup.get_host_mem_ptr();
Expand Down Expand Up @@ -353,7 +418,7 @@ TEMPLATE_TEST_CASE(

INFO((vikunja::test::print_acc_info<Dim>(size)));

vikunja::test::reduce::TestSetupReduceTransform<Dim, alpaka::ExampleDefaultAcc, Data> setup(size);
vikunja::test::reduce::TestSetupReduceTransformPtr<Dim, alpaka::ExampleDefaultAcc, Data> setup(size);

// setup initial values
Data* const host_mem_ptr = setup.get_host_mem_ptr();
Expand Down
Loading

0 comments on commit a1252fa

Please sign in to comment.