error.hpp
转到此文件的文档。
1 /*
2  * 版权所有 (c) 2019-2024, NVIDIA CORPORATION.
3  *
4  * 根据 Apache 许可,版本 2.0 (下称“许可”) 获得许可;除非遵守许可,否则不得使用此文件。
5  * 您可以获取许可的副本,地址是
6  *
7  * https://apache.ac.cn/licenses/LICENSE-2.0
8  *
9  * 除非适用法律要求或书面同意,根据许可分发的软件是按“原样”分发的,没有任何明示或暗示的保证或条件。
10  * 请参阅许可了解特定语言的管理权限和限制。
11  * limitations under the License.
12  * See the License for the specific language governing permissions and
13  * restrictions under the License.
14  */
15  * limitations under the License.
16 
17 #pragma once
18 
19 #include <cudf/detail/utilities/stacktrace.hpp>
20 #include <cudf/utilities/export.hpp>
21 
22 #include <cuda.h>
23 #include <cuda_runtime_api.h>
24 
25 #include <stdexcept>
26 #include <string>
27 #include <type_traits>
28 
29 namespace CUDF_EXPORT cudf {
41  // 排除当前栈帧,因为它即为此构造函数。
42  : _stacktrace{cudf::detail::get_stacktrace(cudf::detail::capture_last_stackframe::NO)}
43  {
44  }
45 
46  public
52  [[nodiscard]] char const* stacktrace() const { return _stacktrace.c_str(); }
53 
54  protected
55  std::string const _stacktrace;
56 };
57 
64 struct logic_error : public std::logic_error, public stacktrace_recorder {
70  logic_error(char const* const message) : std::logic_error(message) {}
71 
77  logic_error(std::string const& message) : std::logic_error(message) {}
78 
79  // TODO 添加错误码成员?这对于在纯 C API 中将异常转换为错误码很有用
80  // exception to an error code in a pure-C API
81 
82  ~logic_error() override
83  {
84  // 需要这样做,以使任何翻译单元 (TU) 的隐式析构函数的第一个实例不会从主机+设备函数“构造”出来,从而也标记隐式版本为主机+设备
85  // from a host+device function marking the implicit version also as host+device
86  }
87 };
92 struct cuda_error : public std::runtime_error, public stacktrace_recorder {
99  cuda_error(std::string const& message, cudaError_t const& error)
100  : std::runtime_error(message), _cudaError(error)
101  {
102  }
103 
104  public
110  [[nodiscard]] cudaError_t error_code() const { return _cudaError; }
111 
112  protected
113  cudaError_t _cudaError;
114 };
115 
116 struct fatal_cuda_error : public cuda_error {
117  using cuda_error::cuda_error; // 继承构造函数
118 };
119 
127 struct data_type_error : public std::invalid_argument, public stacktrace_recorder {
133  data_type_error(char const* const message) : std::invalid_argument(message) {}
134 
140  data_type_error(std::string const& message) : std::invalid_argument(message) {}
141 };
144 } // namespace CUDF_EXPORT cudf
145 
146 #define STRINGIFY_DETAIL(x) #x
147 #define CUDF_STRINGIFY(x) STRINGIFY_DETAIL(x)
148 
178 #define CUDF_EXPECTS(...) \
179  GET_CUDF_EXPECTS_MACRO(__VA_ARGS__, CUDF_EXPECTS_3, CUDF_EXPECTS_2) \
180  (__VA_ARGS__)
181 
183 
184 #define GET_CUDF_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME
185 
186 #define CUDF_EXPECTS_3(_condition, _reason, _exception_type) \
187  do { \
188  static_assert(std::is_base_of_v<std::exception, _exception_type>); \
189  (_condition) ? static_cast<void>(0) \
190  : throw _exception_type /*NOLINT(bugprone-macro-parentheses)*/ \
191  {"CUDF failure at: " __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _reason}; \
192  } while (0)
193 
194 #define CUDF_EXPECTS_2(_condition, _reason) CUDF_EXPECTS_3(_condition, _reason, cudf::logic_error)
195 
197 
217 #define CUDF_FAIL(...) \
218  GET_CUDF_FAIL_MACRO(__VA_ARGS__, CUDF_FAIL_2, CUDF_FAIL_1) \
219  (__VA_ARGS__)
220 
222 
223 #define GET_CUDF_FAIL_MACRO(_1, _2, NAME, ...) NAME
224 
225 #define CUDF_FAIL_2(_what, _exception_type) \
226  /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
227  throw _exception_type { "CUDF failure at:" __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _what }
228 
229 #define CUDF_FAIL_1(_what) CUDF_FAIL_2(_what, cudf::logic_error)
230 
232 
233 namespace CUDF_EXPORT cudf {
234 namespace detail {
235 // @cond
236 inline void throw_cuda_error(cudaError_t error, char const* file, unsigned int line)
237 {
238  // 调用 cudaGetLastError 以清除错误状态。如果在清理后仍然返回相同的错误,几乎可以确定发生了致命错误。
239  // occurred if it still returns the same error after a cleanup.
240  cudaGetLastError();
241  auto const last = cudaFree(nullptr);
242  auto const msg = std::string{"CUDA error encountered at: " + std::string{file} + ":" +
243  std::to_string(line) + ": " + std::to_string(error) + " " +
244  cudaGetErrorName(error) + " " + cudaGetErrorString(error)};
245  // 调用 cudaDeviceSynchronize 以确保 `last` 不是由两次调用之间的异步错误引起的。
246  // between two calls.
247  if (error == last && last == cudaDeviceSynchronize()) {
248  throw fatal_cuda_error{"Fatal " + msg, error};
249  } else {
250  throw cuda_error{msg, error};
251  }
252 }
253 // @endcond
254 } // namespace detail
255 } // namespace CUDF_EXPORT cudf
256 
264 #define CUDF_CUDA_TRY(call) \
265  do { \
266  cudaError_t const status = (call); \
267  if (cudaSuccess != status) { cudf::detail::throw_cuda_error(status, __FILE__, __LINE__); } \
268  } while (0);
269 
283 #ifndef NDEBUG
284 #define CUDF_CHECK_CUDA(stream) \
285  do { \
286  CUDF_CUDA_TRY(cudaStreamSynchronize(stream)); \
287  CUDF_CUDA_TRY(cudaPeekAtLastError()); \
288  } while (0);
289 #else
290 #define CUDF_CHECK_CUDA(stream) CUDF_CUDA_TRY(cudaPeekAtLastError());
291 #endif
cuDF 接口
定义: host_udf.hpp:37
遇到 CUDA 错误时抛出的异常。
定义: error.hpp:92
cuda_error(std::string const &message, cudaError_t const &error)
使用错误消息和代码构造一个新的 CUDA 错误对象。
定义: error.hpp:99
cudaError_t _cudaError
CUDA 错误码。
定义: error.hpp:113
cudaError_t error_code() const
返回与异常关联的 CUDA 错误码。
定义: error.hpp:110
当尝试在不受支持的 dtype 上进行操作时抛出的异常。
定义: error.hpp:127
data_type_error(std::string const &message)
使用错误消息构造一个新的 data_type_error 对象。
定义: error.hpp:140
data_type_error(char const *const message)
使用错误消息构造一个 data_type_error。
定义: error.hpp:133
违反逻辑前提条件时抛出的异常。
定义: error.hpp:64
logic_error(char const *const message)
使用错误消息构造一个 logic_error。
定义: error.hpp:70
logic_error(std::string const &message)
使用错误消息构造一个新的逻辑错误对象。
定义: error.hpp:77
用于在构造时存储当前栈跟踪的结构体。
定义: error.hpp:39
std::string const _stacktrace
作为字符串存储的完整栈跟踪。
定义: error.hpp:55
const char* stacktrace() const
获取对象构造期间捕获的存储栈跟踪。
定义: error.hpp:52