DPC++ Runtime
Runtime libraries for oneAPI DPC++
context_impl.hpp
Go to the documentation of this file.
1 //==---------------- context_impl.hpp - SYCL context ------------*- C++-*---==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #pragma once
10 #include <detail/device_impl.hpp>
12 #include <detail/platform_impl.hpp>
14 #include <sycl/detail/common.hpp>
15 #include <sycl/detail/os_util.hpp>
16 #include <sycl/detail/ur.hpp>
17 #include <sycl/exception_list.hpp>
18 #include <sycl/info/info_desc.hpp>
19 #include <sycl/property_list.hpp>
20 
21 #include <map>
22 #include <memory>
23 #include <optional>
24 #include <set>
25 
26 namespace sycl {
27 inline namespace _V1 {
28 // Forward declaration
29 class device;
30 namespace detail {
31 using PlatformImplPtr = std::shared_ptr<detail::platform_impl>;
32 class context_impl {
33 public:
43  context_impl(const device &Device, async_handler AsyncHandler,
44  const property_list &PropList);
45 
58  context_impl(const std::vector<sycl::device> DeviceList,
59  async_handler AsyncHandler, const property_list &PropList);
60 
71  context_impl(ur_context_handle_t UrContext, async_handler AsyncHandler,
72  const PluginPtr &Plugin,
73  const std::vector<sycl::device> &DeviceList = {},
74  bool OwnedByRuntime = true);
75 
76  ~context_impl();
77 
81  cl_context get() const;
82 
86  const async_handler &get_async_handler() const;
87 
89  const PluginPtr &getPlugin() const { return MPlatform->getPlugin(); }
90 
92  PlatformImplPtr getPlatformImpl() const { return MPlatform; }
93 
97  template <typename Param> typename Param::return_type get_info() const;
98 
102  template <typename Param>
103  typename Param::return_type get_backend_info() const;
104 
113  ur_context_handle_t &getHandleRef();
114 
123  const ur_context_handle_t &getHandleRef() const;
124 
127  const std::vector<device> &getDevices() const { return MDevices; }
128 
130  std::map<std::pair<DeviceLibExt, ur_device_handle_t>,
131  ur_program_handle_t>;
132 
147  return {MCachedLibPrograms, MCachedLibProgramsMutex};
148  }
149 
151 
153  bool hasDevice(std::shared_ptr<detail::device_impl> Device) const;
154 
160  while (!hasDevice(Device)) {
161  if (Device->isRootDevice()) {
162  if (Device->has(aspect::ext_oneapi_is_component)) {
163  // Component devices should be implicitly usable in context created
164  // for a composite device they belong to.
165  auto CompositeDevice = Device->get_info<
166  ext::oneapi::experimental::info::device::composite_device>();
167  return hasDevice(detail::getSyclObjImpl(CompositeDevice));
168  }
169 
170  return false;
171  } else if (Device->getBackend() == backend::opencl) {
172  // OpenCL does not support using descendants of context members within
173  // that context yet. We make the exception in case it supports
174  // component/composite devices.
175  // TODO remove once this limitation is lifted
176  return false;
177  }
178  Device = detail::getSyclObjImpl(
179  Device->get_info<info::device::parent_device>());
180  }
181 
182  return true;
183  }
184 
185  // Returns the backend of this context
186  backend getBackend() const {
187  assert(MPlatform && "MPlatform must be not null");
188  return MPlatform->getBackend();
189  }
190 
193  DeviceImplPtr findMatchingDeviceImpl(ur_device_handle_t &DeviceUR) const;
194 
198  ur_native_handle_t getNative() const;
199 
200  // Returns true if buffer_location property is supported by devices
201  bool isBufferLocationSupported() const;
202 
204  void addAssociatedDeviceGlobal(const void *DeviceGlobalPtr);
205 
207  void addDeviceGlobalInitializer(ur_program_handle_t Program,
208  const std::vector<device> &Devs,
209  const RTDeviceBinaryImage *BinImage);
210 
212  std::vector<ur_event_handle_t>
213  initializeDeviceGlobals(ur_program_handle_t NativePrg,
214  const std::shared_ptr<queue_impl> &QueueImpl);
215 
217  const std::shared_ptr<device_impl> &DeviceImpl,
218  const void *DeviceGlobalPtr, const void *Src, size_t DeviceGlobalTSize,
219  bool IsDeviceImageScoped, size_t NumBytes, size_t Offset);
220 
221  void
222  memcpyFromHostOnlyDeviceGlobal(const std::shared_ptr<device_impl> &DeviceImpl,
223  void *Dest, const void *DeviceGlobalPtr,
224  bool IsDeviceImageScoped, size_t NumBytes,
225  size_t Offset);
226 
228  std::optional<ur_program_handle_t>
229  getProgramForDeviceGlobal(const device &Device,
230  DeviceGlobalMapEntry *DeviceGlobalEntry);
232  std::optional<ur_program_handle_t>
233  getProgramForHostPipe(const device &Device, HostPipeMapEntry *HostPipeEntry);
234 
236  std::optional<ur_program_handle_t>
237  getProgramForDevImgs(const device &Device,
238  const std::set<std::uintptr_t> &ImgIdentifiers,
239  const std::string &ObjectTypeName);
240 
241  bool isOwnedByRuntime() { return MOwnedByRuntime; };
242 
244 
245  const property_list &getPropList() const { return MPropList; }
246 
247 private:
248  bool MOwnedByRuntime;
249  async_handler MAsyncHandler;
250  std::vector<device> MDevices;
251  ur_context_handle_t MContext;
252  PlatformImplPtr MPlatform;
253  property_list MPropList;
254  CachedLibProgramsT MCachedLibPrograms;
255  std::mutex MCachedLibProgramsMutex;
256  mutable KernelProgramCache MKernelProgramCache;
257  mutable PropertySupport MSupportBufferLocationByDevices;
258 
259  std::set<const void *> MAssociatedDeviceGlobals;
260  std::mutex MAssociatedDeviceGlobalsMutex;
261 
262  struct DeviceGlobalInitializer {
263  DeviceGlobalInitializer() = default;
264  DeviceGlobalInitializer(const RTDeviceBinaryImage *BinImage)
265  : MBinImage(BinImage) {
266  // If there are no device globals, they are trivially fully initialized.
267  // Note: Lock is not needed during construction.
268  MDeviceGlobalsFullyInitialized = BinImage->getDeviceGlobals().size() == 0;
269  }
270 
272  void ClearEvents(const PluginPtr &Plugin);
273 
275  const RTDeviceBinaryImage *MBinImage = nullptr;
276 
278  std::mutex MDeviceGlobalInitMutex;
279 
287  bool MDeviceGlobalsFullyInitialized = false;
288 
291  std::vector<ur_event_handle_t> MDeviceGlobalInitEvents;
292  };
293 
294  std::map<std::pair<ur_program_handle_t, ur_device_handle_t>,
295  DeviceGlobalInitializer>
296  MDeviceGlobalInitializers;
297  std::mutex MDeviceGlobalInitializersMutex;
298 
299  // For device_global variables that are not used in any kernel code we still
300  // allow copy operations on them. MDeviceGlobalUnregisteredData stores the
301  // associated writes.
302  // The key to this map is a combination of a the pointer to the device_global
303  // and optionally a device if the device_global has device image scope.
304  std::map<std::pair<const void *, std::optional<ur_device_handle_t>>,
305  std::unique_ptr<std::byte[]>>
306  MDeviceGlobalUnregisteredData;
307  std::mutex MDeviceGlobalUnregisteredDataMutex;
308 };
309 
310 template <typename T, typename Capabilities>
311 void GetCapabilitiesIntersectionSet(const std::vector<sycl::device> &Devices,
312  std::vector<T> &CapabilityList) {
313  for (const sycl::device &Device : Devices) {
314  std::vector<T> NewCapabilityList;
315  std::vector<T> DeviceCapabilities = Device.get_info<Capabilities>();
316  std::set_intersection(
317  CapabilityList.begin(), CapabilityList.end(),
318  DeviceCapabilities.begin(), DeviceCapabilities.end(),
319  std::inserter(NewCapabilityList, NewCapabilityList.begin()));
320  CapabilityList = NewCapabilityList;
321  }
322  CapabilityList.shrink_to_fit();
323 }
324 
325 } // namespace detail
326 } // namespace _V1
327 } // namespace sycl
Represents a reference to value with appropriate lock acquired.
Definition: locked.hpp:23
const PropertyRange & getDeviceGlobals() const
bool hasDevice(std::shared_ptr< detail::device_impl > Device) const
Returns true if and only if context contains the given device.
ur_context_handle_t & getHandleRef()
Gets the underlying context object (if any) without reference count modification.
context_impl(const device &Device, async_handler AsyncHandler, const property_list &PropList)
Constructs a context_impl using a single SYCL devices.
bool isDeviceValid(DeviceImplPtr Device)
Returns true if and only if the device can be used within this context.
std::optional< ur_program_handle_t > getProgramForDevImgs(const device &Device, const std::set< std::uintptr_t > &ImgIdentifiers, const std::string &ObjectTypeName)
Gets a program associated with Dev / Images pairs.
Locked< CachedLibProgramsT > acquireCachedLibPrograms()
In contrast to user programs, which are compiled from user code, library programs come from the SYCL ...
KernelProgramCache & getKernelProgramCache() const
void addDeviceGlobalInitializer(ur_program_handle_t Program, const std::vector< device > &Devs, const RTDeviceBinaryImage *BinImage)
Adds a device global initializer.
void addAssociatedDeviceGlobal(const void *DeviceGlobalPtr)
Adds an associated device global to the tracked associates.
const property_list & getPropList() const
const std::vector< device > & getDevices() const
Unlike ‘get_info<info::context::devices>’, this function returns a reference.
Param::return_type get_info() const
Queries this context for information.
DeviceImplPtr findMatchingDeviceImpl(ur_device_handle_t &DeviceUR) const
Given a UR device, returns the matching shared_ptr<device_impl> within this context.
std::vector< ur_event_handle_t > initializeDeviceGlobals(ur_program_handle_t NativePrg, const std::shared_ptr< queue_impl > &QueueImpl)
Initializes device globals for a program on the associated queue.
void memcpyFromHostOnlyDeviceGlobal(const std::shared_ptr< device_impl > &DeviceImpl, void *Dest, const void *DeviceGlobalPtr, bool IsDeviceImageScoped, size_t NumBytes, size_t Offset)
std::optional< ur_program_handle_t > getProgramForHostPipe(const device &Device, HostPipeMapEntry *HostPipeEntry)
Gets a program associated with a HostPipe Entry from the cache.
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)
Param::return_type get_backend_info() const
Queries SYCL queue for SYCL backend-specific information.
std::map< std::pair< DeviceLibExt, ur_device_handle_t >, ur_program_handle_t > CachedLibProgramsT
const PluginPtr & getPlugin() const
PlatformImplPtr getPlatformImpl() const
ur_native_handle_t getNative() const
Gets the native handle of the SYCL context.
cl_context get() const
Gets OpenCL interoperability context handle.
const async_handler & get_async_handler() const
Gets asynchronous exception handler.
std::optional< ur_program_handle_t > getProgramForDeviceGlobal(const device &Device, DeviceGlobalMapEntry *DeviceGlobalEntry)
Gets a program associated with a device global from the cache.
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
detail::is_device_info_desc< Param >::return_type get_info() const
Queries this SYCL device for information requested by the template parameter param.
Definition: device.hpp:215
Objects of the property_list class are containers for the SYCL properties.
decltype(Obj::impl) const & getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:31
void GetCapabilitiesIntersectionSet(const std::vector< sycl::device > &Devices, std::vector< T > &CapabilityList)
std::shared_ptr< plugin > PluginPtr
Definition: ur.hpp:60
std::shared_ptr< detail::platform_impl > PlatformImplPtr
std::shared_ptr< device_impl > DeviceImplPtr
std::function< void(sycl::exception_list)> async_handler
Definition: access.hpp:18
C++ utilities for Unified Runtime integration.