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 <rmm/logger.hpp>
20 
21 #include <cuda_runtime_api.h>
22 
23 #include <cassert>
24 #include <iostream>
25 #include <stdexcept>
26 #include <string>
27 
28 namespace rmm {
36 struct logic_error : public std::logic_error {
37  using std::logic_error::logic_error;
38 };
39 
44 struct cuda_error : public std::runtime_error {
45  using std::runtime_error::runtime_error;
46 };
47 
52 class bad_alloc : public std::bad_alloc {
53  public:
54  bad_alloc(const char* msg) : _what{std::string{std::bad_alloc::what()} + ": " + msg} {}
55  bad_alloc(std::string const& msg) : bad_alloc{msg.c_str()} {}
56 
57  [[nodiscard]] const char* what() const noexcept override { return _what.c_str(); }
58 
59  private:
60  std::string _what;
61 };
62 
68 class out_of_memory : public bad_alloc {
69  public:
70  out_of_memory(const char* msg) : bad_alloc{std::string{"out_of_memory: "} + msg} {}
71  out_of_memory(std::string const& msg) : out_of_memory{msg.c_str()} {}
72 };
73 
78 class out_of_range : public std::out_of_range {
79  using std::out_of_range::out_of_range;
80 };
81 
82 } // namespace rmm
83 
84 #define STRINGIFY_DETAIL(x) #x
85 #define RMM_STRINGIFY(x) STRINGIFY_DETAIL(x)
86 
110 #define RMM_EXPECTS(...) \
111  GET_RMM_EXPECTS_MACRO(__VA_ARGS__, RMM_EXPECTS_3, RMM_EXPECTS_2) \
112  (__VA_ARGS__)
113 #define GET_RMM_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME
114 #define RMM_EXPECTS_3(_condition, _exception_type, _reason) \
115  (!!(_condition)) ? static_cast<void>(0) \
116  : throw _exception_type /*NOLINT(bugprone-macro-parentheses)*/ \
117  { \
118  "RMM failure at: " __FILE__ ":" RMM_STRINGIFY(__LINE__) ": " _reason \
119  }
120 #define RMM_EXPECTS_2(_condition, _reason) RMM_EXPECTS_3(_condition, rmm::logic_error, _reason)
121 
134 #define RMM_FAIL(...) \
135  GET_RMM_FAIL_MACRO(__VA_ARGS__, RMM_FAIL_2, RMM_FAIL_1) \
136  (__VA_ARGS__)
137 #define GET_RMM_FAIL_MACRO(_1, _2, NAME, ...) NAME
138 #define RMM_FAIL_2(_what, _exception_type) \
139  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
140  throw _exception_type{"RMM failure at:" __FILE__ ":" RMM_STRINGIFY(__LINE__) ": " _what};
141 #define RMM_FAIL_1(_what) RMM_FAIL_2(_what, rmm::logic_error)
142 
164 #define RMM_CUDA_TRY(...) \
165  GET_RMM_CUDA_TRY_MACRO(__VA_ARGS__, RMM_CUDA_TRY_2, RMM_CUDA_TRY_1) \
166  (__VA_ARGS__)
167 #define GET_RMM_CUDA_TRY_MACRO(_1, _2, NAME, ...) NAME
168 #define RMM_CUDA_TRY_2(_call, _exception_type) \
169  do { \
170  cudaError_t const error = (_call); \
171  if (cudaSuccess != error) { \
172  cudaGetLastError(); \
173  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
174  throw _exception_type{std::string{"CUDA error at: "} + __FILE__ + ":" + \
175  RMM_STRINGIFY(__LINE__) + ": " + cudaGetErrorName(error) + " " + \
176  cudaGetErrorString(error)}; \
177  } \
178  } while (0)
179 #define RMM_CUDA_TRY_1(_call) RMM_CUDA_TRY_2(_call, rmm::cuda_error)
180 
191 #define RMM_CUDA_TRY_ALLOC(_call) \
192  do { \
193  cudaError_t const error = (_call); \
194  if (cudaSuccess != error) { \
195  cudaGetLastError(); \
196  auto const msg = std::string{"CUDA error at: "} + __FILE__ + ":" + RMM_STRINGIFY(__LINE__) + \
197  ": " + cudaGetErrorName(error) + " " + cudaGetErrorString(error); \
198  if (cudaErrorMemoryAllocation == error) { \
199  throw rmm::out_of_memory{msg}; \
200  } else { \
201  throw rmm::bad_alloc{msg}; \
202  } \
203  } \
204  } while (0)
205 
231 #ifdef NDEBUG
232 #define RMM_ASSERT_CUDA_SUCCESS(_call) \
233  do { \
234  (_call); \
235  } while (0);
236 #else
237 #define RMM_ASSERT_CUDA_SUCCESS(_call) \
238  do { \
239  cudaError_t const status__ = (_call); \
240  if (status__ != cudaSuccess) { \
241  std::cerr << "CUDA Error detected. " << cudaGetErrorName(status__) << " " \
242  << cudaGetErrorString(status__) << std::endl; \
243  } \
244  /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) */ \
245  assert(status__ == cudaSuccess); \
246  } while (0)
247 #endif
248 
252 #ifdef NDEBUG
253 #define RMM_LOGGING_ASSERT(_expr) (void)0
254 #elif SPDLOG_ACTIVE_LEVEL < SPDLOG_LEVEL_OFF
255 #define RMM_LOGGING_ASSERT(_expr) \
256  do { \
257  bool const success = (_expr); \
258  if (!success) { \
259  RMM_LOG_CRITICAL( \
260  "[" __FILE__ ":" RMM_STRINGIFY(__LINE__) "] Assertion " RMM_STRINGIFY(_expr) " failed."); \
261  rmm::logger().flush(); \
262  /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) */ \
263  assert(success); \
264  } \
265  } while (0)
266 #else
267 #define RMM_LOGGING_ASSERT(_expr) assert((_expr));
268 #endif
rmm::bad_alloc
Exception thrown when an RMM allocation fails.
Definition: error.hpp:52
rmm::logic_error
Exception thrown when logical precondition is violated.
Definition: error.hpp:36
rmm::cuda_error
Exception thrown when a CUDA error is encountered.
Definition: error.hpp:44
rmm::out_of_memory
Exception thrown when RMM runs out of memory.
Definition: error.hpp:68
rmm::out_of_range
Exception thrown when attempting to access outside of a defined range.
Definition: error.hpp:78