error.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2025, 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 <cudf/utilities/export.hpp>
20 
21 #include <cuda.h>
22 #include <cuda_runtime_api.h>
23 
24 #include <stdexcept>
25 #include <string>
26 #include <type_traits>
27 
28 namespace CUDF_EXPORT cudf {
41 struct logic_error : std::logic_error {
47  explicit logic_error(char const* const message) : std::logic_error(message) {}
48 
54  explicit logic_error(std::string const& message) : std::logic_error(message) {}
55 
56  // TODO Add an error code member? This would be useful for translating an
57  // exception to an error code in a pure-C API
58 
59  ~logic_error() override
60  {
61  // Needed so that the first instance of the implicit destructor for any TU isn't 'constructed'
62  // from a host+device function marking the implicit version also as host+device
63  }
64 };
69 struct cuda_error : std::runtime_error {
76  explicit cuda_error(std::string const& message, cudaError_t const& error)
77  : std::runtime_error(message), _cudaError(error)
78  {
79  }
80 
86  [[nodiscard]] cudaError_t error_code() const { return _cudaError; }
87 
88  protected:
89  cudaError_t _cudaError;
90 };
91 
93  using cuda_error::cuda_error; // Inherit constructors
94 };
95 
103 struct data_type_error : std::invalid_argument {
109  explicit data_type_error(char const* const message) : std::invalid_argument(message) {}
110 
116  explicit data_type_error(std::string const& message) : std::invalid_argument(message) {}
117 };
120 } // namespace CUDF_EXPORT cudf
121 
122 #define STRINGIFY_DETAIL(x) #x
123 #define CUDF_STRINGIFY(x) STRINGIFY_DETAIL(x)
124 
154 #define CUDF_EXPECTS(...) \
155  GET_CUDF_EXPECTS_MACRO(__VA_ARGS__, CUDF_EXPECTS_3, CUDF_EXPECTS_2) \
156  (__VA_ARGS__)
157 
159 
160 #define GET_CUDF_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME
161 
162 #define CUDF_EXPECTS_3(_condition, _reason, _exception_type) \
163  do { \
164  static_assert(std::is_base_of_v<std::exception, _exception_type>); \
165  (_condition) ? static_cast<void>(0) \
166  : throw _exception_type /*NOLINT(bugprone-macro-parentheses)*/ \
167  {"CUDF failure at: " __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _reason}; \
168  } while (0)
169 
170 #define CUDF_EXPECTS_2(_condition, _reason) CUDF_EXPECTS_3(_condition, _reason, cudf::logic_error)
171 
173 
193 #define CUDF_FAIL(...) \
194  GET_CUDF_FAIL_MACRO(__VA_ARGS__, CUDF_FAIL_2, CUDF_FAIL_1) \
195  (__VA_ARGS__)
196 
198 
199 #define GET_CUDF_FAIL_MACRO(_1, _2, NAME, ...) NAME
200 
201 #define CUDF_FAIL_2(_what, _exception_type) \
202  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
203  throw _exception_type { "CUDF failure at:" __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _what }
204 
205 #define CUDF_FAIL_1(_what) CUDF_FAIL_2(_what, cudf::logic_error)
206 
208 
209 namespace CUDF_EXPORT cudf {
210 namespace detail {
211 // @cond
212 inline void throw_cuda_error(cudaError_t error, char const* file, unsigned int line)
213 {
214  // Calls cudaGetLastError to clear the error status. It is nearly certain that a fatal error
215  // occurred if it still returns the same error after a cleanup.
216  cudaGetLastError();
217  auto const last = cudaFree(nullptr);
218  auto const msg = std::string{"CUDA error encountered at: " + std::string{file} + ":" +
219  std::to_string(line) + ": " + std::to_string(error) + " " +
220  cudaGetErrorName(error) + " " + cudaGetErrorString(error)};
221  // Call cudaDeviceSynchronize to ensure `last` did not result from an asynchronous error.
222  // between two calls.
223  if (error == last && last == cudaDeviceSynchronize()) {
224  throw fatal_cuda_error{"Fatal " + msg, error};
225  } else {
226  throw cuda_error{msg, error};
227  }
228 }
229 // @endcond
230 } // namespace detail
231 } // namespace CUDF_EXPORT cudf
232 
240 #define CUDF_CUDA_TRY(call) \
241  do { \
242  cudaError_t const status = (call); \
243  if (cudaSuccess != status) { cudf::detail::throw_cuda_error(status, __FILE__, __LINE__); } \
244  } while (0);
245 
259 #ifndef NDEBUG
260 #define CUDF_CHECK_CUDA(stream) \
261  do { \
262  CUDF_CUDA_TRY(cudaStreamSynchronize(stream)); \
263  CUDF_CUDA_TRY(cudaPeekAtLastError()); \
264  } while (0);
265 #else
266 #define CUDF_CHECK_CUDA(stream) CUDF_CUDA_TRY(cudaPeekAtLastError());
267 #endif
cuDF interfaces
Definition: host_udf.hpp:37
Exception thrown when a CUDA error is encountered.
Definition: error.hpp:69
cuda_error(std::string const &message, cudaError_t const &error)
Construct a new cuda error object with error message and code.
Definition: error.hpp:76
cudaError_t _cudaError
CUDA error code.
Definition: error.hpp:89
cudaError_t error_code() const
Returns the CUDA error code associated with the exception.
Definition: error.hpp:86
Exception thrown when an operation is attempted on an unsupported dtype.
Definition: error.hpp:103
data_type_error(std::string const &message)
Construct a new data_type_error object with error message.
Definition: error.hpp:116
data_type_error(char const *const message)
Constructs a data_type_error with the error message.
Definition: error.hpp:109
Exception thrown when logical precondition is violated.
Definition: error.hpp:41
logic_error(char const *const message)
Constructs a logic_error with the error message.
Definition: error.hpp:47
logic_error(std::string const &message)
Construct a new logic error object with error message.
Definition: error.hpp:54