error.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2022, 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.h>
20 #include <cuda_runtime_api.h>
21 #include <stdexcept>
22 #include <string>
23 #include <type_traits>
24 
25 namespace cudf {
38 struct logic_error : public std::logic_error {
44  logic_error(char const* const message) : std::logic_error(message) {}
45 
51  logic_error(std::string const& message) : std::logic_error(message) {}
52 
53  // TODO Add an error code member? This would be useful for translating an
54  // exception to an error code in a pure-C API
55 };
60 struct cuda_error : public std::runtime_error {
67  cuda_error(std::string const& message, cudaError_t const& error)
68  : std::runtime_error(message), _cudaError(error)
69  {
70  }
71 
72  public:
78  cudaError_t error_code() const { return _cudaError; }
79 
80  protected:
81  cudaError_t _cudaError;
82 };
83 
84 struct fatal_cuda_error : public cuda_error {
85  using cuda_error::cuda_error; // Inherit constructors
86 };
89 } // namespace cudf
90 
91 #define STRINGIFY_DETAIL(x) #x
92 #define CUDF_STRINGIFY(x) STRINGIFY_DETAIL(x)
93 
94 
123 #define CUDF_EXPECTS(...) \
124  GET_CUDF_EXPECTS_MACRO(__VA_ARGS__, CUDF_EXPECTS_3, CUDF_EXPECTS_2) \
125  (__VA_ARGS__)
126 
128 
129 #define GET_CUDF_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME
130 
131 #define CUDF_EXPECTS_3(_condition, _reason, _exception_type) \
132  do { \
133  static_assert(std::is_base_of_v<std::exception, _exception_type>); \
134  (_condition) ? static_cast<void>(0) \
135  : throw _exception_type /*NOLINT(bugprone-macro-parentheses)*/ \
136  {"CUDF failure at: " __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _reason}; \
137  } while (0)
138 
139 #define CUDF_EXPECTS_2(_condition, _reason) CUDF_EXPECTS_3(_condition, _reason, cudf::logic_error)
140 
142 
162 #define CUDF_FAIL(...) \
163  GET_CUDF_FAIL_MACRO(__VA_ARGS__, CUDF_FAIL_2, CUDF_FAIL_1) \
164  (__VA_ARGS__)
165 
167 
168 #define GET_CUDF_FAIL_MACRO(_1, _2, NAME, ...) NAME
169 
170 #define CUDF_FAIL_2(_what, _exception_type) \
171  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
172  throw _exception_type { "CUDF failure at:" __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _what }
173 
174 #define CUDF_FAIL_1(_what) CUDF_FAIL_2(_what, cudf::logic_error)
175 
177 
178 namespace cudf {
179 namespace detail {
180 // @cond
181 inline void throw_cuda_error(cudaError_t error, const char* file, unsigned int line)
182 {
183  // Calls cudaGetLastError to clear the error status. It is nearly certain that a fatal error
184  // occurred if it still returns the same error after a cleanup.
185  cudaGetLastError();
186  auto const last = cudaFree(0);
187  auto const msg = std::string{"CUDA error encountered at: " + std::string{file} + ":" +
188  std::to_string(line) + ": " + std::to_string(error) + " " +
189  cudaGetErrorName(error) + " " + cudaGetErrorString(error)};
190  // Call cudaDeviceSynchronize to ensure `last` did not result from an asynchronous error.
191  // between two calls.
192  if (error == last && last == cudaDeviceSynchronize()) {
193  throw fatal_cuda_error{"Fatal " + msg, error};
194  } else {
195  throw cuda_error{msg, error};
196  }
197 }
198 // @endcond
199 } // namespace detail
200 } // namespace cudf
201 
209 #define CUDF_CUDA_TRY(call) \
210  do { \
211  cudaError_t const status = (call); \
212  if (cudaSuccess != status) { cudf::detail::throw_cuda_error(status, __FILE__, __LINE__); } \
213  } while (0);
214 
228 #ifndef NDEBUG
229 #define CUDF_CHECK_CUDA(stream) \
230  do { \
231  CUDF_CUDA_TRY(cudaStreamSynchronize(stream)); \
232  CUDF_CUDA_TRY(cudaPeekAtLastError()); \
233  } while (0);
234 #else
235 #define CUDF_CHECK_CUDA(stream) CUDF_CUDA_TRY(cudaPeekAtLastError());
236 #endif
237 
cudf::fatal_cuda_error
Definition: error.hpp:84
cudf::cuda_error
Exception thrown when a CUDA error is encountered.
Definition: error.hpp:60
cudf::logic_error::logic_error
logic_error(char const *const message)
Constructs a logic_error with the error message.
Definition: error.hpp:44
cudf::logic_error::logic_error
logic_error(std::string const &message)
Construct a new logic error object with error message.
Definition: error.hpp:51
cudf::cuda_error::cuda_error
cuda_error(std::string const &message, cudaError_t const &error)
Construct a new cuda error object with error message and code.
Definition: error.hpp:67
cudf
cuDF interfaces
Definition: aggregation.hpp:34
cudf::logic_error
Exception thrown when logical precondition is violated.
Definition: error.hpp:38
cudf::cuda_error::error_code
cudaError_t error_code() const
Returns the CUDA error code associated with the exception.
Definition: error.hpp:78
cudf::cuda_error::_cudaError
cudaError_t _cudaError
CUDA error code.
Definition: error.hpp:81