libkvikio  23.12.00
cufile.hpp
1 /*
2  * Copyright (c) 2022-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 <stdexcept>
19 
20 #include <iostream>
21 #include <kvikio/shim/cufile_h_wrapper.hpp>
22 #include <kvikio/shim/utils.hpp>
23 
24 namespace kvikio {
25 
26 #ifdef KVIKIO_CUFILE_FOUND
27 
35 class cuFileAPI {
36  public:
37  decltype(cuFileHandleRegister)* HandleRegister{nullptr};
38  decltype(cuFileHandleDeregister)* HandleDeregister{nullptr};
39  decltype(cuFileRead)* Read{nullptr};
40  decltype(cuFileWrite)* Write{nullptr};
41  decltype(cuFileBufRegister)* BufRegister{nullptr};
42  decltype(cuFileBufDeregister)* BufDeregister{nullptr};
43  decltype(cuFileDriverOpen)* DriverOpen{nullptr};
44  decltype(cuFileDriverClose)* DriverClose{nullptr};
45  decltype(cuFileDriverGetProperties)* DriverGetProperties{nullptr};
46  decltype(cuFileDriverSetPollMode)* DriverSetPollMode{nullptr};
47  decltype(cuFileDriverSetMaxCacheSize)* DriverSetMaxCacheSize{nullptr};
48  decltype(cuFileDriverSetMaxPinnedMemSize)* DriverSetMaxPinnedMemSize{nullptr};
49 
50 #ifdef KVIKIO_CUFILE_BATCH_API_FOUND
51  decltype(cuFileBatchIOSetUp)* BatchIOSetUp{nullptr};
52  decltype(cuFileBatchIOSubmit)* BatchIOSubmit{nullptr};
53  decltype(cuFileBatchIOGetStatus)* BatchIOGetStatus{nullptr};
54  decltype(cuFileBatchIOCancel)* BatchIOCancel{nullptr};
55  decltype(cuFileBatchIODestroy)* BatchIODestroy{nullptr};
56 #endif
57 
58 #ifdef KVIKIO_CUFILE_STREAM_API_FOUND
59  decltype(cuFileReadAsync)* ReadAsync{nullptr};
60  decltype(cuFileWriteAsync)* WriteAsync{nullptr};
61  decltype(cuFileStreamRegister)* StreamRegister{nullptr};
62  decltype(cuFileStreamDeregister)* StreamDeregister{nullptr};
63 #endif
64  bool stream_available = false;
65 
66  private:
67  cuFileAPI()
68  {
69  // CUDA versions before CUDA 11.7.1 did not ship libcufile.so.0, so this is
70  // a workaround that adds support for all prior versions of libcufile.
71  void* lib = load_library({"libcufile.so.0",
72  "libcufile.so.1.3.0" /* 11.7.0 */,
73  "libcufile.so.1.2.1" /* 11.6.2, 11.6.1 */,
74  "libcufile.so.1.2.0" /* 11.6.0 */,
75  "libcufile.so.1.1.1" /* 11.5.1 */,
76  "libcufile.so.1.1.0" /* 11.5.0 */,
77  "libcufile.so.1.0.2" /* 11.4.4, 11.4.3, 11.4.2 */,
78  "libcufile.so.1.0.1" /* 11.4.1 */,
79  "libcufile.so.1.0.0" /* 11.4.0 */});
80  get_symbol(HandleRegister, lib, KVIKIO_STRINGIFY(cuFileHandleRegister));
81  get_symbol(HandleDeregister, lib, KVIKIO_STRINGIFY(cuFileHandleDeregister));
82  get_symbol(Read, lib, KVIKIO_STRINGIFY(cuFileRead));
83  get_symbol(Write, lib, KVIKIO_STRINGIFY(cuFileWrite));
84  get_symbol(BufRegister, lib, KVIKIO_STRINGIFY(cuFileBufRegister));
85  get_symbol(BufDeregister, lib, KVIKIO_STRINGIFY(cuFileBufDeregister));
86  get_symbol(DriverOpen, lib, KVIKIO_STRINGIFY(cuFileDriverOpen));
87  get_symbol(DriverClose, lib, KVIKIO_STRINGIFY(cuFileDriverClose));
88  get_symbol(DriverGetProperties, lib, KVIKIO_STRINGIFY(cuFileDriverGetProperties));
89  get_symbol(DriverSetPollMode, lib, KVIKIO_STRINGIFY(cuFileDriverSetPollMode));
90  get_symbol(DriverSetMaxCacheSize, lib, KVIKIO_STRINGIFY(cuFileDriverSetMaxCacheSize));
91  get_symbol(DriverSetMaxPinnedMemSize, lib, KVIKIO_STRINGIFY(cuFileDriverSetMaxPinnedMemSize));
92 
93 #ifdef KVIKIO_CUFILE_BATCH_API_FOUND
94  get_symbol(BatchIOSetUp, lib, KVIKIO_STRINGIFY(cuFileBatchIOSetUp));
95  get_symbol(BatchIOSubmit, lib, KVIKIO_STRINGIFY(cuFileBatchIOSubmit));
96  get_symbol(BatchIOGetStatus, lib, KVIKIO_STRINGIFY(cuFileBatchIOGetStatus));
97  get_symbol(BatchIOCancel, lib, KVIKIO_STRINGIFY(cuFileBatchIOCancel));
98  get_symbol(BatchIODestroy, lib, KVIKIO_STRINGIFY(cuFileBatchIODestroy));
99 #endif
100 
101 #ifdef KVIKIO_CUFILE_STREAM_API_FOUND
102  get_symbol(ReadAsync, lib, KVIKIO_STRINGIFY(cuFileReadAsync));
103  get_symbol(WriteAsync, lib, KVIKIO_STRINGIFY(cuFileWriteAsync));
104  get_symbol(StreamRegister, lib, KVIKIO_STRINGIFY(cuFileStreamRegister));
105  get_symbol(StreamDeregister, lib, KVIKIO_STRINGIFY(cuFileStreamDeregister));
106  try {
107  void* s{};
108  get_symbol(s, lib, "cuFileReadAsync");
109  stream_available = true;
110  } catch (const std::runtime_error&) {
111  }
112 #endif
113 
114  // cuFile is supposed to open and close the driver automatically but because of a bug in
115  // CUDA 11.8, it sometimes segfault. See <https://github.com/rapidsai/kvikio/issues/159>.
116  CUfileError_t const error = DriverOpen();
117  if (error.err != CU_FILE_SUCCESS) {
118  throw std::runtime_error(std::string{"cuFile error at: "} + __FILE__ + ":" +
119  KVIKIO_STRINGIFY(__LINE__) + ": " +
120  cufileop_status_error(error.err));
121  }
122  }
123  ~cuFileAPI()
124  {
125  CUfileError_t const error = DriverClose();
126  if (error.err != CU_FILE_SUCCESS) {
127  std::cerr << "Unable to close GDS file driver: " << cufileop_status_error(error.err)
128  << std::endl;
129  }
130  }
131 
132  public:
133  cuFileAPI(cuFileAPI const&) = delete;
134  void operator=(cuFileAPI const&) = delete;
135 
136  static cuFileAPI& instance()
137  {
138  static cuFileAPI _instance;
139  return _instance;
140  }
141 };
142 
143 #endif
144 
152 #ifdef KVIKIO_CUFILE_FOUND
153 inline bool is_cufile_library_available()
154 {
155  try {
156  cuFileAPI::instance();
157  } catch (const std::runtime_error&) {
158  return false;
159  }
160  return true;
161 }
162 #else
163 constexpr bool is_cufile_library_available() { return false; }
164 #endif
165 
174 inline bool is_cufile_available()
175 {
176  return is_cufile_library_available() && run_udev_readable() && !is_running_in_wsl();
177 }
178 
188 #if defined(KVIKIO_CUFILE_STREAM_API_FOUND) && defined(KVIKIO_CUFILE_STREAM_API_FOUND)
189 inline bool is_batch_and_stream_available()
190 {
191  try {
192  return is_cufile_available() && cuFileAPI::instance().stream_available;
193  } catch (const std::runtime_error&) {
194  return false;
195  }
196 }
197 #else
198 constexpr bool is_batch_and_stream_available() { return false; }
199 #endif
200 
201 } // namespace kvikio