FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
DeviceUtils.h
1
10#ifndef FZ_ANS_DIETGPU_UTILS_DEVICEUTILS_H
11#define FZ_ANS_DIETGPU_UTILS_DEVICEUTILS_H
12
13#pragma once
14#include <iostream>
15#include <cuda.h>
16#include <cuda_runtime.h>
17#include <string>
18#include <vector>
19#include <mutex>
20#include <unordered_map>
21
22#define CUDA_VERIFY(X) \
23 do { \
24 auto err__ = (X); \
25 if (err__ != cudaSuccess) { \
26 std::cout << "CUDA error " << fz::ans::errorToName(err__) \
27 << " " << fz::ans::errorToString(err__) \
28 << std::endl; \
29 } \
30 } while (0)
31
32#ifdef GPU_SYNC_ERROR
33#define CUDA_TEST_ERROR() \
34 do { \
35 CUDA_VERIFY(cudaDeviceSynchronize()); \
36 } while (0)
37#else
38#define CUDA_TEST_ERROR() \
39 do { \
40 CUDA_VERIFY(cudaGetLastError()); \
41 } while (0)
42#endif
43
44namespace fz { namespace ans {
45
46constexpr int kWarpSize = 32;
47
48inline std::string errorToString(cudaError_t err) {
49 return std::string(cudaGetErrorString(err));
50}
51
52inline std::string errorToName(cudaError_t err) {
53 return std::string(cudaGetErrorName(err));
54}
55
56inline int getCurrentDevice() {
57 int dev = -1;
58 CUDA_VERIFY(cudaGetDevice(&dev));
59 return dev;
60}
61
62inline void setCurrentDevice(int device) {
63 CUDA_VERIFY(cudaSetDevice(device));
64}
65
66inline int getNumDevices() {
67 int numDev = -1;
68 cudaError_t err = cudaGetDeviceCount(&numDev);
69 if (cudaErrorNoDevice == err) {
70 numDev = 0;
71 } else {
72 CUDA_VERIFY(err);
73 }
74 return numDev;
75}
76
77inline void synchronizeAllDevices() {
78 for (int i = 0; i < getNumDevices(); ++i) {
79 CUDA_VERIFY(cudaSetDevice(i));
80 CUDA_VERIFY(cudaDeviceSynchronize());
81 }
82}
83
84inline const cudaDeviceProp& getDeviceProperties(int device) {
85 static std::mutex mutex;
86 static std::unordered_map<int, cudaDeviceProp> properties;
87
88 std::lock_guard<std::mutex> guard(mutex);
89
90 auto it = properties.find(device);
91 if (it == properties.end()) {
92 cudaDeviceProp prop;
93 CUDA_VERIFY(cudaGetDeviceProperties(&prop, device));
94 properties[device] = prop;
95 it = properties.find(device);
96 }
97 return it->second;
98}
99
100inline const cudaDeviceProp& getCurrentDeviceProperties() {
101 return getDeviceProperties(getCurrentDevice());
102}
103
104inline int getMaxThreads(int device) {
105 return getDeviceProperties(device).maxThreadsPerBlock;
106}
107
108inline int getMaxThreadsCurrentDevice() {
109 return getMaxThreads(getCurrentDevice());
110}
111
112inline size_t getMaxSharedMemPerBlock(int device) {
113 return getDeviceProperties(device).sharedMemPerBlock;
114}
115
116inline size_t getMaxSharedMemPerBlockCurrentDevice() {
117 return getMaxSharedMemPerBlock(getCurrentDevice());
118}
119
120inline int getDeviceForAddress(const void* p) {
121 if (!p) {
122 return -1;
123 }
124 cudaPointerAttributes att;
125 cudaError_t err = cudaPointerGetAttributes(&att, p);
126 if (err == cudaErrorInvalidValue) {
127 err = cudaGetLastError();
128 return -1;
129 }
130#if CUDA_VERSION < 10000
131 if (att.memoryType == cudaMemoryTypeHost) {
132 return -1;
133 } else {
134 return att.device;
135 }
136#else
137 if (att.type == cudaMemoryTypeDevice) {
138 return att.device;
139 } else {
140 return -1;
141 }
142#endif
143}
144
145inline bool getFullUnifiedMemSupport(int device) {
146 const auto& prop = getDeviceProperties(device);
147 return (prop.major >= 6);
148}
149
150inline bool getFullUnifiedMemSupportCurrentDevice() {
151 return getFullUnifiedMemSupport(getCurrentDevice());
152}
153
154class DeviceScope {
155 public:
156 explicit DeviceScope(int device) {
157 if (device >= 0) {
158 int curDevice = getCurrentDevice();
159 if (curDevice != device) {
160 prevDevice_ = curDevice;
161 setCurrentDevice(device);
162 return;
163 }
164 }
165 prevDevice_ = -1;
166 }
167 ~DeviceScope() {
168 if (prevDevice_ != -1) {
169 setCurrentDevice(prevDevice_);
170 }
171 }
172 private:
173 int prevDevice_;
174};
175
176class CudaEvent {
177 public:
178 explicit CudaEvent(cudaStream_t stream, bool timer = false) : event_(nullptr) {
179 CUDA_VERIFY(cudaEventCreateWithFlags(
180 &event_, timer ? cudaEventDefault : cudaEventDisableTiming));
181 CUDA_VERIFY(cudaEventRecord(event_, stream));
182 }
183 CudaEvent(const CudaEvent&) = delete;
184 CudaEvent(CudaEvent&& event) noexcept : event_(event.event_) {
185 event.event_ = nullptr;
186 }
187 ~CudaEvent() {
188 if (event_) CUDA_VERIFY(cudaEventDestroy(event_));
189 }
190 CudaEvent& operator=(CudaEvent&& event) noexcept {
191 event_ = event.event_;
192 event.event_ = nullptr;
193 return *this;
194 }
195 CudaEvent& operator=(CudaEvent&) = delete;
196 inline cudaEvent_t get() { return event_; }
197 void streamWaitOnEvent(cudaStream_t stream) {
198 CUDA_VERIFY(cudaStreamWaitEvent(stream, event_, 0));
199 }
200 void cpuWaitOnEvent() { CUDA_VERIFY(cudaEventSynchronize(event_)); }
201 float timeFrom(CudaEvent& from) {
202 cpuWaitOnEvent();
203 float ms = 0;
204 CUDA_VERIFY(cudaEventElapsedTime(&ms, from.event_, event_));
205 return ms;
206 }
207 private:
208 cudaEvent_t event_;
209};
210
211class CudaStream {
212 public:
213 explicit CudaStream(int flags = cudaStreamDefault) : stream_(nullptr) {
214 CUDA_VERIFY(cudaStreamCreateWithFlags(&stream_, flags));
215 }
216 CudaStream(const CudaStream&) = delete;
217 CudaStream(CudaStream&& stream) noexcept : stream_(stream.stream_) {
218 stream.stream_ = nullptr;
219 }
220 ~CudaStream() {
221 if (stream_) CUDA_VERIFY(cudaStreamDestroy(stream_));
222 }
223 CudaStream& operator=(CudaStream&& stream) noexcept {
224 stream_ = stream.stream_;
225 stream.stream_ = nullptr;
226 return *this;
227 }
228 CudaStream& operator=(CudaStream&) = delete;
229 inline cudaStream_t get() { return stream_; }
230 operator cudaStream_t() { return stream_; }
231 static CudaStream make() { return CudaStream(); }
232 static CudaStream makeNonBlocking() { return CudaStream(cudaStreamNonBlocking); }
233 private:
234 cudaStream_t stream_;
235};
236
237}} // namespace fz::ans
238
239#endif // FZ_ANS_DIETGPU_UTILS_DEVICEUTILS_H
Definition dag.h:24