-
Notifications
You must be signed in to change notification settings - Fork 744
/
context_impl.hpp
327 lines (279 loc) · 12.9 KB
/
context_impl.hpp
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
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
//==---------------- context_impl.hpp - SYCL context ------------*- C++-*---==//
//
// 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 <detail/device_impl.hpp>
#include <detail/kernel_program_cache.hpp>
#include <detail/platform_impl.hpp>
#include <detail/program_manager/program_manager.hpp>
#include <sycl/detail/common.hpp>
#include <sycl/detail/os_util.hpp>
#include <sycl/detail/ur.hpp>
#include <sycl/exception_list.hpp>
#include <sycl/info/info_desc.hpp>
#include <sycl/property_list.hpp>
#include <map>
#include <memory>
#include <optional>
#include <set>
namespace sycl {
inline namespace _V1 {
// Forward declaration
class device;
namespace detail {
using PlatformImplPtr = std::shared_ptr<detail::platform_impl>;
class context_impl {
public:
/// Constructs a context_impl using a single SYCL devices.
///
/// The constructed context_impl will use the AsyncHandler parameter to
/// handle exceptions.
/// PropList carries the properties of the constructed context_impl.
///
/// \param Device is an instance of SYCL device.
/// \param AsyncHandler is an instance of async_handler.
/// \param PropList is an instance of property_list.
context_impl(const device &Device, async_handler AsyncHandler,
const property_list &PropList);
/// Constructs a context_impl using a list of SYCL devices.
///
/// Newly created instance will save each SYCL device in the list. This
/// requres that all devices in the list are associated with the same
/// SYCL platform.
/// The constructed context_impl will use the AsyncHandler parameter to
/// handle exceptions.
/// PropList carries the properties of the constructed context_impl.
///
/// \param DeviceList is a list of SYCL device instances.
/// \param AsyncHandler is an instance of async_handler.
/// \param PropList is an instance of property_list.
context_impl(const std::vector<sycl::device> DeviceList,
async_handler AsyncHandler, const property_list &PropList);
/// Construct a context_impl using plug-in interoperability handle.
///
/// The constructed context_impl will use the AsyncHandler parameter to
/// handle exceptions.
///
/// \param UrContext is an instance of a valid plug-in context handle.
/// \param AsyncHandler is an instance of async_handler.
/// \param Plugin is the reference to the underlying Plugin that this
/// \param OwnedByRuntime is the flag if ownership is kept by user or
/// transferred to runtime
context_impl(ur_context_handle_t UrContext, async_handler AsyncHandler,
const PluginPtr &Plugin,
const std::vector<sycl::device> &DeviceList = {},
bool OwnedByRuntime = true);
~context_impl();
/// Gets OpenCL interoperability context handle.
///
/// \return an instance of OpenCL cl_context.
cl_context get() const;
/// Gets asynchronous exception handler.
///
/// \return an instance of SYCL async_handler.
const async_handler &get_async_handler() const;
/// \return the Plugin associated with the platform of this context.
const PluginPtr &getPlugin() const { return MPlatform->getPlugin(); }
/// \return the PlatformImpl associated with this context.
PlatformImplPtr getPlatformImpl() const { return MPlatform; }
/// Queries this context for information.
///
/// The return type depends on information being queried.
template <typename Param> typename Param::return_type get_info() const;
/// Queries SYCL queue for SYCL backend-specific information.
///
/// The return type depends on information being queried.
template <typename Param>
typename Param::return_type get_backend_info() const;
/// Gets the underlying context object (if any) without reference count
/// modification.
///
/// Caller must ensure the returned object lives on stack only. It can also
/// be safely passed to the underlying native runtime API. Warning. Returned
/// reference will be invalid if context_impl was destroyed.
///
/// \return an instance of raw plug-in context handle.
ur_context_handle_t &getHandleRef();
/// Gets the underlying context object (if any) without reference count
/// modification.
///
/// Caller must ensure the returned object lives on stack only. It can also
/// be safely passed to the underlying native runtime API. Warning. Returned
/// reference will be invalid if context_impl was destroyed.
///
/// \return an instance of raw plug-in context handle.
const ur_context_handle_t &getHandleRef() const;
/// Unlike `get_info<info::context::devices>', this function returns a
/// reference.
const std::vector<device> &getDevices() const { return MDevices; }
using CachedLibProgramsT =
std::map<std::pair<DeviceLibExt, ur_device_handle_t>,
ur_program_handle_t>;
/// In contrast to user programs, which are compiled from user code, library
/// programs come from the SYCL runtime. They are identified by the
/// corresponding extension:
///
/// cl_intel_devicelib_assert -> #<ur program with assert functions>
/// cl_intel_devicelib_complex -> #<ur program with complex functions>
/// etc.
///
/// See `doc/design/DeviceLibExtensions.rst' for
/// more details.
///
/// \returns an instance of sycl::detail::Locked which wraps a map with device
/// library programs and the corresponding lock for synchronized access.
Locked<CachedLibProgramsT> acquireCachedLibPrograms() {
return {MCachedLibPrograms, MCachedLibProgramsMutex};
}
KernelProgramCache &getKernelProgramCache() const;
/// Returns true if and only if context contains the given device.
bool hasDevice(std::shared_ptr<detail::device_impl> Device) const;
/// Returns true if and only if the device can be used within this context.
/// For OpenCL this is currently equivalent to hasDevice, for other backends
/// it returns true if the device is either a member of the context or a
/// descendant of a member.
bool isDeviceValid(DeviceImplPtr Device) {
while (!hasDevice(Device)) {
if (Device->isRootDevice()) {
if (Device->has(aspect::ext_oneapi_is_component)) {
// Component devices should be implicitly usable in context created
// for a composite device they belong to.
auto CompositeDevice = Device->get_info<
ext::oneapi::experimental::info::device::composite_device>();
return hasDevice(detail::getSyclObjImpl(CompositeDevice));
}
return false;
} else if (Device->getBackend() == backend::opencl) {
// OpenCL does not support using descendants of context members within
// that context yet. We make the exception in case it supports
// component/composite devices.
// TODO remove once this limitation is lifted
return false;
}
Device = detail::getSyclObjImpl(
Device->get_info<info::device::parent_device>());
}
return true;
}
// Returns the backend of this context
backend getBackend() const {
assert(MPlatform && "MPlatform must be not null");
return MPlatform->getBackend();
}
/// Given a UR device, returns the matching shared_ptr<device_impl>
/// within this context. May return nullptr if no match discovered.
DeviceImplPtr findMatchingDeviceImpl(ur_device_handle_t &DeviceUR) const;
/// Gets the native handle of the SYCL context.
///
/// \return a native handle.
ur_native_handle_t getNative() const;
// Returns true if buffer_location property is supported by devices
bool isBufferLocationSupported() const;
/// Adds an associated device global to the tracked associates.
void addAssociatedDeviceGlobal(const void *DeviceGlobalPtr);
/// Adds a device global initializer.
void addDeviceGlobalInitializer(ur_program_handle_t Program,
const std::vector<device> &Devs,
const RTDeviceBinaryImage *BinImage);
/// Initializes device globals for a program on the associated queue.
std::vector<ur_event_handle_t>
initializeDeviceGlobals(ur_program_handle_t NativePrg,
const std::shared_ptr<queue_impl> &QueueImpl);
void memcpyToHostOnlyDeviceGlobal(
const std::shared_ptr<device_impl> &DeviceImpl,
const void *DeviceGlobalPtr, const void *Src, size_t DeviceGlobalTSize,
bool IsDeviceImageScoped, size_t NumBytes, size_t Offset);
void
memcpyFromHostOnlyDeviceGlobal(const std::shared_ptr<device_impl> &DeviceImpl,
void *Dest, const void *DeviceGlobalPtr,
bool IsDeviceImageScoped, size_t NumBytes,
size_t Offset);
/// Gets a program associated with a device global from the cache.
std::optional<ur_program_handle_t>
getProgramForDeviceGlobal(const device &Device,
DeviceGlobalMapEntry *DeviceGlobalEntry);
/// Gets a program associated with a HostPipe Entry from the cache.
std::optional<ur_program_handle_t>
getProgramForHostPipe(const device &Device, HostPipeMapEntry *HostPipeEntry);
/// Gets a program associated with Dev / Images pairs.
std::optional<ur_program_handle_t>
getProgramForDevImgs(const device &Device,
const std::set<std::uintptr_t> &ImgIdentifiers,
const std::string &ObjectTypeName);
bool isOwnedByRuntime() { return MOwnedByRuntime; };
enum PropertySupport { NotSupported = 0, Supported = 1, NotChecked = 2 };
const property_list &getPropList() const { return MPropList; }
private:
bool MOwnedByRuntime;
async_handler MAsyncHandler;
std::vector<device> MDevices;
ur_context_handle_t MContext;
PlatformImplPtr MPlatform;
property_list MPropList;
CachedLibProgramsT MCachedLibPrograms;
std::mutex MCachedLibProgramsMutex;
mutable KernelProgramCache MKernelProgramCache;
mutable PropertySupport MSupportBufferLocationByDevices;
std::set<const void *> MAssociatedDeviceGlobals;
std::mutex MAssociatedDeviceGlobalsMutex;
struct DeviceGlobalInitializer {
DeviceGlobalInitializer() = default;
DeviceGlobalInitializer(const RTDeviceBinaryImage *BinImage)
: MBinImage(BinImage) {
// If there are no device globals, they are trivially fully initialized.
// Note: Lock is not needed during construction.
MDeviceGlobalsFullyInitialized = BinImage->getDeviceGlobals().size() == 0;
}
/// Clears all events of the initializer. This will not acquire the lock.
void ClearEvents(const PluginPtr &Plugin);
/// The binary image of the program.
const RTDeviceBinaryImage *MBinImage = nullptr;
/// Mutex for protecting initialization of device globals for the image.
std::mutex MDeviceGlobalInitMutex;
/// Flag signalling whether or not the device globals have been initialized.
/// This is effectively the same as checking that MDeviceGlobalInitEvents
/// is empty, however it does not require MDeviceGlobalInitMutex to be held
/// when checked as it will only be true when initialization is guaranteed
/// to be done.
/// MDeviceGlobalInitMutex must be held when determining if initialization
/// has been begun or when setting the value.
bool MDeviceGlobalsFullyInitialized = false;
/// A vector of events associated with the initialization of device globals.
/// MDeviceGlobalInitMutex must be held when accessing this.
std::vector<ur_event_handle_t> MDeviceGlobalInitEvents;
};
std::map<std::pair<ur_program_handle_t, ur_device_handle_t>,
DeviceGlobalInitializer>
MDeviceGlobalInitializers;
std::mutex MDeviceGlobalInitializersMutex;
// For device_global variables that are not used in any kernel code we still
// allow copy operations on them. MDeviceGlobalUnregisteredData stores the
// associated writes.
// The key to this map is a combination of a the pointer to the device_global
// and optionally a device if the device_global has device image scope.
std::map<std::pair<const void *, std::optional<ur_device_handle_t>>,
std::unique_ptr<std::byte[]>>
MDeviceGlobalUnregisteredData;
std::mutex MDeviceGlobalUnregisteredDataMutex;
};
template <typename T, typename Capabilities>
void GetCapabilitiesIntersectionSet(const std::vector<sycl::device> &Devices,
std::vector<T> &CapabilityList) {
for (const sycl::device &Device : Devices) {
std::vector<T> NewCapabilityList;
std::vector<T> DeviceCapabilities = Device.get_info<Capabilities>();
std::set_intersection(
CapabilityList.begin(), CapabilityList.end(),
DeviceCapabilities.begin(), DeviceCapabilities.end(),
std::inserter(NewCapabilityList, NewCapabilityList.begin()));
CapabilityList = NewCapabilityList;
}
CapabilityList.shrink_to_fit();
}
} // namespace detail
} // namespace _V1
} // namespace sycl