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