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