DPC++ Runtime
Runtime libraries for oneAPI DPC++
program_manager.hpp
Go to the documentation of this file.
1 //==------ program_manager.hpp --- SYCL program manager---------------------==//
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/cg.hpp>
16 #include <sycl/detail/cg_types.hpp>
17 #include <sycl/detail/common.hpp>
19 #include <sycl/detail/export.hpp>
21 #include <sycl/detail/os_util.hpp>
22 #include <sycl/detail/ur.hpp>
23 #include <sycl/detail/util.hpp>
24 #include <sycl/device.hpp>
25 #include <sycl/kernel_bundle.hpp>
26 
27 #include <cstdint>
28 #include <map>
29 #include <memory>
30 #include <set>
31 #include <unordered_map>
32 #include <unordered_set>
33 #include <vector>
34 
35 // +++ Entry points referenced by the offload wrapper object {
36 
39 extern "C" __SYCL_EXPORT void __sycl_register_lib(sycl_device_binaries desc);
40 
44 extern "C" __SYCL_EXPORT void __sycl_unregister_lib(sycl_device_binaries desc);
45 
46 // +++ }
47 
48 namespace sycl {
49 inline namespace _V1 {
50 class context;
51 namespace detail {
52 
53 bool doesDevSupportDeviceRequirements(const device &Dev,
54  const RTDeviceBinaryImage &BinImages);
55 std::optional<sycl::exception>
56 checkDevSupportDeviceRequirements(const device &Dev,
57  const RTDeviceBinaryImage &BinImages,
58  const NDRDescT &NDRDesc = {});
59 
60 // This value must be the same as in libdevice/device_itt.h.
61 // See sycl/doc/design/ITTAnnotations.md for more info.
62 static constexpr uint32_t inline ITTSpecConstId = 0xFF747469;
63 
64 class context_impl;
65 using ContextImplPtr = std::shared_ptr<context_impl>;
66 class device_impl;
67 using DeviceImplPtr = std::shared_ptr<device_impl>;
68 class queue_impl;
69 class event_impl;
70 // DeviceLibExt is shared between sycl runtime and sycl-post-link tool.
71 // If any update is made here, need to sync with DeviceLibExt definition
72 // in llvm/tools/sycl-post-link/sycl-post-link.cpp
73 enum class DeviceLibExt : std::uint32_t {
84 };
85 
86 // Provides single loading and building OpenCL programs with unique contexts
87 // that is necessary for no interoperability cases with lambda.
89 public:
90  // Returns the single instance of the program manager for the entire
91  // process. Can only be called after staticInit is done.
92  static ProgramManager &getInstance();
93 
94  RTDeviceBinaryImage &getDeviceImage(const std::string &KernelName,
95  const context &Context,
96  const device &Device,
97  bool JITCompilationIsRequired = false);
98 
100  const std::unordered_set<RTDeviceBinaryImage *> &ImagesToVerify,
101  const context &Context, const device &Device,
102  bool JITCompilationIsRequired = false);
103 
104  ur_program_handle_t createURProgram(const RTDeviceBinaryImage &Img,
105  const context &Context,
106  const device &Device);
126  std::pair<ur_program_handle_t, bool>
128  const RTDeviceBinaryImage &Img,
129  const std::vector<const RTDeviceBinaryImage *> &AllImages,
130  const context &Context,
131  const device &Device,
132  const std::string &CompileAndLinkOptions,
133  SerializedObj SpecConsts);
143  ur_program_handle_t getBuiltURProgram(const ContextImplPtr &ContextImpl,
144  const DeviceImplPtr &DeviceImpl,
145  const std::string &KernelName,
146  const NDRDescT &NDRDesc = {},
147  bool JITCompilationIsRequired = false);
148 
149  ur_program_handle_t getBuiltURProgram(const context &Context,
150  const device &Device,
151  const std::string &KernelName,
152  const property_list &PropList,
153  bool JITCompilationIsRequired = false);
154 
155  std::tuple<ur_kernel_handle_t, std::mutex *, const KernelArgMask *,
156  ur_program_handle_t>
157  getOrCreateKernel(const ContextImplPtr &ContextImpl,
158  const DeviceImplPtr &DeviceImpl,
159  const std::string &KernelName,
160  const NDRDescT &NDRDesc = {});
161 
162  ur_kernel_handle_t getCachedMaterializedKernel(
163  const std::string &KernelName,
164  const std::vector<unsigned char> &SpecializationConsts);
165 
166  ur_kernel_handle_t getOrCreateMaterializedKernel(
167  const RTDeviceBinaryImage &Img, const context &Context,
168  const device &Device, const std::string &KernelName,
169  const std::vector<unsigned char> &SpecializationConsts);
170 
171  ur_program_handle_t getUrProgramFromUrKernel(ur_kernel_handle_t Kernel,
172  const ContextImplPtr Context);
173 
174  void addImages(sycl_device_binaries DeviceImages);
175  void debugPrintBinaryImages() const;
176  static std::string getProgramBuildLog(const ur_program_handle_t &Program,
177  const ContextImplPtr Context);
178 
179  uint32_t getDeviceLibReqMask(const RTDeviceBinaryImage &Img);
180 
185  const KernelArgMask *
186  getEliminatedKernelArgMask(ur_program_handle_t NativePrg,
187  const std::string &KernelName);
188 
189  // The function returns the unique SYCL kernel identifier associated with a
190  // kernel name.
191  kernel_id getSYCLKernelID(const std::string &KernelName);
192 
193  // The function returns a vector containing all unique SYCL kernel identifiers
194  // in SYCL device images.
195  std::vector<kernel_id> getAllSYCLKernelIDs();
196 
197  // The function returns the unique SYCL kernel identifier associated with a
198  // built-in kernel name.
199  kernel_id getBuiltInKernelID(const std::string &KernelName);
200 
201  // The function inserts or initializes a device_global entry into the
202  // device_global map.
203  void addOrInitDeviceGlobalEntry(const void *DeviceGlobalPtr,
204  const char *UniqueId);
205 
206  // Returns true if any available image is compatible with the device Dev.
207  bool hasCompatibleImage(const device &Dev);
208 
209  // The function gets a device_global entry identified by the pointer to the
210  // device_global object from the device_global map.
211  DeviceGlobalMapEntry *getDeviceGlobalEntry(const void *DeviceGlobalPtr);
212 
213  // The function gets multiple device_global entries identified by their unique
214  // IDs from the device_global map.
215  std::vector<DeviceGlobalMapEntry *>
216  getDeviceGlobalEntries(const std::vector<std::string> &UniqueIds,
217  bool ExcludeDeviceImageScopeDecorated = false);
218  // The function inserts or initializes a host_pipe entry into the
219  // host_pipe map.
220  void addOrInitHostPipeEntry(const void *HostPipePtr, const char *UniqueId);
221 
222  // The function gets a host_pipe entry identified by the unique ID from
223  // the host_pipe map.
224  HostPipeMapEntry *getHostPipeEntry(const std::string &UniqueId);
225 
226  // The function gets a host_pipe entry identified by the pointer to the
227  // host_pipe object from the host_pipe map.
228  HostPipeMapEntry *getHostPipeEntry(const void *HostPipePtr);
229 
232  const context &Ctx, const device &Dev);
233 
234  // The function returns a vector of SYCL device images that are compiled with
235  // the required state and at least one device from the passed list of devices.
236  std::vector<device_image_plain> getSYCLDeviceImagesWithCompatibleState(
237  const context &Ctx, const std::vector<device> &Devs,
238  bundle_state TargetState, const std::vector<kernel_id> &KernelIDs = {});
239 
240  // Brind images in the passed vector to the required state. Does it inplace
241  void
242  bringSYCLDeviceImagesToState(std::vector<device_image_plain> &DeviceImages,
243  bundle_state TargetState);
244 
245  // The function returns a vector of SYCL device images in required state,
246  // which are compatible with at least one of the device from Devs.
247  std::vector<device_image_plain>
248  getSYCLDeviceImages(const context &Ctx, const std::vector<device> &Devs,
249  bundle_state State);
250 
251  // The function returns a vector of SYCL device images, for which Selector
252  // callable returns true, in required state, which are compatible with at
253  // least one of the device from Devs.
254  std::vector<device_image_plain>
255  getSYCLDeviceImages(const context &Ctx, const std::vector<device> &Devs,
256  const DevImgSelectorImpl &Selector,
257  bundle_state TargetState);
258 
259  // The function returns a vector of SYCL device images which represent at
260  // least one kernel from kernel ids vector in required state, which are
261  // compatible with at least one of the device from Devs.
262  std::vector<device_image_plain>
263  getSYCLDeviceImages(const context &Ctx, const std::vector<device> &Devs,
264  const std::vector<kernel_id> &KernelIDs,
265  bundle_state TargetState);
266 
267  // Produces new device image by convering input device image to the object
268  // state
269  device_image_plain compile(const device_image_plain &DeviceImage,
270  const std::vector<device> &Devs,
271  const property_list &PropList);
272 
273  // Produces set of device images by convering input device images to object
274  // the executable state
275  std::vector<device_image_plain> link(const device_image_plain &DeviceImages,
276  const std::vector<device> &Devs,
277  const property_list &PropList);
278 
279  // Produces new device image by converting input device image to the
280  // executable state
281  device_image_plain build(const device_image_plain &DeviceImage,
282  const std::vector<device> &Devs,
283  const property_list &PropList);
284 
285  std::tuple<ur_kernel_handle_t, std::mutex *, const KernelArgMask *>
286  getOrCreateKernel(const context &Context, const std::string &KernelName,
287  const property_list &PropList, ur_program_handle_t Program);
288 
289  ProgramManager();
290  ~ProgramManager() = default;
291 
292  bool kernelUsesAssert(const std::string &KernelName) const;
293 
294  bool kernelUsesAsan() const { return m_AsanFoundInImage; }
295 
296  std::set<RTDeviceBinaryImage *>
297  getRawDeviceImages(const std::vector<kernel_id> &KernelIDs);
298 
299 private:
300  ProgramManager(ProgramManager const &) = delete;
301  ProgramManager &operator=(ProgramManager const &) = delete;
302 
303  using ProgramPtr = std::unique_ptr<remove_pointer_t<ur_program_handle_t>,
304  decltype(&::urProgramRelease)>;
305  ProgramPtr build(ProgramPtr Program, const ContextImplPtr Context,
306  const std::string &CompileOptions,
307  const std::string &LinkOptions, ur_device_handle_t Device,
308  uint32_t DeviceLibReqMask,
309  const std::vector<ur_program_handle_t> &ProgramsToLink);
310 
312  void dumpImage(const RTDeviceBinaryImage &Img, uint32_t SequenceID = 0) const;
313 
315  void cacheKernelUsesAssertInfo(RTDeviceBinaryImage &Img);
316 
317  std::set<RTDeviceBinaryImage *>
318  collectDeviceImageDepsForImportedSymbols(const RTDeviceBinaryImage &Img,
319  device Dev);
320 
321  std::set<RTDeviceBinaryImage *>
322  collectDependentDeviceImagesForVirtualFunctions(
323  const RTDeviceBinaryImage &Img, device Dev);
324 
327  using RTDeviceBinaryImageUPtr = std::unique_ptr<RTDeviceBinaryImage>;
328 
333  //
334  std::unordered_map<std::string, kernel_id> m_KernelName2KernelIDs;
335 
336  // Maps KernelIDs to device binary images. There can be more than one image
337  // in case of SPIRV + AOT.
338  // Using shared_ptr to avoid expensive copy of the vector.
340  std::unordered_multimap<kernel_id, RTDeviceBinaryImage *>
341  m_KernelIDs2BinImage;
342 
343  // Maps device binary image to a vector of kernel ids in this image.
344  // Using shared_ptr to avoid expensive copy of the vector.
345  // The vector is initialized in addImages function and is supposed to be
346  // immutable afterwards.
348  std::unordered_map<RTDeviceBinaryImage *,
349  std::shared_ptr<std::vector<kernel_id>>>
350  m_BinImg2KernelIDs;
351 
356  std::mutex m_KernelIDsMutex;
357 
364  std::unordered_multimap<std::string, RTDeviceBinaryImage *> m_ServiceKernels;
365 
367  // from kernel bundles.
369  std::unordered_multimap<std::string, RTDeviceBinaryImage *>
370  m_ExportedSymbolImages;
371 
374  std::unordered_set<RTDeviceBinaryImageUPtr> m_DeviceImages;
375 
378  std::unordered_map<std::string, kernel_id> m_BuiltInKernelIDs;
379 
382  std::unordered_map<std::string, std::set<RTDeviceBinaryImage *>>
383  m_VFSet2BinImage;
384 
386  std::mutex m_BuiltInKernelIDsMutex;
387 
388  // Keeps track of ur_program to image correspondence. Needed for:
389  // - knowing which specialization constants are used in the program and
390  // injecting their current values before compiling the SPIR-V; the binary
391  // image object has info about all spec constants used in the module
392  // - finding kernel argument masks for kernels associated with each
393  // ur_program
394  // NOTE: using RTDeviceBinaryImage raw pointers is OK, since they are not
395  // referenced from outside SYCL runtime and RTDeviceBinaryImage object
396  // lifetime matches program manager's one.
397  // NOTE: keys in the map can be invalid (reference count went to zero and
398  // the underlying program disposed of), so the map can't be used in any way
399  // other than binary image lookup with known live UrProgram as the key.
400  // NOTE: access is synchronized via the MNativeProgramsMutex
401  std::unordered_map<ur_program_handle_t, const RTDeviceBinaryImage *>
402  NativePrograms;
403 
405  std::mutex MNativeProgramsMutex;
406 
407  using KernelNameToArgMaskMap = std::unordered_map<std::string, KernelArgMask>;
410  std::unordered_map<const RTDeviceBinaryImage *, KernelNameToArgMaskMap>
411  m_EliminatedKernelArgMasks;
412 
414  bool m_UseSpvFile = false;
415  RTDeviceBinaryImageUPtr m_SpvFileImage;
416 
417  std::set<std::string> m_KernelUsesAssert;
418 
419  // True iff there is a device image compiled with AddressSanitizer
420  bool m_AsanFoundInImage;
421 
422  // Maps between device_global identifiers and associated information.
423  std::unordered_map<std::string, std::unique_ptr<DeviceGlobalMapEntry>>
424  m_DeviceGlobals;
425  std::unordered_map<const void *, DeviceGlobalMapEntry *> m_Ptr2DeviceGlobal;
426 
428  std::mutex m_DeviceGlobalsMutex;
429 
430  // Maps between host_pipe identifiers and associated information.
431  std::unordered_map<std::string, std::unique_ptr<HostPipeMapEntry>>
432  m_HostPipes;
433  std::unordered_map<const void *, HostPipeMapEntry *> m_Ptr2HostPipe;
434 
436  std::mutex m_HostPipesMutex;
437 
438  using MaterializedEntries =
439  std::map<std::vector<unsigned char>, ur_kernel_handle_t>;
440  std::unordered_map<std::string, MaterializedEntries> m_MaterializedKernels;
441 };
442 } // namespace detail
443 } // namespace _V1
444 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:50
ur_program_handle_t getBuiltURProgram(const ContextImplPtr &ContextImpl, const DeviceImplPtr &DeviceImpl, const std::string &KernelName, const NDRDescT &NDRDesc={}, bool JITCompilationIsRequired=false)
Builds or retrieves from cache a program defining the kernel with given name.
std::tuple< ur_kernel_handle_t, std::mutex *, const KernelArgMask *, ur_program_handle_t > getOrCreateKernel(const ContextImplPtr &ContextImpl, const DeviceImplPtr &DeviceImpl, const std::string &KernelName, const NDRDescT &NDRDesc={})
std::set< RTDeviceBinaryImage * > getRawDeviceImages(const std::vector< kernel_id > &KernelIDs)
uint32_t getDeviceLibReqMask(const RTDeviceBinaryImage &Img)
ur_kernel_handle_t getOrCreateMaterializedKernel(const RTDeviceBinaryImage &Img, const context &Context, const device &Device, const std::string &KernelName, const std::vector< unsigned char > &SpecializationConsts)
kernel_id getBuiltInKernelID(const std::string &KernelName)
ur_program_handle_t getBuiltURProgram(const context &Context, const device &Device, const std::string &KernelName, const property_list &PropList, bool JITCompilationIsRequired=false)
void addImages(sycl_device_binaries DeviceImages)
std::vector< device_image_plain > getSYCLDeviceImages(const context &Ctx, const std::vector< device > &Devs, bundle_state State)
ur_kernel_handle_t getCachedMaterializedKernel(const std::string &KernelName, const std::vector< unsigned char > &SpecializationConsts)
static ProgramManager & getInstance()
std::vector< device_image_plain > getSYCLDeviceImagesWithCompatibleState(const context &Ctx, const std::vector< device > &Devs, bundle_state TargetState, const std::vector< kernel_id > &KernelIDs={})
ur_program_handle_t createURProgram(const RTDeviceBinaryImage &Img, const context &Context, const device &Device)
const KernelArgMask * getEliminatedKernelArgMask(ur_program_handle_t NativePrg, const std::string &KernelName)
Returns the mask for eliminated kernel arguments for the requested kernel within the native program.
void addOrInitHostPipeEntry(const void *HostPipePtr, const char *UniqueId)
kernel_id getSYCLKernelID(const std::string &KernelName)
static std::string getProgramBuildLog(const ur_program_handle_t &Program, const ContextImplPtr Context)
std::pair< ur_program_handle_t, bool > getOrCreateURProgram(const RTDeviceBinaryImage &Img, const std::vector< const RTDeviceBinaryImage * > &AllImages, const context &Context, const device &Device, const std::string &CompileAndLinkOptions, SerializedObj SpecConsts)
Creates a UR program using either a cached device code binary if present in the persistent cache or f...
DeviceGlobalMapEntry * getDeviceGlobalEntry(const void *DeviceGlobalPtr)
device_image_plain getDeviceImageFromBinaryImage(RTDeviceBinaryImage *BinImage, const context &Ctx, const device &Dev)
RTDeviceBinaryImage & getDeviceImage(const std::string &KernelName, const context &Context, const device &Device, bool JITCompilationIsRequired=false)
bool kernelUsesAssert(const std::string &KernelName) const
void bringSYCLDeviceImagesToState(std::vector< device_image_plain > &DeviceImages, bundle_state TargetState)
HostPipeMapEntry * getHostPipeEntry(const std::string &UniqueId)
device_image_plain build(const device_image_plain &DeviceImage, const std::vector< device > &Devs, const property_list &PropList)
void addOrInitDeviceGlobalEntry(const void *DeviceGlobalPtr, const char *UniqueId)
ur_program_handle_t getUrProgramFromUrKernel(ur_kernel_handle_t Kernel, const ContextImplPtr Context)
device_image_plain compile(const device_image_plain &DeviceImage, const std::vector< device > &Devs, const property_list &PropList)
bool hasCompatibleImage(const device &Dev)
std::vector< device_image_plain > link(const device_image_plain &DeviceImages, const std::vector< device > &Devs, const property_list &PropList)
std::vector< DeviceGlobalMapEntry * > getDeviceGlobalEntries(const std::vector< std::string > &UniqueIds, bool ExcludeDeviceImageScopeDecorated=false)
std::vector< kernel_id > getAllSYCLKernelIDs()
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
Objects of the class identify kernel is some kernel_bundle related APIs.
Objects of the property_list class are containers for the SYCL properties.
std::optional< sycl::exception > checkDevSupportDeviceRequirements(const device &Dev, const RTDeviceBinaryImage &Img, const NDRDescT &NDRDesc)
std::function< bool(const detail::DeviceImageImplPtr &DevImgImpl)> DevImgSelectorImpl
std::vector< bool > KernelArgMask
static constexpr uint32_t ITTSpecConstId
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: event_impl.hpp:32
std::shared_ptr< device_impl > DeviceImplPtr
bool doesDevSupportDeviceRequirements(const device &Dev, const RTDeviceBinaryImage &Img)
std::vector< unsigned char > SerializedObj
Definition: util.hpp:69
Definition: access.hpp:18
void __sycl_unregister_lib(sycl_device_binaries desc)
Executed as a part of current module's (.exe, .dll) static de-initialization.
void __sycl_register_lib(sycl_device_binaries desc)
Executed as a part of current module's (.exe, .dll) static initialization.
This struct is a record of all the device code that may be offloaded.
Definition: compiler.hpp:186
C++ utilities for Unified Runtime integration.