-
Notifications
You must be signed in to change notification settings - Fork 849
Expand file tree
/
Copy pathmemory.hpp
More file actions
302 lines (247 loc) · 11.7 KB
/
Copy pathmemory.hpp
File metadata and controls
302 lines (247 loc) · 11.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
//===--------- memory.hpp - Level Zero Adapter ---------------------------===//
//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM
// Exceptions. See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#pragma once
#include <cassert>
#include <unified-runtime/ur_api.h>
#include "../device.hpp"
#include "../helpers/memory_helpers.hpp"
#include "../image_common.hpp"
#include "command_list_manager.hpp"
#include "common.hpp"
#include "common/ur_ref_count.hpp"
#include <umf/ipc.h>
using usm_unique_ptr_t = std::unique_ptr<void, std::function<void(void *)>>;
struct ur_mem_buffer_t : ur_object {
enum class device_access_mode_t { read_write, read_only, write_only };
ur_mem_buffer_t(ur_context_handle_t hContext, size_t size,
device_access_mode_t accessMode);
virtual ~ur_mem_buffer_t() = default;
virtual ur_shared_mutex &getMutex();
// Following functions should always be called under the lock.
// Returns pointer to the device memory. If device handle is NULL,
// the buffer is allocated on the first device in the context.
virtual void *getDevicePtr(ur_device_handle_t, device_access_mode_t,
size_t offset, size_t size,
ze_command_list_handle_t cmdList,
wait_list_view &waitListView) = 0;
virtual void *mapHostPtr(ur_map_flags_t, size_t offset, size_t size,
ze_command_list_handle_t cmdList,
wait_list_view &waitListView) = 0;
virtual void unmapHostPtr(void *pMappedPtr, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) = 0;
device_access_mode_t getDeviceAccessMode() const { return accessMode; }
ur_context_handle_t getContext() const { return hContext; }
size_t getSize() const { return size; }
static ur_mem_buffer_t::device_access_mode_t
getDeviceAccessMode(ur_mem_flags_t memFlag) {
if (memFlag & UR_MEM_FLAG_READ_WRITE) {
return ur_mem_buffer_t::device_access_mode_t::read_write;
} else if (memFlag & UR_MEM_FLAG_READ_ONLY) {
return ur_mem_buffer_t::device_access_mode_t::read_only;
} else if (memFlag & UR_MEM_FLAG_WRITE_ONLY) {
return ur_mem_buffer_t::device_access_mode_t::write_only;
} else {
return ur_mem_buffer_t::device_access_mode_t::read_write;
}
}
protected:
const ur_context_handle_t hContext;
const size_t size;
const device_access_mode_t accessMode;
};
// non-owning buffer wrapper around USM pointer
struct ur_usm_handle_t : ur_mem_buffer_t {
ur_usm_handle_t(ur_context_handle_t hContext, size_t size, const void *ptr);
void *getDevicePtr(ur_device_handle_t, device_access_mode_t, size_t offset,
size_t size, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void *mapHostPtr(ur_map_flags_t, size_t offset, size_t size,
ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void unmapHostPtr(void *pMappedPtr, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
private:
void *ptr;
};
struct host_allocation_desc_t {
host_allocation_desc_t(usm_unique_ptr_t ptr, size_t size, size_t offset,
ur_map_flags_t flags)
: ptr(std::move(ptr)), size(size), offset(offset), flags(flags) {}
usm_unique_ptr_t ptr;
size_t size;
size_t offset;
ur_map_flags_t flags;
};
// Manages memory buffer for integrated GPU.
// For integrated devices the buffer has been allocated in host memory
// and can be accessed by the device without copying.
struct ur_integrated_buffer_handle_t : ur_mem_buffer_t {
ur_integrated_buffer_handle_t(ur_context_handle_t hContext, void *hostPtr,
size_t size, device_access_mode_t accessMode);
ur_integrated_buffer_handle_t(ur_context_handle_t hContext, void *hostPtr,
size_t size, device_access_mode_t accessMode,
bool ownHostPtr);
~ur_integrated_buffer_handle_t();
void *getDevicePtr(ur_device_handle_t, device_access_mode_t, size_t offset,
size_t size, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void *mapHostPtr(ur_map_flags_t, size_t offset, size_t size,
ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void unmapHostPtr(void *pMappedPtr, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
// Perform final copy-back to original host pointer if needed
void copyBackToHostIfNeeded();
private:
usm_unique_ptr_t ptr;
void *writeBackPtr = nullptr;
std::vector<host_allocation_desc_t> mappedRegions;
};
// Manages memory buffer for discrete GPU.
// Memory is allocated on the device and migrated/copies if necessary.
struct ur_discrete_buffer_handle_t : ur_mem_buffer_t {
// If hostPtr is not null, the buffer is allocated immediately on the
// first device in the context. Otherwise, the buffer is allocated on
// firt getDevicePtr call.
ur_discrete_buffer_handle_t(ur_context_handle_t hContext, void *hostPtr,
size_t size, device_access_mode_t accessMode);
~ur_discrete_buffer_handle_t();
// Create buffer on top of existing device memory.
ur_discrete_buffer_handle_t(ur_context_handle_t hContext,
ur_device_handle_t hDevice, void *devicePtr,
size_t size, device_access_mode_t accessMode,
void *writeBackMemory, bool ownDevicePtr);
void *getDevicePtr(ur_device_handle_t, device_access_mode_t, size_t offset,
size_t size, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void *mapHostPtr(ur_map_flags_t, size_t offset, size_t size,
ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void unmapHostPtr(void *pMappedPtr, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
private:
void *getCurrentAllocation();
// Vector of per-device allocations indexed by device->Id
std::vector<usm_unique_ptr_t> deviceAllocations;
// Specifies device on which the latest allocation resides.
// If null, there is no allocation.
ur_device_handle_t activeAllocationDevice = nullptr;
// If not null, copy the buffer content back to this memory on release.
void *writeBackPtr = nullptr;
// If not null, mapHostPtr should map memory to this ptr
usm_unique_ptr_t mapToPtr;
std::vector<host_allocation_desc_t> hostAllocations;
void *getActiveDeviceAlloc(size_t offset = 0);
void *allocateOnDevice(ur_device_handle_t hDevice, size_t size);
// Ensures a device allocation exists for hDevice and returns its pointer.
// Unlike allocateOnDevice, does NOT update activeAllocationDevice, so it
// is safe to call before the data migration is complete.
void *ensureDeviceAlloc(ur_device_handle_t hDevice, size_t size);
ur_result_t migrateBufferTo(ur_device_handle_t hDevice, void *src,
size_t size);
};
struct ur_shared_buffer_handle_t : ur_mem_buffer_t {
ur_shared_buffer_handle_t(ur_context_handle_t hContext, void *devicePtr,
size_t size, device_access_mode_t accessMode,
bool ownDevicePtr);
void *getDevicePtr(ur_device_handle_t, device_access_mode_t, size_t offset,
size_t size, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void *mapHostPtr(ur_map_flags_t, size_t offset, size_t size,
ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void unmapHostPtr(void *pMappedPtr, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
private:
usm_unique_ptr_t ptr;
};
struct ur_mem_sub_buffer_t : ur_mem_buffer_t {
ur_mem_sub_buffer_t(ur_mem_handle_t hParent, size_t offset, size_t size,
device_access_mode_t accessMode);
~ur_mem_sub_buffer_t();
void *getDevicePtr(ur_device_handle_t, device_access_mode_t, size_t offset,
size_t size, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void *mapHostPtr(ur_map_flags_t, size_t offset, size_t size,
ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
void unmapHostPtr(void *pMappedPtr, ze_command_list_handle_t cmdList,
wait_list_view &waitListView) override;
ur_shared_mutex &getMutex() override;
private:
ur_mem_handle_t hParent;
size_t offset;
};
struct ur_mem_image_t : ur_object {
ur_mem_image_t(ur_context_handle_t hContext, ur_mem_flags_t flags,
const ur_image_format_t *pImageFormat,
const ur_image_desc_t *pImageDesc, void *pHost);
ur_mem_image_t(ur_context_handle_t, const ur_image_format_t *pImageFormat,
const ur_image_desc_t *pImageDesc, ze_image_handle_t zeImage,
bool ownZeImage);
ze_image_handle_t getZeImage() const { return zeImage.get(); }
std::pair<ze_image_handle_t, ze_image_region_t>
getRWRegion(ur_rect_offset_t &origin, ur_rect_region_t ®ion,
size_t rowPitch, size_t slicePitch);
struct copy_desc_t {
std::pair<ze_image_handle_t, ze_image_region_t> src;
std::pair<ze_image_handle_t, ze_image_region_t> dst;
};
static copy_desc_t getCopyRegions(ur_mem_image_t &src, ur_mem_image_t &dst,
ur_rect_offset_t &srcOrigin,
ur_rect_offset_t &dstOrigin,
ur_rect_region_t ®ion);
ur_context_handle_t getContext() const { return hContext; }
private:
const ur_context_handle_t hContext;
v2::raii::ze_image_handle_t zeImage;
ZeStruct<ze_image_desc_t> zeImageDesc;
};
struct ur_mem_handle_t_ : ur::handle_base<ur::level_zero::ddi_getter> {
template <typename T, typename... Args>
static ur_mem_handle_t_ *create(Args &&...args) {
return new ur_mem_handle_t_(std::in_place_type<T>,
std::forward<Args>(args)...);
}
ur_mem_buffer_t *getBuffer() {
return std::visit(
[](auto &&arg) -> ur_mem_buffer_t * {
if constexpr (std::is_base_of_v<ur_mem_buffer_t,
std::decay_t<decltype(arg)>>) {
return static_cast<ur_mem_buffer_t *>(&arg);
} else {
throw UR_RESULT_ERROR_INVALID_MEM_OBJECT;
}
},
mem);
}
ur_mem_image_t *getImage() {
return std::visit(
[](auto &&arg) -> ur_mem_image_t * {
if constexpr (std::is_same_v<ur_mem_image_t,
std::decay_t<decltype(arg)>>) {
return static_cast<ur_mem_image_t *>(&arg);
} else {
throw UR_RESULT_ERROR_INVALID_MEM_OBJECT;
}
},
mem);
}
bool isImage() const { return std::holds_alternative<ur_mem_image_t>(mem); }
ur::RefCount RefCount;
private:
template <typename T, typename... Args>
ur_mem_handle_t_(std::in_place_type_t<T>, Args &&...args)
: ur::handle_base<ur::level_zero::ddi_getter>(),
mem(std::in_place_type<T>, std::forward<Args>(args)...) {}
std::variant<ur_usm_handle_t, ur_integrated_buffer_handle_t,
ur_discrete_buffer_handle_t, ur_shared_buffer_handle_t,
ur_mem_sub_buffer_t, ur_mem_image_t>
mem;
};