error.hpp
1 /*
2  * Copyright (c) 2020, NVIDIA CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <cuda_runtime_api.h>
20 
21 #include <cassert>
22 #include <iostream>
23 #include <stdexcept>
24 #include <string>
25 
26 namespace rmm {
27 
37 struct logic_error : public std::logic_error {
38  using std::logic_error::logic_error;
39 };
40 
47 struct cuda_error : public std::runtime_error {
48  using std::runtime_error::runtime_error;
49 };
50 
57 class bad_alloc : public std::bad_alloc {
58  public:
64  bad_alloc(const char* msg) : _what{std::string{std::bad_alloc::what()} + ": " + msg} {}
65 
71  bad_alloc(std::string const& msg) : bad_alloc{msg.c_str()} {}
72 
76  [[nodiscard]] const char* what() const noexcept override { return _what.c_str(); }
77 
78  private:
79  std::string _what;
80 };
81 
89 class out_of_memory : public bad_alloc {
90  public:
96  out_of_memory(const char* msg) : bad_alloc{std::string{"out_of_memory: "} + msg} {}
97 
103  out_of_memory(std::string const& msg) : out_of_memory{msg.c_str()} {}
104 };
105 
112 class out_of_range : public std::out_of_range {
113  using std::out_of_range::out_of_range;
114 };
115 
116 } // namespace rmm
117 
118 #define STRINGIFY_DETAIL(x) #x
119 #define RMM_STRINGIFY(x) STRINGIFY_DETAIL(x)
120 
145 #define RMM_EXPECTS(...) \
146  GET_RMM_EXPECTS_MACRO(__VA_ARGS__, RMM_EXPECTS_3, RMM_EXPECTS_2) \
147  (__VA_ARGS__)
148 #define GET_RMM_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME
149 #define RMM_EXPECTS_3(_condition, _reason, _exception_type) \
150  (!!(_condition)) ? static_cast<void>(0) \
151  : throw _exception_type /*NOLINT(bugprone-macro-parentheses)*/ \
152  { \
153  "RMM failure at: " __FILE__ ":" RMM_STRINGIFY(__LINE__) ": " _reason \
154  }
155 #define RMM_EXPECTS_2(_condition, _reason) RMM_EXPECTS_3(_condition, _reason, rmm::logic_error)
156 
169 #define RMM_FAIL(...) \
170  GET_RMM_FAIL_MACRO(__VA_ARGS__, RMM_FAIL_2, RMM_FAIL_1) \
171  (__VA_ARGS__)
172 #define GET_RMM_FAIL_MACRO(_1, _2, NAME, ...) NAME
173 #define RMM_FAIL_2(_what, _exception_type) \
174  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
175  throw _exception_type{"RMM failure at:" __FILE__ ":" RMM_STRINGIFY(__LINE__) ": " _what};
176 #define RMM_FAIL_1(_what) RMM_FAIL_2(_what, rmm::logic_error)
177 
199 #define RMM_CUDA_TRY(...) \
200  GET_RMM_CUDA_TRY_MACRO(__VA_ARGS__, RMM_CUDA_TRY_2, RMM_CUDA_TRY_1) \
201  (__VA_ARGS__)
202 #define GET_RMM_CUDA_TRY_MACRO(_1, _2, NAME, ...) NAME
203 #define RMM_CUDA_TRY_2(_call, _exception_type) \
204  do { \
205  cudaError_t const error = (_call); \
206  if (cudaSuccess != error) { \
207  cudaGetLastError(); \
208  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
209  throw _exception_type{std::string{"CUDA error at: "} + __FILE__ + ":" + \
210  RMM_STRINGIFY(__LINE__) + ": " + cudaGetErrorName(error) + " " + \
211  cudaGetErrorString(error)}; \
212  } \
213  } while (0)
214 #define RMM_CUDA_TRY_1(_call) RMM_CUDA_TRY_2(_call, rmm::cuda_error)
215 
226 #define RMM_CUDA_TRY_ALLOC(_call) \
227  do { \
228  cudaError_t const error = (_call); \
229  if (cudaSuccess != error) { \
230  cudaGetLastError(); \
231  auto const msg = std::string{"CUDA error at: "} + __FILE__ + ":" + RMM_STRINGIFY(__LINE__) + \
232  ": " + cudaGetErrorName(error) + " " + cudaGetErrorString(error); \
233  if (cudaErrorMemoryAllocation == error) { throw rmm::out_of_memory{msg}; } \
234  throw rmm::bad_alloc{msg}; \
235  } \
236  } while (0)
237 
263 #ifdef NDEBUG
264 #define RMM_ASSERT_CUDA_SUCCESS(_call) \
265  do { \
266  (_call); \
267  } while (0);
268 #else
269 #define RMM_ASSERT_CUDA_SUCCESS(_call) \
270  do { \
271  cudaError_t const status__ = (_call); \
272  if (status__ != cudaSuccess) { \
273  std::cerr << "CUDA Error detected. " << cudaGetErrorName(status__) << " " \
274  << cudaGetErrorString(status__) << std::endl; \
275  } \
276  /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) */ \
277  assert(status__ == cudaSuccess); \
278  } while (0)
279 #endif
Exception thrown when an RMM allocation fails.
Definition: error.hpp:57
const char * what() const noexcept override
The explanatory string.
Definition: error.hpp:76
bad_alloc(std::string const &msg)
Constructs a bad_alloc with the error message.
Definition: error.hpp:71
bad_alloc(const char *msg)
Constructs a bad_alloc with the error message.
Definition: error.hpp:64
Exception thrown when RMM runs out of memory.
Definition: error.hpp:89
out_of_memory(std::string const &msg)
Constructs an out_of_memory with the error message.
Definition: error.hpp:103
out_of_memory(const char *msg)
Constructs an out_of_memory with the error message.
Definition: error.hpp:96
Exception thrown when attempting to access outside of a defined range.
Definition: error.hpp:112
Exception thrown when a CUDA error is encountered.
Definition: error.hpp:47
Exception thrown when logical precondition is violated.
Definition: error.hpp:37