DPC++ Runtime
Runtime libraries for oneAPI DPC++
pi.cpp
Go to the documentation of this file.
1 //===-- pi.cpp - PI utilities implementation -------------------*- 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 
13 
14 #include "context_impl.hpp"
15 #include <detail/config.hpp>
17 #include <detail/plugin.hpp>
18 #include <detail/xpti_registry.hpp>
19 #include <sycl/context.hpp>
20 #include <sycl/detail/common.hpp>
22 #include <sycl/detail/pi.hpp>
24 #include <sycl/version.hpp>
25 
26 #include <bitset>
27 #include <cstdarg>
28 #include <cstring>
29 #include <iostream>
30 #include <map>
31 #include <sstream>
32 #include <stddef.h>
33 #include <string>
34 #include <tuple>
35 
36 #ifdef XPTI_ENABLE_INSTRUMENTATION
37 // Include the headers necessary for emitting
38 // traces using the trace framework
39 #include "xpti/xpti_trace_framework.h"
40 #endif
41 
42 namespace sycl {
43 inline namespace _V1 {
44 namespace detail {
45 #ifdef XPTI_ENABLE_INSTRUMENTATION
46 // Global (to the SYCL runtime) graph handle that all command groups are a
47 // child of
49 xpti_td *GSYCLGraphEvent = nullptr;
51 xpti_td *GPICallEvent = nullptr;
53 xpti_td *GPIArgCallEvent = nullptr;
54 xpti_td *GPIArgCallActiveEvent = nullptr;
55 
56 uint8_t PiCallStreamID = 0;
57 uint8_t PiDebugCallStreamID = 0;
58 
59 #endif // XPTI_ENABLE_INSTRUMENTATION
60 
61 template <sycl::backend BE> void *getPluginOpaqueData(void *OpaqueDataParam) {
62  void *ReturnOpaqueData = nullptr;
63  const PluginPtr &Plugin = pi::getPlugin<BE>();
64 
66  OpaqueDataParam, &ReturnOpaqueData);
67 
68  return ReturnOpaqueData;
69 }
70 
71 template __SYCL_EXPORT void *
72 getPluginOpaqueData<sycl::backend::ext_intel_esimd_emulator>(void *);
73 
74 namespace pi {
75 
76 static void initializePlugins(std::vector<PluginPtr> &Plugins);
77 
78 bool XPTIInitDone = false;
79 
80 // Implementation of the SYCL PI API call tracing methods that use XPTI
81 // framework to emit these traces that will be used by tools.
82 uint64_t emitFunctionBeginTrace(const char *FName) {
83  uint64_t CorrelationID = 0;
84 #ifdef XPTI_ENABLE_INSTRUMENTATION
85  // The function_begin and function_end trace point types are defined to
86  // trace library API calls and they are currently enabled here for support
87  // tools that need the API scope. The methods emitFunctionBeginTrace() and
88  // emitFunctionEndTrace() can be extended to also trace the arguments of the
89  // PI API call using a trace point type the extends the predefined trace
90  // point types.
91  //
92  // You can use the sample collector in llvm/xptifw/samples/syclpi_collector
93  // to print the API traces and also extend them to support arguments that
94  // may be traced later.
95  //
115  constexpr uint16_t NotificationTraceType =
116  (uint16_t)xpti::trace_point_type_t::function_begin;
117  if (xptiCheckTraceEnabled(PiCallStreamID, NotificationTraceType)) {
118  CorrelationID = xptiGetUniqueId();
119  xptiNotifySubscribers(PiCallStreamID, NotificationTraceType, GPICallEvent,
120  nullptr, CorrelationID,
121  static_cast<const void *>(FName));
122  }
123 #endif // XPTI_ENABLE_INSTRUMENTATION
124  return CorrelationID;
125 }
126 
127 void emitFunctionEndTrace(uint64_t CorrelationID, const char *FName) {
128 #ifdef XPTI_ENABLE_INSTRUMENTATION
129  constexpr uint16_t NotificationTraceType =
130  (uint16_t)xpti::trace_point_type_t::function_end;
131  if (xptiCheckTraceEnabled(PiCallStreamID, NotificationTraceType)) {
132  // CorrelationID is the unique ID that ties together a function_begin and
133  // function_end pair of trace calls. The splitting of a scoped_notify into
134  // two function calls incurs an additional overhead as the StreamID must
135  // be looked up twice.
136  xptiNotifySubscribers(PiCallStreamID, NotificationTraceType, GPICallEvent,
137  nullptr, CorrelationID,
138  static_cast<const void *>(FName));
139  }
140 #endif // XPTI_ENABLE_INSTRUMENTATION
141 }
142 
143 uint64_t emitFunctionWithArgsBeginTrace(uint32_t FuncID, const char *FuncName,
144  unsigned char *ArgsData,
145  pi_plugin Plugin) {
146  uint64_t CorrelationID = 0;
147 #ifdef XPTI_ENABLE_INSTRUMENTATION
148  constexpr uint16_t NotificationTraceType =
149  (uint16_t)xpti::trace_point_type_t::function_with_args_begin;
150  if (xptiCheckTraceEnabled(PiDebugCallStreamID, NotificationTraceType)) {
151  xpti::function_with_args_t Payload{FuncID, FuncName, ArgsData, nullptr,
152  &Plugin};
153  {
155  auto CodeLoc = Tls.query();
156  xpti::payload_t PL = xpti::payload_t(
157  CodeLoc.functionName(), CodeLoc.fileName(), CodeLoc.lineNumber(),
158  CodeLoc.columnNumber(), nullptr);
159  uint64_t InstanceNumber{};
160  assert(GPIArgCallActiveEvent == nullptr);
161  GPIArgCallActiveEvent =
162  xptiMakeEvent("Plugin interface call", &PL, xpti::trace_graph_event,
163  xpti_at::active, &InstanceNumber);
164  }
165 
166  CorrelationID = xptiGetUniqueId();
167  xptiNotifySubscribers(PiDebugCallStreamID, NotificationTraceType,
168  GPIArgCallEvent, GPIArgCallActiveEvent, CorrelationID,
169  &Payload);
170  }
171 #endif
172  return CorrelationID;
173 }
174 
175 void emitFunctionWithArgsEndTrace(uint64_t CorrelationID, uint32_t FuncID,
176  const char *FuncName, unsigned char *ArgsData,
177  pi_result Result, pi_plugin Plugin) {
178 #ifdef XPTI_ENABLE_INSTRUMENTATION
179  constexpr uint16_t NotificationTraceType =
180  (uint16_t)xpti::trace_point_type_t::function_with_args_end;
181  if (xptiCheckTraceEnabled(PiDebugCallStreamID, NotificationTraceType)) {
182  xpti::function_with_args_t Payload{FuncID, FuncName, ArgsData, &Result,
183  &Plugin};
184 
185  xptiNotifySubscribers(PiDebugCallStreamID, NotificationTraceType,
186  GPIArgCallEvent, GPIArgCallActiveEvent, CorrelationID,
187  &Payload);
188  GPIArgCallActiveEvent = nullptr;
189  }
190 #endif
191 }
192 
195  void *user_data) {
196  auto impl = getSyclObjImpl(context);
197  auto contextHandle = reinterpret_cast<pi_context>(impl->getHandleRef());
198  const auto &Plugin = impl->getPlugin();
199  Plugin->call<PiApiKind::piextContextSetExtendedDeleter>(contextHandle, func,
200  user_data);
201 }
202 
204  switch (info) {
206  return "PI_PLATFORM_INFO_PROFILE";
208  return "PI_PLATFORM_INFO_VERSION";
210  return "PI_PLATFORM_INFO_NAME";
212  return "PI_PLATFORM_INFO_VENDOR";
214  return "PI_PLATFORM_INFO_EXTENSIONS";
216  return "PI_EXT_PLATFORM_INFO_BACKEND";
217  }
218  die("Unknown pi_platform_info value passed to "
219  "sycl::detail::pi::platformInfoToString");
220 }
221 
222 std::string memFlagToString(pi_mem_flags Flag) {
223  assertion(((Flag == 0u) || ((Flag & (Flag - 1)) == 0)) &&
224  "More than one bit set");
225 
226  std::stringstream Sstream;
227 
228  switch (Flag) {
229  case pi_mem_flags{0}:
230  Sstream << "pi_mem_flags(0)";
231  break;
233  Sstream << "PI_MEM_FLAGS_ACCESS_RW";
234  break;
236  Sstream << "PI_MEM_FLAGS_HOST_PTR_USE";
237  break;
239  Sstream << "PI_MEM_FLAGS_HOST_PTR_COPY";
240  break;
241  default:
242  Sstream << "unknown pi_mem_flags bit == " << Flag;
243  }
244 
245  return Sstream.str();
246 }
247 
248 std::string memFlagsToString(pi_mem_flags Flags) {
249  std::stringstream Sstream;
250  bool FoundFlag = false;
251 
252  auto FlagSeparator = [](bool FoundFlag) { return FoundFlag ? "|" : ""; };
253 
254  pi_mem_flags ValidFlags[] = {PI_MEM_FLAGS_ACCESS_RW,
257 
258  if (Flags == 0u) {
259  Sstream << "pi_mem_flags(0)";
260  } else {
261  for (const auto Flag : ValidFlags) {
262  if (Flag & Flags) {
263  Sstream << FlagSeparator(FoundFlag) << memFlagToString(Flag);
264  FoundFlag = true;
265  }
266  }
267 
268  std::bitset<64> UnkownBits(Flags & ~(PI_MEM_FLAGS_ACCESS_RW |
271  if (UnkownBits.any()) {
272  Sstream << FlagSeparator(FoundFlag)
273  << "unknown pi_mem_flags bits == " << UnkownBits;
274  }
275  }
276 
277  return Sstream.str();
278 }
279 
280 // GlobalPlugin is a global Plugin used with Interoperability constructors that
281 // use OpenCL objects to construct SYCL class objects.
282 // TODO: GlobalPlugin does not seem to be needed anymore. Consider removing it!
283 std::shared_ptr<plugin> GlobalPlugin;
284 
285 // Find the plugin at the appropriate location and return the location.
286 std::vector<std::pair<std::string, backend>> findPlugins() {
287  std::vector<std::pair<std::string, backend>> PluginNames;
288 
289  // TODO: Based on final design discussions, change the location where the
290  // plugin must be searched; how to identify the plugins etc. Currently the
291  // search is done for libpi_opencl.so/pi_opencl.dll file in LD_LIBRARY_PATH
292  // env only.
293  //
294 
297 
298  // Will we be filtering with SYCL_DEVICE_FILTER or ONEAPI_DEVICE_SELECTOR ?
299  // We do NOT attempt to support both simultaneously.
300  if (OdsTargetList && FilterList) {
302  "ONEAPI_DEVICE_SELECTOR cannot be used in "
303  "conjunction with SYCL_DEVICE_FILTER");
304  } else if (!FilterList && !OdsTargetList) {
305  PluginNames.emplace_back(__SYCL_OPENCL_PLUGIN_NAME, backend::opencl);
306  PluginNames.emplace_back(__SYCL_LEVEL_ZERO_PLUGIN_NAME,
308  PluginNames.emplace_back(__SYCL_CUDA_PLUGIN_NAME, backend::ext_oneapi_cuda);
309  PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME, backend::ext_oneapi_hip);
310  PluginNames.emplace_back(__SYCL_UR_PLUGIN_NAME, backend::all);
311  PluginNames.emplace_back(__SYCL_NATIVE_CPU_PLUGIN_NAME,
313  } else if (FilterList) {
314  std::vector<device_filter> Filters = FilterList->get();
315  bool OpenCLFound = false;
316  bool LevelZeroFound = false;
317  bool CudaFound = false;
318  bool EsimdCpuFound = false;
319  bool HIPFound = false;
320  bool NativeCPUFound = false;
321  for (const device_filter &Filter : Filters) {
322  backend Backend = Filter.Backend ? Filter.Backend.value() : backend::all;
323  if (!OpenCLFound &&
324  (Backend == backend::opencl || Backend == backend::all)) {
325  PluginNames.emplace_back(__SYCL_OPENCL_PLUGIN_NAME, backend::opencl);
326  OpenCLFound = true;
327  }
328  if (!LevelZeroFound && (Backend == backend::ext_oneapi_level_zero ||
329  Backend == backend::all)) {
330  PluginNames.emplace_back(__SYCL_LEVEL_ZERO_PLUGIN_NAME,
332  LevelZeroFound = true;
333  }
334  if (!CudaFound &&
335  (Backend == backend::ext_oneapi_cuda || Backend == backend::all)) {
336  PluginNames.emplace_back(__SYCL_CUDA_PLUGIN_NAME,
338  CudaFound = true;
339  }
340  if (!EsimdCpuFound && Backend == backend::ext_intel_esimd_emulator) {
341  PluginNames.emplace_back(__SYCL_ESIMD_EMULATOR_PLUGIN_NAME,
342  backend::ext_intel_esimd_emulator);
343  EsimdCpuFound = true;
344  }
345  if (!HIPFound &&
346  (Backend == backend::ext_oneapi_hip || Backend == backend::all)) {
347  PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME,
349  HIPFound = true;
350  }
351  if (!NativeCPUFound &&
352  (Backend == backend::ext_native_cpu || Backend == backend::all)) {
353  PluginNames.emplace_back(__SYCL_NATIVE_CPU_PLUGIN_NAME,
355  }
356  PluginNames.emplace_back(__SYCL_UR_PLUGIN_NAME, backend::all);
357  }
358  } else {
359  ods_target_list &list = *OdsTargetList;
361  PluginNames.emplace_back(__SYCL_OPENCL_PLUGIN_NAME, backend::opencl);
362  }
364  PluginNames.emplace_back(__SYCL_LEVEL_ZERO_PLUGIN_NAME,
366  }
368  PluginNames.emplace_back(__SYCL_CUDA_PLUGIN_NAME,
370  }
371  if (list.backendCompatible(backend::ext_intel_esimd_emulator)) {
372  PluginNames.emplace_back(__SYCL_ESIMD_EMULATOR_PLUGIN_NAME,
373  backend::ext_intel_esimd_emulator);
374  }
376  PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME, backend::ext_oneapi_hip);
377  }
379  PluginNames.emplace_back(__SYCL_NATIVE_CPU_PLUGIN_NAME,
381  }
382  PluginNames.emplace_back(__SYCL_UR_PLUGIN_NAME, backend::all);
383  }
384  return PluginNames;
385 }
386 
387 // Load the Plugin by calling the OS dependent library loading call.
388 // Return the handle to the Library.
389 void *loadPlugin(const std::string &PluginPath) {
390  return loadOsPluginLibrary(PluginPath);
391 }
392 
393 // Unload the given plugin by calling teh OS-specific library unloading call.
394 // \param Library OS-specific library handle created when loading.
395 int unloadPlugin(void *Library) { return unloadOsPluginLibrary(Library); }
396 
397 // Binds all the PI Interface APIs to Plugin Library Function Addresses.
398 // TODO: Remove the 'OclPtr' extension to PI_API.
399 // TODO: Change the functionality such that a single getOsLibraryFuncAddress
400 // call is done to get all Interface API mapping. The plugin interface also
401 // needs to setup infrastructure to route PI_CALLs to the appropriate plugins.
402 // Currently, we bind to a singe plugin.
403 bool bindPlugin(void *Library,
404  const std::shared_ptr<PiPlugin> &PluginInformation) {
405 
406  decltype(::piPluginInit) *PluginInitializeFunction =
407  (decltype(&::piPluginInit))(getOsLibraryFuncAddress(Library,
408  "piPluginInit"));
409  if (PluginInitializeFunction == nullptr)
410  return false;
411 
412  int Err = PluginInitializeFunction(PluginInformation.get());
413 
414  // TODO: Compare Supported versions and check for backward compatibility.
415  // Make sure err is PI_SUCCESS.
416  assert((Err == PI_SUCCESS) && "Unexpected error when binding to Plugin.");
417  (void)Err;
418 
419  // TODO: Return a more meaningful value/enum.
420  return true;
421 }
422 
423 bool trace(TraceLevel Level) {
424  auto TraceLevelMask = SYCLConfig<SYCL_PI_TRACE>::get();
425  return (TraceLevelMask & Level) == Level;
426 }
427 
428 // Initializes all available Plugins.
429 std::vector<PluginPtr> &initialize() {
430  static std::once_flag PluginsInitDone;
431  // std::call_once is blocking all other threads if a thread is already
432  // creating a vector of plugins. So, no additional lock is needed.
433  std::call_once(PluginsInitDone, [&]() {
435  });
437 }
438 
439 // Implementation of this function is OS specific. Please see windows_pi.cpp and
440 // posix_pi.cpp.
441 // TODO: refactor code when support matrix for DPCPP changes and <filesystem> is
442 // available on all supported systems.
443 std::vector<std::tuple<std::string, backend, void *>>
444 loadPlugins(const std::vector<std::pair<std::string, backend>> &&PluginNames);
445 
446 static void initializePlugins(std::vector<PluginPtr> &Plugins) {
447  const std::vector<std::pair<std::string, backend>> PluginNames =
448  findPlugins();
449 
450  if (PluginNames.empty() && trace(PI_TRACE_ALL))
451  std::cerr << "SYCL_PI_TRACE[all]: "
452  << "No Plugins Found." << std::endl;
453 
454  // Get library handles for the list of plugins.
455  std::vector<std::tuple<std::string, backend, void *>> LoadedPlugins =
456  loadPlugins(std::move(PluginNames));
457 
458  for (auto &[Name, Backend, Library] : LoadedPlugins) {
459  std::shared_ptr<PiPlugin> PluginInformation = std::make_shared<PiPlugin>(
461  /*Targets=*/nullptr, /*FunctionPointers=*/{}});
462 
463  if (!Library) {
464  if (trace(PI_TRACE_ALL)) {
465  std::cerr << "SYCL_PI_TRACE[all]: "
466  << "Check if plugin is present. "
467  << "Failed to load plugin: " << Name << std::endl;
468  }
469  continue;
470  }
471 
472  if (!bindPlugin(Library, PluginInformation)) {
473  if (trace(PI_TRACE_ALL)) {
474  std::cerr << "SYCL_PI_TRACE[all]: "
475  << "Failed to bind PI APIs to the plugin: " << Name
476  << std::endl;
477  }
478  continue;
479  }
480  PluginPtr &NewPlugin = Plugins.emplace_back(
481  std::make_shared<plugin>(PluginInformation, Backend, Library));
483  std::cerr << "SYCL_PI_TRACE[basic]: "
484  << "Plugin found and successfully loaded: " << Name
485  << " [ PluginVersion: "
486  << NewPlugin->getPiPlugin().PluginVersion << " ]" << std::endl;
487  }
488 
489 #ifdef XPTI_ENABLE_INSTRUMENTATION
491 
492  if (!(xptiTraceEnabled() && !XPTIInitDone))
493  return;
494  // Not sure this is the best place to initialize the framework; SYCL runtime
495  // team needs to advise on the right place, until then we piggy-back on the
496  // initialization of the PI layer.
497 
498  // Initialize the global events just once, in the case pi::initialize() is
499  // called multiple times
500  XPTIInitDone = true;
501  // Registers a new stream for 'sycl' and any plugin that wants to listen to
502  // this stream will register itself using this string or stream ID for this
503  // string.
504  uint8_t StreamID = xptiRegisterStream(SYCL_STREAM_NAME);
505  // Let all tool plugins know that a stream by the name of 'sycl' has been
506  // initialized and will be generating the trace stream.
509  // Create a tracepoint to indicate the graph creation
510  xpti::payload_t GraphPayload("application_graph");
511  uint64_t GraphInstanceNo;
512  GSYCLGraphEvent =
513  xptiMakeEvent("application_graph", &GraphPayload, xpti::trace_graph_event,
514  xpti_at::active, &GraphInstanceNo);
515  if (GSYCLGraphEvent) {
516  // The graph event is a global event and will be used as the parent for
517  // all nodes (command groups)
518  xptiNotifySubscribers(StreamID, xpti::trace_graph_create, nullptr,
519  GSYCLGraphEvent, GraphInstanceNo, nullptr);
520  }
521 
522  // Let subscribers know a new stream is being initialized
525  xpti::payload_t PIPayload("Plugin Interface Layer");
526  uint64_t PiInstanceNo;
527  GPICallEvent =
528  xptiMakeEvent("PI Layer", &PIPayload, xpti::trace_algorithm_event,
529  xpti_at::active, &PiInstanceNo);
530 
533  xpti::payload_t PIArgPayload(
534  "Plugin Interface Layer (with function arguments)");
535  uint64_t PiArgInstanceNo;
536  GPIArgCallEvent = xptiMakeEvent("PI Layer with arguments", &PIArgPayload,
537  xpti::trace_algorithm_event, xpti_at::active,
538  &PiArgInstanceNo);
539 
540  PiCallStreamID = xptiRegisterStream(SYCL_PICALL_STREAM_NAME);
541  PiDebugCallStreamID = xptiRegisterStream(SYCL_PIDEBUGCALL_STREAM_NAME);
542 #endif
543 }
544 
545 // Get the plugin serving given backend.
546 template <backend BE> const PluginPtr &getPlugin() {
547  static PluginPtr *Plugin = nullptr;
548  if (Plugin)
549  return *Plugin;
550 
551  std::vector<PluginPtr> &Plugins = pi::initialize();
552  for (auto &P : Plugins)
553  if (P->hasBackend(BE)) {
554  Plugin = &P;
555  return *Plugin;
556  }
557 
558  throw runtime_error("pi::getPlugin couldn't find plugin",
559  PI_ERROR_INVALID_OPERATION);
560 }
561 
562 template __SYCL_EXPORT const PluginPtr &getPlugin<backend::opencl>();
563 template __SYCL_EXPORT const PluginPtr &
564 getPlugin<backend::ext_oneapi_level_zero>();
565 template __SYCL_EXPORT const PluginPtr &
566 getPlugin<backend::ext_intel_esimd_emulator>();
567 template __SYCL_EXPORT const PluginPtr &getPlugin<backend::ext_oneapi_cuda>();
568 template __SYCL_EXPORT const PluginPtr &getPlugin<backend::ext_oneapi_hip>();
569 
570 // Report error and no return (keeps compiler from printing warnings).
571 // TODO: Probably change that to throw a catchable exception,
572 // but for now it is useful to see every failure.
573 //
574 [[noreturn]] void die(const char *Message) {
575  std::cerr << "pi_die: " << Message << std::endl;
576  std::terminate();
577 }
578 
579 void assertion(bool Condition, const char *Message) {
580  if (!Condition)
581  die(Message);
582 }
583 
584 // Reads an integer value from ELF data.
585 template <typename ResT>
586 static ResT readELFValue(const unsigned char *Data, size_t NumBytes,
587  bool IsBigEndian) {
588  assert(NumBytes <= sizeof(ResT));
589  ResT Result = 0;
590  if (IsBigEndian) {
591  for (size_t I = 0; I < NumBytes; ++I) {
592  Result = (Result << 8) | static_cast<ResT>(Data[I]);
593  }
594  } else {
595  std::copy(Data, Data + NumBytes, reinterpret_cast<char *>(&Result));
596  }
597  return Result;
598 }
599 
600 // Checks if an ELF image contains a section with a specified name.
601 static bool checkELFSectionPresent(const std::string &ExpectedSectionName,
602  const unsigned char *ImgData,
603  size_t ImgSize) {
604  // Check for 64bit and big-endian.
605  bool Is64bit = ImgData[4] == 2;
606  bool IsBigEndian = ImgData[5] == 2;
607 
608  // Make offsets based on whether the ELF file is 64bit or not.
609  size_t SectionHeaderOffsetInfoOffset = Is64bit ? 0x28 : 0x20;
610  size_t SectionHeaderSizeInfoOffset = Is64bit ? 0x3A : 0x2E;
611  size_t SectionHeaderNumInfoOffset = Is64bit ? 0x3C : 0x30;
612  size_t SectionStringsHeaderIndexInfoOffset = Is64bit ? 0x3E : 0x32;
613 
614  // if the image doesn't contain enough data for the header values, end early.
615  if (ImgSize < SectionStringsHeaderIndexInfoOffset + 2)
616  return false;
617 
618  // Read the e_shoff, e_shentsize, e_shnum, and e_shstrndx entries in the
619  // header.
620  uint64_t SectionHeaderOffset = readELFValue<uint64_t>(
621  ImgData + SectionHeaderOffsetInfoOffset, Is64bit ? 8 : 4, IsBigEndian);
622  uint16_t SectionHeaderSize = readELFValue<uint16_t>(
623  ImgData + SectionHeaderSizeInfoOffset, 2, IsBigEndian);
624  uint16_t SectionHeaderNum = readELFValue<uint16_t>(
625  ImgData + SectionHeaderNumInfoOffset, 2, IsBigEndian);
626  uint16_t SectionStringsHeaderIndex = readELFValue<uint16_t>(
627  ImgData + SectionStringsHeaderIndexInfoOffset, 2, IsBigEndian);
628 
629  // End early if we do not have the expected number of section headers or
630  // if the read section string header index is out-of-range.
631  if (ImgSize < SectionHeaderOffset + SectionHeaderNum * SectionHeaderSize ||
632  SectionStringsHeaderIndex >= SectionHeaderNum)
633  return false;
634 
635  // Get the location of the section string data.
636  size_t SectionStringsInfoOffset = Is64bit ? 0x18 : 0x10;
637  const unsigned char *SectionStringsHeaderData =
638  ImgData + SectionHeaderOffset +
639  SectionStringsHeaderIndex * SectionHeaderSize;
640  uint64_t SectionStrings = readELFValue<uint64_t>(
641  SectionStringsHeaderData + SectionStringsInfoOffset, Is64bit ? 8 : 4,
642  IsBigEndian);
643  const unsigned char *SectionStringsData = ImgData + SectionStrings;
644 
645  // For each section, check the name against the expected section and return
646  // true if we find it.
647  for (size_t I = 0; I < SectionHeaderNum; ++I) {
648  // Get the offset into the section string data of this sections name.
649  const unsigned char *HeaderData =
650  ImgData + SectionHeaderOffset + I * SectionHeaderSize;
651  uint32_t SectionNameOffset =
652  readELFValue<uint32_t>(HeaderData, 4, IsBigEndian);
653 
654  // Read the section name and check if it is the same as the name we are
655  // looking for.
656  const char *SectionName =
657  reinterpret_cast<const char *>(SectionStringsData + SectionNameOffset);
658  if (SectionName == ExpectedSectionName)
659  return true;
660  }
661  return false;
662 }
663 
664 // Returns the e_type field from an ELF image.
665 static uint16_t getELFHeaderType(const unsigned char *ImgData, size_t ImgSize) {
666  (void)ImgSize;
667  assert(ImgSize >= 18 && "Not enough bytes to have an ELF header type.");
668 
669  bool IsBigEndian = ImgData[5] == 2;
670  return readELFValue<uint16_t>(ImgData + 16, 2, IsBigEndian);
671 }
672 
674 getBinaryImageFormat(const unsigned char *ImgData, size_t ImgSize) {
675  // Top-level magic numbers for the recognized binary image formats.
676  struct {
678  const uint32_t Magic;
679  } Fmts[] = {{PI_DEVICE_BINARY_TYPE_SPIRV, 0x07230203},
681  // 'I', 'N', 'T', 'C' ; Intel native
682  {PI_DEVICE_BINARY_TYPE_NATIVE, 0x43544E49}};
683 
684  if (ImgSize >= sizeof(Fmts[0].Magic)) {
685  std::remove_const_t<decltype(Fmts[0].Magic)> Hdr = 0;
686  std::copy(ImgData, ImgData + sizeof(Hdr), reinterpret_cast<char *>(&Hdr));
687 
688  // Check headers for direct formats.
689  for (const auto &Fmt : Fmts) {
690  if (Hdr == Fmt.Magic)
691  return Fmt.Fmt;
692  }
693 
694  // ELF e_type for recognized binary image formats.
695  struct {
697  const uint16_t Magic;
698  } ELFFmts[] = {{PI_DEVICE_BINARY_TYPE_NATIVE, 0xFF04}, // OpenCL executable
699  {PI_DEVICE_BINARY_TYPE_NATIVE, 0xFF12}}; // ZEBIN executable
700 
701  // ELF files need to be parsed separately. The header type ends after 18
702  // bytes.
703  if (Hdr == 0x464c457F && ImgSize >= 18) {
704  uint16_t HdrType = getELFHeaderType(ImgData, ImgSize);
705  for (const auto &ELFFmt : ELFFmts) {
706  if (HdrType == ELFFmt.Magic)
707  return ELFFmt.Fmt;
708  }
709  // Newer ZEBIN format does not have a special header type, but can instead
710  // be identified by having a required .ze_info section.
711  if (checkELFSectionPresent(".ze_info", ImgData, ImgSize))
713  }
714  }
716 }
717 
718 } // namespace pi
719 } // namespace detail
720 } // namespace _V1
721 } // namespace sycl
sycl::_V1::detail::pi::bindPlugin
bool bindPlugin(void *Library, const std::shared_ptr< PiPlugin > &PluginInformation)
Definition: pi.cpp:403
sycl::_V1::detail::tls_code_loc_t::query
const detail::code_location & query()
Query the information in the TLS slot.
Definition: common.cpp:55
PI_DEVICE_BINARY_TYPE_NONE
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_NONE
Definition: pi.h:876
sycl::_V1::detail::pi::loadPlugins
std::vector< std::tuple< std::string, backend, void * > > loadPlugins(const std::vector< std::pair< std::string, backend >> &&PluginNames)
Definition: posix_pi.cpp:53
sycl::_V1::detail::pi::initializePlugins
static void initializePlugins(std::vector< PluginPtr > &Plugins)
Definition: pi.cpp:446
sycl::_V1::detail::pi::contextSetExtendedDeleter
void contextSetExtendedDeleter(const sycl::context &constext, pi_context_extended_deleter func, void *user_data)
Definition: pi.cpp:193
sycl::_V1::detail::pi::PiDeviceBinaryType
::pi_device_binary_type PiDeviceBinaryType
Definition: pi.hpp:134
sycl::_V1::detail::SYCL_STREAM_NAME
constexpr const char * SYCL_STREAM_NAME
Definition: xpti_registry.hpp:29
sycl::_V1::backend
backend
Definition: backend_types.hpp:18
context_impl.hpp
sycl::_V1::detail::pi::initialize
std::vector< PluginPtr > & initialize()
Definition: pi.cpp:429
sycl::_V1::detail::pi::memFlagsToString
std::string memFlagsToString(pi_mem_flags Flags)
Definition: pi.cpp:248
device_filter.hpp
PI_DEVICE_BINARY_TYPE_SPIRV
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_SPIRV
Definition: pi.h:881
sycl::_V1::make_error_code
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:94
config.hpp
sycl::_V1::backend::ext_oneapi_level_zero
@ ext_oneapi_level_zero
PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE
Definition: pi.h:883
PI_MEM_FLAGS_HOST_PTR_COPY
constexpr pi_mem_flags PI_MEM_FLAGS_HOST_PTR_COPY
Definition: pi.h:700
_pi_plugin
Definition: pi.h:2694
xpti_registry.hpp
sycl::_V1::detail::GlobalHandler::getXPTIRegistry
XPTIRegistry & getXPTIRegistry()
Definition: global_handler.cpp:217
sycl::_V1::detail::pi::getELFHeaderType
static uint16_t getELFHeaderType(const unsigned char *ImgData, size_t ImgSize)
Definition: pi.cpp:665
_pi_result
_pi_result
Definition: pi.h:205
sycl::_V1::detail::GlobalHandler::instance
static GlobalHandler & instance()
Definition: global_handler.cpp:125
common.hpp
sycl::_V1::detail::SYCL_PIDEBUGCALL_STREAM_NAME
constexpr const char * SYCL_PIDEBUGCALL_STREAM_NAME
Definition: xpti_registry.hpp:34
piPluginInit
pi_result piPluginInit(pi_plugin *plugin_info)
Definition: pi_cuda.cpp:1186
sycl::_V1::backend::ext_oneapi_hip
@ ext_oneapi_hip
detail
---— Error handling, matching OpenCL plugin semantics.
Definition: common.hpp:44
sycl::_V1::detail::ods_target_list::backendCompatible
bool backendCompatible(backend Backend)
Definition: device_filter.cpp:273
sycl::_V1::detail::pi::unloadOsPluginLibrary
int unloadOsPluginLibrary(void *Library)
Definition: posix_pi.cpp:39
sycl
Definition: access.hpp:18
sycl::_V1::backend::all
@ all
sycl::_V1::detail::pi::emitFunctionWithArgsBeginTrace
uint64_t emitFunctionWithArgsBeginTrace(uint32_t FuncID, const char *FName, unsigned char *ArgsData, pi_plugin Plugin)
Notifies XPTI subscribers about PI function calls and packs call arguments.
Definition: pi.cpp:143
plugin.hpp
sycl::_V1::detail::device_filter_list::get
std::vector< device_filter > & get()
Definition: device_filter.hpp:92
PI_PLATFORM_INFO_NAME
@ PI_PLATFORM_INFO_NAME
Definition: pi.h:222
pi.hpp
sycl::_V1::backend::ext_oneapi_cuda
@ ext_oneapi_cuda
sycl::_V1::detail::getPlugin
static const PluginPtr & getPlugin(backend Backend)
Definition: backend.cpp:32
sycl::_V1::detail::pi::unloadPlugin
int unloadPlugin(void *Library)
Definition: pi.cpp:395
stl_type_traits.hpp
sycl::_V1::detail::pi::emitFunctionBeginTrace
uint64_t emitFunctionBeginTrace(const char *FName)
Emits an XPTI trace before a PI API call is made.
Definition: pi.cpp:82
sycl::_V1::detail::pi::readELFValue
static ResT readELFValue(const unsigned char *Data, size_t NumBytes, bool IsBigEndian)
Definition: pi.cpp:586
piextContextSetExtendedDeleter
pi_result piextContextSetExtendedDeleter(pi_context context, pi_context_extended_deleter func, void *user_data)
Definition: pi_cuda.cpp:127
GMinVer
constexpr int GMinVer
Definition: tracing.cpp:28
PI_DEVICE_BINARY_TYPE_NATIVE
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_NATIVE
Definition: pi.h:878
GVerStr
constexpr auto GVerStr
Definition: tracing.cpp:26
pi_mem_flags
pi_bitfield pi_mem_flags
Definition: pi.h:694
sycl::_V1::detail::tls_code_loc_t
Data type that manages the code_location information in TLS.
Definition: common.hpp:129
sycl::_V1::detail::pi::findPlugins
std::vector< std::pair< std::string, backend > > findPlugins()
Definition: pi.cpp:286
sycl::_V1::detail::SYCL_PICALL_STREAM_NAME
constexpr const char * SYCL_PICALL_STREAM_NAME
Definition: xpti_registry.hpp:31
sycl::_V1::detail::XPTIRegistry::initializeFrameworkOnce
void initializeFrameworkOnce()
Definition: xpti_registry.hpp:65
pi_context_extended_deleter
void(* pi_context_extended_deleter)(void *user_data)
Definition: pi.h:1271
sycl::_V1::exception
Definition: exception.hpp:68
sycl::_V1::detail::pi::platformInfoToString
std::string platformInfoToString(pi_platform_info info)
Definition: pi.cpp:203
std::cerr
__SYCL_EXTERN_STREAM_ATTRS ostream cerr
Linked to standard error (unbuffered)
piextPluginGetOpaqueData
pi_result piextPluginGetOpaqueData(void *opaque_data_param, void **opaque_data_return)
API to get Plugin internal data, opaque to SYCL RT.
Definition: pi_cuda.cpp:1149
PI_MEM_FLAGS_HOST_PTR_USE
constexpr pi_mem_flags PI_MEM_FLAGS_HOST_PTR_USE
Definition: pi.h:699
sycl::_V1::detail::XPTIRegistry::initializeStream
void initializeStream(const std::string &StreamName, uint32_t MajVer, uint32_t MinVer, const std::string &VerStr)
Notifies XPTI subscribers about new stream.
Definition: xpti_registry.hpp:94
sycl::_V1::detail::pi::XPTIInitDone
bool XPTIInitDone
Definition: pi.cpp:78
global_handler.hpp
PI_PLATFORM_INFO_VERSION
@ PI_PLATFORM_INFO_VERSION
Definition: pi.h:225
sycl::_V1::detail::pi::loadPlugin
void * loadPlugin(const std::string &PluginPath)
Definition: pi.cpp:389
PI_PLATFORM_INFO_PROFILE
@ PI_PLATFORM_INFO_PROFILE
Definition: pi.h:223
sycl::_V1::errc::invalid
@ invalid
sycl::_V1::detail::pi::PI_TRACE_BASIC
@ PI_TRACE_BASIC
Definition: pi.hpp:58
PI_MEM_FLAGS_ACCESS_RW
constexpr pi_mem_flags PI_MEM_FLAGS_ACCESS_RW
Definition: pi.h:696
PI_PLATFORM_INFO_VENDOR
@ PI_PLATFORM_INFO_VENDOR
Definition: pi.h:224
sycl::_V1::detail::device_filter
Definition: device_filter.hpp:72
sycl::_V1::detail::pi::loadOsPluginLibrary
void * loadOsPluginLibrary(const std::string &Library)
Definition: posix_pi.cpp:33
sycl::_V1::backend::opencl
@ opencl
_PI_H_VERSION_STRING
#define _PI_H_VERSION_STRING
Definition: pi.h:165
sycl::_V1::detail::pi::getBinaryImageFormat
PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData, size_t ImgSize)
Tries to determine the device binary image foramat.
Definition: pi.cpp:674
sycl::_V1::detail::device_filter_list
Definition: device_filter.hpp:84
_pi_platform_info
_pi_platform_info
Definition: pi.h:220
sycl::_V1::detail::pi::TraceLevel
TraceLevel
Definition: pi.hpp:57
sycl::_V1::detail::pi::getOsLibraryFuncAddress
void * getOsLibraryFuncAddress(void *Library, const std::string &FunctionName)
Definition: posix_pi.cpp:47
PI_EXT_PLATFORM_INFO_BACKEND
@ PI_EXT_PLATFORM_INFO_BACKEND
Definition: pi.h:226
sycl::_V1::detail::pi::GlobalPlugin
std::shared_ptr< plugin > GlobalPlugin
Definition: pi.cpp:283
sycl::_V1::detail::ods_target_list
Definition: device_filter.hpp:55
GMajVer
constexpr int GMajVer
Definition: tracing.cpp:27
sycl::_V1::detail::pi::checkELFSectionPresent
static bool checkELFSectionPresent(const std::string &ExpectedSectionName, const unsigned char *ImgData, size_t ImgSize)
Definition: pi.cpp:601
sycl::_V1::detail::pi::PI_TRACE_ALL
@ PI_TRACE_ALL
Definition: pi.hpp:60
sycl::_V1::detail::pi::assertion
void assertion(bool Condition, const char *Message=nullptr)
Definition: pi.cpp:579
context.hpp
sycl::_V1::backend::ext_native_cpu
@ ext_native_cpu
die
void die(const char *Message)
Definition: ur.hpp:52
sycl::_V1::detail::pi::memFlagToString
std::string memFlagToString(pi_mem_flags Flag)
Definition: pi.cpp:222
sycl::_V1::detail::pi::emitFunctionEndTrace
void emitFunctionEndTrace(uint64_t CorrelationID, const char *FName)
Emits an XPTI trace after the PI API call has been made.
Definition: pi.cpp:127
sycl::_V1::detail::getPluginOpaqueData
void * getPluginOpaqueData(void *opaquedata_arg)
Definition: pi.cpp:61
sycl::_V1::detail::pi::trace
bool trace(TraceLevel level)
Definition: pi.cpp:423
sycl::_V1::detail::GlobalHandler::getPlugins
std::vector< PluginPtr > & getPlugins()
Definition: global_handler.cpp:203
sycl::_V1::detail::SYCLConfig::get
static const char * get()
Definition: config.hpp:115
sycl::_V1::detail::pi::emitFunctionWithArgsEndTrace
void emitFunctionWithArgsEndTrace(uint64_t CorrelationID, uint32_t FuncID, const char *FName, unsigned char *ArgsData, pi_result Result, pi_plugin Plugin)
Notifies XPTI subscribers about PI function call result.
Definition: pi.cpp:175
_pi_context
Definition: pi_cuda.hpp:52
sycl::_V1::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:30
sycl::_V1::context
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:51
sycl::_V1::detail::PluginPtr
std::shared_ptr< plugin > PluginPtr
Definition: pi.hpp:48
PI_PLATFORM_INFO_EXTENSIONS
@ PI_PLATFORM_INFO_EXTENSIONS
Definition: pi.h:221