Skip to content

Commit

Permalink
Add runtime macro alpaka_device_throw
Browse files Browse the repository at this point in the history
  • Loading branch information
mehmetyusufoglu committed Jun 13, 2024
1 parent c2a37cc commit b03addd
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/alpaka/alpaka.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#include "alpaka/core/OmpSchedule.hpp"
#include "alpaka/core/Positioning.hpp"
#include "alpaka/core/RemoveRestrict.hpp"
#include "alpaka/core/RuntimeMacros.hpp"
#include "alpaka/core/Sycl.hpp"
#include "alpaka/core/ThreadPool.hpp"
#include "alpaka/core/Unreachable.hpp"
Expand Down
34 changes: 34 additions & 0 deletions include/alpaka/core/RuntimeMacros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* Copyright 2022 Andrea Bocci, Mehmet Yusufoglu */
#pragma once
//! ALPAKA_DEVICE_THROW either aborts(terminating the program and creating a core dump) or throws std::runtime_error
//! depending on the Acc. It is impossible to "catch" aborts; but the std::runtime_error exception can be catched in
//! the catch block.
//!
//! The OpenMP specification mandates that exceptions thrown by some thread must be handled by the same thread.
//! Therefore std::runtime_error thrown by ALPAKA_DEVICE_THROW aborts the the program for OpenMP backends. If needed
//! the SIGABRT signal can be catched by signal handler.
#if defined(ALPAKA_ACC_GPU_CUDA_ENABLED) && defined(__CUDA_ARCH__)
# define ALPAKA_DEVICE_THROW(MSG) \
{ \
printf("%s [ALPAKA_DEVICE_THROW: Calling __trap(). Cuda backend is enabled.]\n", (MSG)); \
__trap(); \
}
#elif defined(ALPAKA_ACC_GPU_HIP_ENABLED) && defined(__HIP_DEVICE_COMPILE__)
# define ALPAKA_DEVICE_THROW(MSG) \
{ \
printf("%s [ALPAKA_DEVICE_THROW: Calling abort(). Hip backend is enabled.]\n", (MSG)); \
abort(); \
}
#elif defined(ALPAKA_ACC_SYCL_ENABLED) && defined(__SYCL_DEVICE_ONLY__)
# define ALPAKA_DEVICE_THROW(MSG) \
{ \
printf("%s [ALPAKA_DEVICE_THROW: Calling std::abort(). Sycl backend is enabled.]\n", (MSG)); \
std::abort(); \
}
#else
# define ALPAKA_DEVICE_THROW(MSG) \
{ \
printf("Throwing std::runtime_error exception\n"); \
throw std::runtime_error(MSG); \
}
#endif
85 changes: 85 additions & 0 deletions test/unit/kernel/src/KernelThrow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* Copyright 2022 René Widera, Mehmet Yusufoglu, Andrea Bocci
* SPDX-License-Identifier: MPL-2.0
*/

#include <alpaka/core/RuntimeMacros.hpp>
#include <alpaka/test/acc/TestAccs.hpp>
#include <alpaka/test/queue/Queue.hpp>

#include <catch2/catch_template_test_macros.hpp>
#include <catch2/catch_test_macros.hpp>

class KernelWithThrow
{
public:
template<typename TAcc>
ALPAKA_FN_ACC auto operator()(TAcc const& acc) const -> void
{
using Idx = alpaka::Idx<TAcc>;
using Dim = alpaka::Dim<TAcc>;
using Vec = alpaka::Vec<Dim, Idx>;
Vec const globalThreadIdx = alpaka::getIdx<alpaka::Grid, alpaka::Threads>(acc);
Vec const globalThreadExtent = alpaka::getWorkDiv<alpaka::Grid, alpaka::Threads>(acc);

// Map the three dimensional thread index into a one dimensional thread index space.
auto const linearizedGlobalThreadIdx = alpaka::mapIdx<1u>(globalThreadIdx, globalThreadExtent);

if(static_cast<unsigned>(linearizedGlobalThreadIdx[0u]) == 0u)
{
printf("linearizedGlobalThreadIdx: %lu\n", linearizedGlobalThreadIdx[0]);
// Throw abort or std::runtime_error depending on acc type
ALPAKA_DEVICE_THROW("Exception thrown by the kernel");
}
alpaka::syncBlockThreads(acc);
}
};

template<typename T, typename Acc>
void checkThrow()
{
if constexpr(alpaka::accMatchesTags<Acc, T>)
{
using Idx = alpaka::Idx<Acc>;
using Dim = alpaka::Dim<Acc>;
using Vec = alpaka::Vec<Dim, Idx>;
using QueueProperty = alpaka::Blocking;
using Queue = alpaka::Queue<Acc, QueueProperty>;

auto const platformAcc = alpaka::Platform<Acc>{};
auto const devAcc = alpaka::getDevByIdx(platformAcc, 0);

Queue queue(devAcc);
auto const workDiv = alpaka::WorkDivMembers<Dim, Idx>{Vec{8}, Vec{1}, Vec{1}};

KernelWithThrow kernel;
auto runner = [&]() { alpaka::exec<Acc>(queue, workDiv, kernel); };
try
{
runner();
}
catch(std::runtime_error& e)
{
CHECK(e.what() == std::string("Exception thrown by the kernel"));
}
catch(std::exception& e)
{
FAIL(std::string("Wrong exception type thrown in kernel:") + e.what());
}
}
}

using TestAccs = alpaka::test::EnabledAccs<alpaka::DimInt<1u>, std::size_t>;

TEMPLATE_LIST_TEST_CASE("ThrowForCpuThreadAndSerial", "[kernel]", TestAccs)
{
using Acc = TestType;
// Test runtime-error exceptions. Aborts can not be catched.
checkThrow<alpaka::TagCpuThreads, Acc>();
checkThrow<alpaka::TagCpuSerial, Acc>();

// The OpenMP specification mandates that exceptions thrown by some thread must be handled by the same thread and
// within the same parallel region. Therefore std::runtime_error aborts the program.

// checkThrow<alpaka::TagCpuOmp2Blocks, Acc>();
// checkThrow<alpaka::TagCpuOmp2Threads, Acc>();
}

0 comments on commit b03addd

Please sign in to comment.