Skip to content

Commit

Permalink
show better error message if kernel argument is not trivially copyable
Browse files Browse the repository at this point in the history
fix alpaka-group#1922

Currently, alpaka is checking all kernel arguments with the fold expression that all arguments are trivially copyable. The problem is if one argument is not trivially copyable the user does not know which.

By checking each argument separately and providing the index to the validator class the user gets the information on which argument produces issues.
This simplifies the debugging a lot.
  • Loading branch information
psychocoderHPC committed Jun 28, 2023
1 parent 78e984d commit 70cb398
Showing 1 changed file with 66 additions and 47 deletions.
113 changes: 66 additions & 47 deletions include/alpaka/kernel/Traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,70 +199,89 @@ namespace alpaka
static_assert(std::is_same_v<Result, void>, "The TKernelFnObj is required to return void!");
}
};
} // namespace detail
//! Creates a kernel execution task.
//!
//! \tparam TAcc The accelerator type.
//! \param workDiv The index domain work division.
//! \param kernelFnObj The kernel function object which should be executed.
//! \param args,... The kernel invocation arguments.
//! \return The kernel execution task.

template<typename T, size_t N>
struct AssertArgumentNTriviallyCopyable
{
static_assert(std::is_trivially_copyable_v<T>, "Kernel N arguments must be trivially copyable!");
};

template<typename... T, size_t... I>
void assertTriviallyCopyable(std::tuple<T...>&&, std::index_sequence<I...>)
{
(AssertArgumentNTriviallyCopyable<std::tuple_element_t<I, std::tuple<T...>>, I>{}, ...);
}

//! Check that each argument type is trivially copyable
template<typename... T>
void assertTriviallyCopyable(T&&...)
{
assertTriviallyCopyable(std::tuple<T...>{}, std::make_index_sequence<sizeof...(T)>{});
!
}
}
} // namespace detail
//! Creates a kernel execution task.
//!
//! \tparam TAcc The accelerator type.
//! \param workDiv The index domain work division.
//! \param kernelFnObj The kernel function object which should be executed.
//! \param args,... The kernel invocation arguments.
//! \return The kernel execution task.
#if BOOST_COMP_CLANG
# pragma clang diagnostic pop
#endif
template<typename TAcc, typename TWorkDiv, typename TKernelFnObj, typename... TArgs>
ALPAKA_FN_HOST auto createTaskKernel(TWorkDiv const& workDiv, TKernelFnObj const& kernelFnObj, TArgs&&... args)
{
// check for void return type
detail::CheckFnReturnType<TAcc>{}(kernelFnObj, args...);
template<typename TAcc, typename TWorkDiv, typename TKernelFnObj, typename... TArgs>
ALPAKA_FN_HOST auto createTaskKernel(TWorkDiv const& workDiv, TKernelFnObj const& kernelFnObj, TArgs&&... args)
{
// check for void return type
detail::CheckFnReturnType<TAcc>{}(kernelFnObj, args...);

#if BOOST_COMP_NVCC
static_assert(
std::is_trivially_copyable_v<TKernelFnObj> || __nv_is_extended_device_lambda_closure_type(TKernelFnObj)
|| __nv_is_extended_host_device_lambda_closure_type(TKernelFnObj),
"Kernels must be trivially copyable or an extended CUDA lambda expression!");
static_assert(
std::is_trivially_copyable_v<TKernelFnObj> || __nv_is_extended_device_lambda_closure_type(TKernelFnObj)
|| __nv_is_extended_host_device_lambda_closure_type(TKernelFnObj),
"Kernels must be trivially copyable or an extended CUDA lambda expression!");
#else
static_assert(std::is_trivially_copyable_v<TKernelFnObj>, "Kernels must be trivially copyable!");
static_assert(std::is_trivially_copyable_v<TKernelFnObj>, "Kernels must be trivially copyable!");
#endif
static_assert(
(std::is_trivially_copyable_v<std::decay_t<TArgs>> && ...),
"Kernel arguments must be trivially copyable!");
static_assert(
Dim<std::decay_t<TWorkDiv>>::value == Dim<TAcc>::value,
"The dimensions of TAcc and TWorkDiv have to be identical!");
static_assert(
std::is_same_v<Idx<std::decay_t<TWorkDiv>>, Idx<TAcc>>,
"The idx type of TAcc and the idx type of TWorkDiv have to be identical!");
detail::assertTriviallyCopyable(std::forward<std::decay_t<TArgs>>(args)...);
static_assert(
Dim<std::decay_t<TWorkDiv>>::value == Dim<TAcc>::value,
"The dimensions of TAcc and TWorkDiv have to be identical!");
static_assert(
std::is_same_v<Idx<std::decay_t<TWorkDiv>>, Idx<TAcc>>,
"The idx type of TAcc and the idx type of TWorkDiv have to be identical!");

#if ALPAKA_DEBUG >= ALPAKA_DEBUG_FULL
std::cout << __func__ << " workDiv: " << workDiv
<< ", kernelFnObj: " << core::demangled<decltype(kernelFnObj)> << std::endl;
std::cout << __func__ << " workDiv: " << workDiv
<< ", kernelFnObj: " << core::demangled<decltype(kernelFnObj)> << std::endl;
#endif
return trait::CreateTaskKernel<TAcc, TWorkDiv, TKernelFnObj, TArgs...>::createTaskKernel(
workDiv,
kernelFnObj,
std::forward<TArgs>(args)...);
}
return trait::CreateTaskKernel<TAcc, TWorkDiv, TKernelFnObj, TArgs...>::createTaskKernel(
workDiv,
kernelFnObj,
std::forward<TArgs>(args)...);
}

#if BOOST_COMP_CLANG
# pragma clang diagnostic push
# pragma clang diagnostic ignored \
"-Wdocumentation" // clang does not support the syntax for variadic template arguments "args,..."
#endif
//! Executes the given kernel in the given queue.
//!
//! \tparam TAcc The accelerator type.
//! \param queue The queue to enqueue the view copy task into.
//! \param workDiv The index domain work division.
//! \param kernelFnObj The kernel function object which should be executed.
//! \param args,... The kernel invocation arguments.
//! Executes the given kernel in the given queue.
//!
//! \tparam TAcc The accelerator type.
//! \param queue The queue to enqueue the view copy task into.
//! \param workDiv The index domain work division.
//! \param kernelFnObj The kernel function object which should be executed.
//! \param args,... The kernel invocation arguments.
#if BOOST_COMP_CLANG
# pragma clang diagnostic pop
#endif
template<typename TAcc, typename TQueue, typename TWorkDiv, typename TKernelFnObj, typename... TArgs>
ALPAKA_FN_HOST auto exec(TQueue& queue, TWorkDiv const& workDiv, TKernelFnObj const& kernelFnObj, TArgs&&... args)
-> void
{
enqueue(queue, createTaskKernel<TAcc>(workDiv, kernelFnObj, std::forward<TArgs>(args)...));
}
template<typename TAcc, typename TQueue, typename TWorkDiv, typename TKernelFnObj, typename... TArgs>
ALPAKA_FN_HOST auto exec(TQueue& queue, TWorkDiv const& workDiv, TKernelFnObj const& kernelFnObj, TArgs&&... args)
-> void
{
enqueue(queue, createTaskKernel<TAcc>(workDiv, kernelFnObj, std::forward<TArgs>(args)...));
}
} // namespace alpaka

0 comments on commit 70cb398

Please sign in to comment.