error.hpp
1 /*
2  * Copyright (c) 2021-2023, 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 #pragma once
17 
18 #include <exception>
19 #include <system_error>
20 
21 #include <kvikio/shim/cuda.hpp>
22 #include <kvikio/shim/cufile_h_wrapper.hpp>
23 
24 namespace kvikio {
25 
26 struct CUfileException : public std::runtime_error {
27  using std::runtime_error::runtime_error;
28 };
29 
30 #ifndef CUDA_DRIVER_TRY
31 #define CUDA_DRIVER_TRY(...) \
32  GET_CUDA_DRIVER_TRY_MACRO(__VA_ARGS__, CUDA_DRIVER_TRY_2, CUDA_DRIVER_TRY_1) \
33  (__VA_ARGS__)
34 #define GET_CUDA_DRIVER_TRY_MACRO(_1, _2, NAME, ...) NAME
35 #define CUDA_DRIVER_TRY_2(_call, _exception_type) \
36  do { \
37  CUresult const error = (_call); \
38  if (error == CUDA_ERROR_STUB_LIBRARY) { \
39  throw(_exception_type){std::string{"CUDA error at: "} + __FILE__ + ":" + \
40  KVIKIO_STRINGIFY(__LINE__) + \
41  ": CUDA_ERROR_STUB_LIBRARY(" \
42  "The CUDA driver loaded is a stub library)"}; \
43  } \
44  if (error != CUDA_SUCCESS) { \
45  const char* err_name = nullptr; \
46  const char* err_str = nullptr; \
47  CUresult err_name_status = cudaAPI::instance().GetErrorName(error, &err_name); \
48  CUresult err_str_status = cudaAPI::instance().GetErrorString(error, &err_str); \
49  if (err_name_status == CUDA_ERROR_INVALID_VALUE) { err_name = "unknown"; } \
50  if (err_str_status == CUDA_ERROR_INVALID_VALUE) { err_str = "unknown"; } \
51  throw(_exception_type){std::string{"CUDA error at: "} + __FILE__ + ":" + \
52  KVIKIO_STRINGIFY(__LINE__) + ": " + std::string(err_name) + "(" + \
53  std::string(err_str) + ")"}; \
54  } \
55  } while (0)
56 #define CUDA_DRIVER_TRY_1(_call) CUDA_DRIVER_TRY_2(_call, kvikio::CUfileException)
57 #endif
58 
59 #ifdef KVIKIO_CUFILE_FOUND
60 #ifndef CUFILE_TRY
61 #define CUFILE_TRY(...) \
62  GET_CUFILE_TRY_MACRO(__VA_ARGS__, CUFILE_TRY_2, CUFILE_TRY_1) \
63  (__VA_ARGS__)
64 #define GET_CUFILE_TRY_MACRO(_1, _2, NAME, ...) NAME
65 #define CUFILE_TRY_2(_call, _exception_type) \
66  do { \
67  CUfileError_t const error = (_call); \
68  if (error.err != CU_FILE_SUCCESS) { \
69  if (error.err == CU_FILE_CUDA_DRIVER_ERROR) { \
70  CUresult const cuda_error = error.cu_err; \
71  CUDA_DRIVER_TRY(cuda_error); \
72  } \
73  throw(_exception_type){std::string{"cuFile error at: "} + __FILE__ + ":" + \
74  KVIKIO_STRINGIFY(__LINE__) + ": " + \
75  cufileop_status_error(error.err)}; \
76  } \
77  } while (0)
78 #define CUFILE_TRY_1(_call) CUFILE_TRY_2(_call, kvikio::CUfileException)
79 #endif
80 #endif
81 
82 #ifndef CUFILE_CHECK_STREAM_IO
83 #define CUFILE_CHECK_STREAM_IO(...) \
84  GET_CUFILE_CHECK_STREAM_IO_MACRO( \
85  __VA_ARGS__, CUFILE_CHECK_STREAM_IO_2, CUFILE_CHECK_STREAM_IO_1) \
86  (__VA_ARGS__)
87 #define GET_CUFILE_CHECK_STREAM_IO_MACRO(_1, _2, NAME, ...) NAME
88 #ifdef KVIKIO_CUFILE_FOUND
89 #define CUFILE_CHECK_STREAM_IO_2(_nbytes_done, _exception_type) \
90  do { \
91  auto const _nbytes = *(_nbytes_done); \
92  if (_nbytes < 0) { \
93  throw(_exception_type){std::string{"cuFile error at: "} + __FILE__ + ":" + \
94  KVIKIO_STRINGIFY(__LINE__) + ": " + std::to_string(_nbytes)}; \
95  } \
96  } while (0)
97 #else
98 // if cufile isn't available, we don't do anything in the body
99 #define CUFILE_CHECK_STREAM_IO_2(_nbytes_done, _exception_type) \
100  do { \
101  } while (0)
102 #endif
103 #define CUFILE_CHECK_STREAM_IO_1(_call) CUFILE_CHECK_STREAM_IO_2(_call, kvikio::CUfileException)
104 #endif
105 
106 } // namespace kvikio