| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // This Source Code Form is subject to the terms of the Mozilla | |
| // Public License v. 2.0. If a copy of the MPL was not distributed | |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
| // SPDX-FileCopyrightText: The Eigen Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| // Host-side helpers shared by the CUDA and HIP paths of the Tensor GPU device: reporting of failed runtime calls | |
| // and checked kernel launches. Written against the gpu* aliases of GpuHipCudaDefines.inc, so it is only meaningful | |
| // inside that alias window (TensorDeviceGpu.h includes it there) and neither includes nor undefines the .inc files | |
| // itself; outside the window it is inert, so a standalone parse sees nothing. The macros below may expand after the | |
| // window closes, which is why each of them only calls a function defined here. | |
| #if defined(EIGEN_CORE_GPU_HIP_CUDA_DEFINES_H) && !defined(EIGEN_CORE_UTIL_GPU_RUNTIME_H) | |
| #define EIGEN_CORE_UTIL_GPU_RUNTIME_H | |
| #include <cstdio> | |
| #include <cstdlib> | |
| #include <utility> | |
| namespace Eigen { | |
| namespace internal { | |
| // Prints `file:line: call: error name: description` to stderr and stops: std::abort() where assertions are | |
| // compiled out, a failed eigen_assert otherwise, so a debugger or the test harness sees the usual assertion. | |
| inline void gpu_runtime_check_failed(gpuError_t error, const char* expression, const char* file, int line) { | |
| std::fprintf(stderr, "%s:%d: %s: %s: %s\n", file, line, expression, gpuGetErrorName(error), gpuGetErrorString(error)); | |
| #if defined(EIGEN_NO_DEBUG) | |
| std::abort(); | |
| #else | |
| eigen_assert(false && "GPU runtime call failed"); | |
| #endif | |
| } | |
| inline void gpu_runtime_check(gpuError_t error, const char* expression, const char* file, int line) { | |
| if (error != gpuSuccess) gpu_runtime_check_failed(error, expression, file, line); | |
| } | |
| } // namespace internal | |
| } // namespace Eigen | |
| // EIGEN_GPU_RUNTIME_CHECK(call) evaluates a runtime-API call once and reports a failure through | |
| // gpu_runtime_check_failed(). Define the macro before including the module to route failures elsewhere. There is | |
| // no mode that ignores the result: a failed call has not done its work, and a sticky error leaves the context | |
| // unusable for every later call. | |
| #if !defined(EIGEN_GPU_RUNTIME_CHECK) | |
| #define EIGEN_GPU_RUNTIME_CHECK(expr) \ | |
| do { \ | |
| ::Eigen::internal::gpu_runtime_check((expr), #expr, __FILE__, __LINE__); \ | |
| } while (0) | |
| #endif | |
| #if defined(EIGEN_GPUCC) | |
| namespace Eigen { | |
| namespace internal { | |
| // Enqueues `kernel` on `stream` and reports a launch failure through EIGEN_GPU_RUNTIME_CHECK. hip-clang accepts the | |
| // <<<>>> syntax, so CUDA and HIP share one definition; the kernel is passed as the function pointer the occupancy | |
| // API takes as well. With EIGEN_GPU_SYNC_LAUNCHES defined every launch is followed by a checked synchronization of | |
| // its stream, so an execution failure is reported at the launch that caused it rather than at a later call. | |
| template <typename... KernelArgs, typename... Args> | |
| void gpu_launch(void (*kernel)(KernelArgs...), dim3 grid, dim3 block, size_t shared_mem, gpuStream_t stream, | |
| Args&&... args) { | |
| // clang-format off | |
| kernel<<<grid, block, shared_mem, stream>>>(std::forward<Args>(args)...); | |
| // clang-format on | |
| EIGEN_GPU_RUNTIME_CHECK(gpuGetLastError()); | |
| #if defined(EIGEN_GPU_SYNC_LAUNCHES) | |
| EIGEN_GPU_RUNTIME_CHECK(gpuStreamSynchronize(stream)); | |
| #endif | |
| } | |
| } // namespace internal | |
| } // namespace Eigen | |
| #endif // EIGEN_GPUCC | |
| #endif // EIGEN_CORE_UTIL_GPU_RUNTIME_H |