detail/error.hpp
1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #pragma once
7 
8 #include <rmm/error.hpp>
9 
10 #include <cuda_runtime_api.h>
11 
12 #include <cassert>
13 #include <exception>
14 #include <iostream>
15 #include <string>
16 #include <type_traits>
17 
18 #define STRINGIFY_DETAIL(x) #x
19 #define RMM_STRINGIFY(x) STRINGIFY_DETAIL(x)
20 
45 #define RMM_EXPECTS(...) \
46  GET_RMM_EXPECTS_MACRO(__VA_ARGS__, RMM_EXPECTS_3, RMM_EXPECTS_2) \
47  (__VA_ARGS__)
48 #define GET_RMM_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME
49 #define RMM_EXPECTS_3(_condition, _reason, _exception_type) \
50  do { \
51  static_assert(std::is_base_of_v<std::exception, _exception_type>); \
52  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
53  (!!(_condition)) ? static_cast<void>(0) \
54  : throw _exception_type{std::string{"RMM failure at: "} + __FILE__ + ":" + \
55  RMM_STRINGIFY(__LINE__) + ": " + _reason}; \
56  } while (0)
57 #define RMM_EXPECTS_2(_condition, _reason) RMM_EXPECTS_3(_condition, _reason, rmm::logic_error)
58 
71 #define RMM_FAIL(...) \
72  GET_RMM_FAIL_MACRO(__VA_ARGS__, RMM_FAIL_2, RMM_FAIL_1) \
73  (__VA_ARGS__)
74 #define GET_RMM_FAIL_MACRO(_1, _2, NAME, ...) NAME
75 #define RMM_FAIL_2(_what, _exception_type) \
76  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
77  throw _exception_type \
78  { \
79  std::string{"RMM failure at:"} + __FILE__ + ":" + RMM_STRINGIFY(__LINE__) + ": " + _what \
80  }
81 #define RMM_FAIL_1(_what) RMM_FAIL_2(_what, rmm::logic_error)
82 
103 #define RMM_CUDA_TRY(...) \
104  GET_RMM_CUDA_TRY_MACRO(__VA_ARGS__, RMM_CUDA_TRY_2, RMM_CUDA_TRY_1) \
105  (__VA_ARGS__)
106 #define GET_RMM_CUDA_TRY_MACRO(_1, _2, NAME, ...) NAME
107 #define RMM_CUDA_TRY_2(_call, _exception_type) \
108  do { \
109  cudaError_t const error = (_call); \
110  if (cudaSuccess != error) { \
111  cudaGetLastError(); \
112  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
113  throw _exception_type{std::string{"CUDA error at: "} + __FILE__ + ":" + \
114  RMM_STRINGIFY(__LINE__) + ": " + cudaGetErrorName(error) + " " + \
115  cudaGetErrorString(error)}; \
116  } \
117  } while (0)
118 #define RMM_CUDA_TRY_1(_call) RMM_CUDA_TRY_2(_call, rmm::cuda_error)
119 
134 #define RMM_CUDA_TRY_ALLOC(...) \
135  GET_RMM_CUDA_TRY_ALLOC_MACRO(__VA_ARGS__, RMM_CUDA_TRY_ALLOC_2, RMM_CUDA_TRY_ALLOC_1) \
136  (__VA_ARGS__)
137 #define GET_RMM_CUDA_TRY_ALLOC_MACRO(_1, _2, NAME, ...) NAME
138 
139 #define RMM_CUDA_TRY_ALLOC_2(_call, num_bytes) \
140  do { \
141  cudaError_t const error = (_call); \
142  if (cudaSuccess != error) { \
143  cudaGetLastError(); \
144  auto const msg = std::string{"CUDA error (failed to allocate "} + \
145  std::to_string(num_bytes) + " bytes) at: " + __FILE__ + ":" + \
146  RMM_STRINGIFY(__LINE__) + ": " + cudaGetErrorName(error) + " " + \
147  cudaGetErrorString(error); \
148  if (cudaErrorMemoryAllocation == error) { throw rmm::out_of_memory{msg}; } \
149  throw rmm::bad_alloc{msg}; \
150  } \
151  } while (0)
152 
153 #define RMM_CUDA_TRY_ALLOC_1(_call) \
154  do { \
155  cudaError_t const error = (_call); \
156  if (cudaSuccess != error) { \
157  cudaGetLastError(); \
158  auto const msg = std::string{"CUDA error at: "} + __FILE__ + ":" + RMM_STRINGIFY(__LINE__) + \
159  ": " + cudaGetErrorName(error) + " " + cudaGetErrorString(error); \
160  if (cudaErrorMemoryAllocation == error) { throw rmm::out_of_memory{msg}; } \
161  throw rmm::bad_alloc{msg}; \
162  } \
163  } while (0)
164 
190 #ifdef NDEBUG
191 #define RMM_ASSERT_CUDA_SUCCESS(_call) \
192  do { \
193  (_call); \
194  } while (0);
195 #else
196 #define RMM_ASSERT_CUDA_SUCCESS(_call) \
197  do { \
198  cudaError_t const status__ = (_call); \
199  if (status__ != cudaSuccess) { \
200  std::cerr << "CUDA Error detected. " << cudaGetErrorName(status__) << " " \
201  << cudaGetErrorString(status__) << std::endl; \
202  } \
203  /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) */ \
204  assert(status__ == cudaSuccess); \
205  } while (0)
206 #endif