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  //
295 #ifndef __INTEL_PREVIEW_BREAKING_CHANGES
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  }
305  if (FilterList) {
306  std::vector<device_filter> Filters = FilterList->get();
307  bool OpenCLFound = false;
308  bool LevelZeroFound = false;
309  bool CudaFound = false;
310  bool EsimdCpuFound = false;
311  bool HIPFound = false;
312  bool NativeCPUFound = false;
313  for (const device_filter &Filter : Filters) {
314  backend Backend = Filter.Backend ? Filter.Backend.value() : backend::all;
315  if (!OpenCLFound &&
316  (Backend == backend::opencl || Backend == backend::all)) {
317  PluginNames.emplace_back(__SYCL_OPENCL_PLUGIN_NAME, backend::opencl);
318  OpenCLFound = true;
319  }
320  if (!LevelZeroFound && (Backend == backend::ext_oneapi_level_zero ||
321  Backend == backend::all)) {
322  PluginNames.emplace_back(__SYCL_LEVEL_ZERO_PLUGIN_NAME,
324  LevelZeroFound = true;
325  }
326  if (!CudaFound &&
327  (Backend == backend::ext_oneapi_cuda || Backend == backend::all)) {
328  PluginNames.emplace_back(__SYCL_CUDA_PLUGIN_NAME,
330  CudaFound = true;
331  }
332  if (!EsimdCpuFound && Backend == backend::ext_intel_esimd_emulator) {
333  PluginNames.emplace_back(__SYCL_ESIMD_EMULATOR_PLUGIN_NAME,
334  backend::ext_intel_esimd_emulator);
335  EsimdCpuFound = true;
336  }
337  if (!HIPFound &&
338  (Backend == backend::ext_oneapi_hip || Backend == backend::all)) {
339  PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME,
341  HIPFound = true;
342  }
343  if (!NativeCPUFound && (Backend == backend::ext_oneapi_native_cpu ||
344  Backend == backend::all)) {
345  PluginNames.emplace_back(__SYCL_NATIVE_CPU_PLUGIN_NAME,
347  }
348  PluginNames.emplace_back(__SYCL_UR_PLUGIN_NAME, backend::all);
349  }
350  return PluginNames;
351  }
352 #endif // __INTEL_PREVIEW_BREAKING_CHANGES
353  if (!OdsTargetList) {
354  PluginNames.emplace_back(__SYCL_OPENCL_PLUGIN_NAME, backend::opencl);
355  PluginNames.emplace_back(__SYCL_LEVEL_ZERO_PLUGIN_NAME,
357  PluginNames.emplace_back(__SYCL_CUDA_PLUGIN_NAME, backend::ext_oneapi_cuda);
358  PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME, backend::ext_oneapi_hip);
359  PluginNames.emplace_back(__SYCL_UR_PLUGIN_NAME, backend::all);
360  PluginNames.emplace_back(__SYCL_NATIVE_CPU_PLUGIN_NAME,
362 
363  } else {
364  ods_target_list &list = *OdsTargetList;
366  PluginNames.emplace_back(__SYCL_OPENCL_PLUGIN_NAME, backend::opencl);
367  }
369  PluginNames.emplace_back(__SYCL_LEVEL_ZERO_PLUGIN_NAME,
371  }
373  PluginNames.emplace_back(__SYCL_CUDA_PLUGIN_NAME,
375  }
376 #ifndef __INTEL_PREVIEW_BREAKING_CHANGES
377  if (list.backendCompatible(backend::ext_intel_esimd_emulator)) {
378  PluginNames.emplace_back(__SYCL_ESIMD_EMULATOR_PLUGIN_NAME,
379  backend::ext_intel_esimd_emulator);
380  }
381 #endif
383  PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME, backend::ext_oneapi_hip);
384  }
386  PluginNames.emplace_back(__SYCL_NATIVE_CPU_PLUGIN_NAME,
388  }
389  PluginNames.emplace_back(__SYCL_UR_PLUGIN_NAME, backend::all);
390  }
391  return PluginNames;
392 }
393 
394 // Load the Plugin by calling the OS dependent library loading call.
395 // Return the handle to the Library.
396 void *loadPlugin(const std::string &PluginPath) {
397  return loadOsPluginLibrary(PluginPath);
398 }
399 
400 // Unload the given plugin by calling teh OS-specific library unloading call.
401 // \param Library OS-specific library handle created when loading.
402 int unloadPlugin(void *Library) { return unloadOsPluginLibrary(Library); }
403 
404 // Binds all the PI Interface APIs to Plugin Library Function Addresses.
405 // TODO: Remove the 'OclPtr' extension to PI_API.
406 // TODO: Change the functionality such that a single getOsLibraryFuncAddress
407 // call is done to get all Interface API mapping. The plugin interface also
408 // needs to setup infrastructure to route PI_CALLs to the appropriate plugins.
409 // Currently, we bind to a singe plugin.
410 bool bindPlugin(void *Library,
411  const std::shared_ptr<PiPlugin> &PluginInformation) {
412 
413  decltype(::piPluginInit) *PluginInitializeFunction =
414  (decltype(&::piPluginInit))(getOsLibraryFuncAddress(Library,
415  "piPluginInit"));
416  if (PluginInitializeFunction == nullptr)
417  return false;
418 
419  int Err = PluginInitializeFunction(PluginInformation.get());
420 
421  // TODO: Compare Supported versions and check for backward compatibility.
422  // Make sure err is PI_SUCCESS.
423  assert((Err == PI_SUCCESS) && "Unexpected error when binding to Plugin.");
424  (void)Err;
425 
426  // TODO: Return a more meaningful value/enum.
427  return true;
428 }
429 
430 bool trace(TraceLevel Level) {
431  auto TraceLevelMask = SYCLConfig<SYCL_PI_TRACE>::get();
432  return (TraceLevelMask & Level) == Level;
433 }
434 
435 // Initializes all available Plugins.
436 std::vector<PluginPtr> &initialize() {
437  static std::once_flag PluginsInitDone;
438  // std::call_once is blocking all other threads if a thread is already
439  // creating a vector of plugins. So, no additional lock is needed.
440  std::call_once(PluginsInitDone, [&]() {
442  });
444 }
445 
446 // Implementation of this function is OS specific. Please see windows_pi.cpp and
447 // posix_pi.cpp.
448 // TODO: refactor code when support matrix for DPCPP changes and <filesystem> is
449 // available on all supported systems.
450 std::vector<std::tuple<std::string, backend, void *>>
451 loadPlugins(const std::vector<std::pair<std::string, backend>> &&PluginNames);
452 
453 static void initializePlugins(std::vector<PluginPtr> &Plugins) {
454  const std::vector<std::pair<std::string, backend>> PluginNames =
455  findPlugins();
456 
457  if (PluginNames.empty() && trace(PI_TRACE_ALL))
458  std::cerr << "SYCL_PI_TRACE[all]: "
459  << "No Plugins Found." << std::endl;
460 
461  // Get library handles for the list of plugins.
462  std::vector<std::tuple<std::string, backend, void *>> LoadedPlugins =
463  loadPlugins(std::move(PluginNames));
464 
465  bool IsAsanUsed = ProgramManager::getInstance().kernelUsesAsan();
466 
467  for (auto &[Name, Backend, Library] : LoadedPlugins) {
468  std::shared_ptr<PiPlugin> PluginInformation =
469  std::make_shared<PiPlugin>(PiPlugin{
471  /*Targets=*/nullptr, /*FunctionPointers=*/{},
472  /*IsAsanUsed*/
474 
475  if (!Library) {
476  if (trace(PI_TRACE_ALL)) {
477  std::cerr << "SYCL_PI_TRACE[all]: "
478  << "Check if plugin is present. "
479  << "Failed to load plugin: " << Name << std::endl;
480  }
481  continue;
482  }
483 
484  if (!bindPlugin(Library, PluginInformation)) {
485  if (trace(PI_TRACE_ALL)) {
486  std::cerr << "SYCL_PI_TRACE[all]: "
487  << "Failed to bind PI APIs to the plugin: " << Name
488  << std::endl;
489  }
490  continue;
491  }
492  PluginPtr &NewPlugin = Plugins.emplace_back(
493  std::make_shared<plugin>(PluginInformation, Backend, Library));
495  std::cerr << "SYCL_PI_TRACE[basic]: "
496  << "Plugin found and successfully loaded: " << Name
497  << " [ PluginVersion: "
498  << NewPlugin->getPiPlugin().PluginVersion << " ]" << std::endl;
499  }
500 
501 #ifdef XPTI_ENABLE_INSTRUMENTATION
503 
504  if (!(xptiTraceEnabled() && !XPTIInitDone))
505  return;
506  // Not sure this is the best place to initialize the framework; SYCL runtime
507  // team needs to advise on the right place, until then we piggy-back on the
508  // initialization of the PI layer.
509 
510  // Initialize the global events just once, in the case pi::initialize() is
511  // called multiple times
512  XPTIInitDone = true;
513  // Registers a new stream for 'sycl' and any plugin that wants to listen to
514  // this stream will register itself using this string or stream ID for this
515  // string.
516  uint8_t StreamID = xptiRegisterStream(SYCL_STREAM_NAME);
517  // Let all tool plugins know that a stream by the name of 'sycl' has been
518  // initialized and will be generating the trace stream.
521  // Create a tracepoint to indicate the graph creation
522  xpti::payload_t GraphPayload("application_graph");
523  uint64_t GraphInstanceNo;
524  GSYCLGraphEvent =
525  xptiMakeEvent("application_graph", &GraphPayload, xpti::trace_graph_event,
526  xpti_at::active, &GraphInstanceNo);
527  if (GSYCLGraphEvent) {
528  // The graph event is a global event and will be used as the parent for
529  // all nodes (command groups)
530  xptiNotifySubscribers(StreamID, xpti::trace_graph_create, nullptr,
531  GSYCLGraphEvent, GraphInstanceNo, nullptr);
532  }
533 
534  // Let subscribers know a new stream is being initialized
537  xpti::payload_t PIPayload("Plugin Interface Layer");
538  uint64_t PiInstanceNo;
539  GPICallEvent =
540  xptiMakeEvent("PI Layer", &PIPayload, xpti::trace_algorithm_event,
541  xpti_at::active, &PiInstanceNo);
542 
545  xpti::payload_t PIArgPayload(
546  "Plugin Interface Layer (with function arguments)");
547  uint64_t PiArgInstanceNo;
548  GPIArgCallEvent = xptiMakeEvent("PI Layer with arguments", &PIArgPayload,
549  xpti::trace_algorithm_event, xpti_at::active,
550  &PiArgInstanceNo);
551 
552  PiCallStreamID = xptiRegisterStream(SYCL_PICALL_STREAM_NAME);
553  PiDebugCallStreamID = xptiRegisterStream(SYCL_PIDEBUGCALL_STREAM_NAME);
554 #endif
555 }
556 
557 // Get the plugin serving given backend.
558 template <backend BE> const PluginPtr &getPlugin() {
559  static PluginPtr *Plugin = nullptr;
560  if (Plugin)
561  return *Plugin;
562 
563  std::vector<PluginPtr> &Plugins = pi::initialize();
564  for (auto &P : Plugins)
565  if (P->hasBackend(BE)) {
566  Plugin = &P;
567  return *Plugin;
568  }
569 
570  throw runtime_error("pi::getPlugin couldn't find plugin",
571  PI_ERROR_INVALID_OPERATION);
572 }
573 
574 template __SYCL_EXPORT const PluginPtr &getPlugin<backend::opencl>();
575 template __SYCL_EXPORT const PluginPtr &
576 getPlugin<backend::ext_oneapi_level_zero>();
577 template __SYCL_EXPORT const PluginPtr &
578 getPlugin<backend::ext_intel_esimd_emulator>();
579 template __SYCL_EXPORT const PluginPtr &getPlugin<backend::ext_oneapi_cuda>();
580 template __SYCL_EXPORT const PluginPtr &getPlugin<backend::ext_oneapi_hip>();
581 
582 // Report error and no return (keeps compiler from printing warnings).
583 // TODO: Probably change that to throw a catchable exception,
584 // but for now it is useful to see every failure.
585 //
586 [[noreturn]] void die(const char *Message) {
587  std::cerr << "pi_die: " << Message << std::endl;
588  std::terminate();
589 }
590 
591 void assertion(bool Condition, const char *Message) {
592  if (!Condition)
593  die(Message);
594 }
595 
596 // Reads an integer value from ELF data.
597 template <typename ResT>
598 static ResT readELFValue(const unsigned char *Data, size_t NumBytes,
599  bool IsBigEndian) {
600  assert(NumBytes <= sizeof(ResT));
601  ResT Result = 0;
602  if (IsBigEndian) {
603  for (size_t I = 0; I < NumBytes; ++I) {
604  Result = (Result << 8) | static_cast<ResT>(Data[I]);
605  }
606  } else {
607  std::copy(Data, Data + NumBytes, reinterpret_cast<char *>(&Result));
608  }
609  return Result;
610 }
611 
612 // Checks if an ELF image contains a section with a specified name.
613 static bool checkELFSectionPresent(const std::string &ExpectedSectionName,
614  const unsigned char *ImgData,
615  size_t ImgSize) {
616  // Check for 64bit and big-endian.
617  bool Is64bit = ImgData[4] == 2;
618  bool IsBigEndian = ImgData[5] == 2;
619 
620  // Make offsets based on whether the ELF file is 64bit or not.
621  size_t SectionHeaderOffsetInfoOffset = Is64bit ? 0x28 : 0x20;
622  size_t SectionHeaderSizeInfoOffset = Is64bit ? 0x3A : 0x2E;
623  size_t SectionHeaderNumInfoOffset = Is64bit ? 0x3C : 0x30;
624  size_t SectionStringsHeaderIndexInfoOffset = Is64bit ? 0x3E : 0x32;
625 
626  // if the image doesn't contain enough data for the header values, end early.
627  if (ImgSize < SectionStringsHeaderIndexInfoOffset + 2)
628  return false;
629 
630  // Read the e_shoff, e_shentsize, e_shnum, and e_shstrndx entries in the
631  // header.
632  uint64_t SectionHeaderOffset = readELFValue<uint64_t>(
633  ImgData + SectionHeaderOffsetInfoOffset, Is64bit ? 8 : 4, IsBigEndian);
634  uint16_t SectionHeaderSize = readELFValue<uint16_t>(
635  ImgData + SectionHeaderSizeInfoOffset, 2, IsBigEndian);
636  uint16_t SectionHeaderNum = readELFValue<uint16_t>(
637  ImgData + SectionHeaderNumInfoOffset, 2, IsBigEndian);
638  uint16_t SectionStringsHeaderIndex = readELFValue<uint16_t>(
639  ImgData + SectionStringsHeaderIndexInfoOffset, 2, IsBigEndian);
640 
641  // End early if we do not have the expected number of section headers or
642  // if the read section string header index is out-of-range.
643  if (ImgSize < SectionHeaderOffset + SectionHeaderNum * SectionHeaderSize ||
644  SectionStringsHeaderIndex >= SectionHeaderNum)
645  return false;
646 
647  // Get the location of the section string data.
648  size_t SectionStringsInfoOffset = Is64bit ? 0x18 : 0x10;
649  const unsigned char *SectionStringsHeaderData =
650  ImgData + SectionHeaderOffset +
651  SectionStringsHeaderIndex * SectionHeaderSize;
652  uint64_t SectionStrings = readELFValue<uint64_t>(
653  SectionStringsHeaderData + SectionStringsInfoOffset, Is64bit ? 8 : 4,
654  IsBigEndian);
655  const unsigned char *SectionStringsData = ImgData + SectionStrings;
656 
657  // For each section, check the name against the expected section and return
658  // true if we find it.
659  for (size_t I = 0; I < SectionHeaderNum; ++I) {
660  // Get the offset into the section string data of this sections name.
661  const unsigned char *HeaderData =
662  ImgData + SectionHeaderOffset + I * SectionHeaderSize;
663  uint32_t SectionNameOffset =
664  readELFValue<uint32_t>(HeaderData, 4, IsBigEndian);
665 
666  // Read the section name and check if it is the same as the name we are
667  // looking for.
668  const char *SectionName =
669  reinterpret_cast<const char *>(SectionStringsData + SectionNameOffset);
670  if (SectionName == ExpectedSectionName)
671  return true;
672  }
673  return false;
674 }
675 
676 // Returns the e_type field from an ELF image.
677 static uint16_t getELFHeaderType(const unsigned char *ImgData, size_t ImgSize) {
678  (void)ImgSize;
679  assert(ImgSize >= 18 && "Not enough bytes to have an ELF header type.");
680 
681  bool IsBigEndian = ImgData[5] == 2;
682  return readELFValue<uint16_t>(ImgData + 16, 2, IsBigEndian);
683 }
684 
686 getBinaryImageFormat(const unsigned char *ImgData, size_t ImgSize) {
687  // Top-level magic numbers for the recognized binary image formats.
688  auto MatchMagicNumber = [&](auto Number) {
689  return ImgSize >= sizeof(Number) &&
690  std::memcmp(ImgData, &Number, sizeof(Number)) == 0;
691  };
692 
693  if (MatchMagicNumber(uint32_t{0x07230203}))
695 
696  if (MatchMagicNumber(uint32_t{0xDEC04342}))
698 
699  if (MatchMagicNumber(uint32_t{0x43544E49}))
700  // 'I', 'N', 'T', 'C' ; Intel native
702 
703  // Check for ELF format, size requirements include data we'll read in case of
704  // succesful match.
705  if (ImgSize >= 18 && MatchMagicNumber(uint32_t{0x464c457F})) {
706  uint16_t ELFHdrType = getELFHeaderType(ImgData, ImgSize);
707  if (ELFHdrType == 0xFF04)
708  // OpenCL executable.
710 
711  if (ELFHdrType == 0xFF12)
712  // ZEBIN executable.
714 
715  // Newer ZEBIN format does not have a special header type, but can instead
716  // be identified by having a required .ze_info section.
717  if (checkELFSectionPresent(".ze_info", ImgData, ImgSize))
719  }
720 
721  if (MatchMagicNumber(std::array{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}))
722  // "ar" format is used to pack binaries for multiple devices, e.g. via
723  //
724  // -Xsycl-target-backend=spir64_gen "-device acm-g10,acm-g11"
725  //
726  // option.
728 
730 }
731 
732 } // namespace pi
733 } // namespace detail
734 } // namespace _V1
735 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:51
std::vector< PluginPtr > & getPlugins()
static GlobalHandler & instance()
static ProgramManager & getInstance()
static const char * get()
Definition: config.hpp:115
void initializeStream(const std::string &StreamName, uint32_t MajVer, uint32_t MinVer, const std::string &VerStr)
Notifies XPTI subscribers about new stream.
std::vector< device_filter > & get()
bool backendCompatible(backend Backend)
Data type that manages the code_location information in TLS.
Definition: common.hpp:129
const detail::code_location & query()
Query the information in the TLS slot.
Definition: common.cpp:55
__SYCL_EXTERN_STREAM_ATTRS ostream cerr
Linked to standard error (unbuffered)
std::string memFlagToString(pi_mem_flags Flag)
Definition: pi.cpp:222
static bool checkELFSectionPresent(const std::string &ExpectedSectionName, const unsigned char *ImgData, size_t ImgSize)
Definition: pi.cpp:613
void contextSetExtendedDeleter(const sycl::context &constext, pi_context_extended_deleter func, void *user_data)
Definition: pi.cpp:193
std::string memFlagsToString(pi_mem_flags Flags)
Definition: pi.cpp:248
void emitFunctionEndTrace(uint64_t CorrelationID, const char *FName)
Emits an XPTI trace after the PI API call has been made.
Definition: pi.cpp:127
static void initializePlugins(std::vector< PluginPtr > &Plugins)
Definition: pi.cpp:453
void * loadOsPluginLibrary(const std::string &Library)
Definition: posix_pi.cpp:33
std::vector< PluginPtr > & initialize()
Definition: pi.cpp:436
void die(const char *Message)
Definition: pi.cpp:586
uint64_t emitFunctionBeginTrace(const char *FName)
Emits an XPTI trace before a PI API call is made.
Definition: pi.cpp:82
void assertion(bool Condition, const char *Message=nullptr)
Definition: pi.cpp:591
std::vector< std::pair< std::string, backend > > findPlugins()
Definition: pi.cpp:286
void * loadPlugin(const std::string &PluginPath)
Definition: pi.cpp:396
PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData, size_t ImgSize)
Tries to determine the device binary image foramat.
Definition: pi.cpp:686
bool trace(TraceLevel level)
Definition: pi.cpp:430
static ResT readELFValue(const unsigned char *Data, size_t NumBytes, bool IsBigEndian)
Definition: pi.cpp:598
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
std::string platformInfoToString(pi_platform_info info)
Definition: pi.cpp:203
std::shared_ptr< plugin > GlobalPlugin
Definition: pi.cpp:283
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
bool bindPlugin(void *Library, const std::shared_ptr< PiPlugin > &PluginInformation)
Definition: pi.cpp:410
static uint16_t getELFHeaderType(const unsigned char *ImgData, size_t ImgSize)
Definition: pi.cpp:677
::pi_device_binary_type PiDeviceBinaryType
Definition: pi.hpp:134
void * getOsLibraryFuncAddress(void *Library, const std::string &FunctionName)
Definition: posix_pi.cpp:47
int unloadOsPluginLibrary(void *Library)
Definition: posix_pi.cpp:39
std::vector< std::tuple< std::string, backend, void * > > loadPlugins(const std::vector< std::pair< std::string, backend >> &&PluginNames)
Definition: posix_pi.cpp:53
int unloadPlugin(void *Library)
Definition: pi.cpp:402
constexpr const char * SYCL_PIDEBUGCALL_STREAM_NAME
constexpr const char * SYCL_STREAM_NAME
static const PluginPtr & getPlugin(backend Backend)
Definition: backend.cpp:32
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:30
void * getPluginOpaqueData(void *opaquedata_arg)
Definition: pi.cpp:61
std::shared_ptr< plugin > PluginPtr
Definition: pi.hpp:48
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:94
Definition: access.hpp:18
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE
Definition: pi.h:918
_pi_result
Definition: pi.h:211
#define _PI_H_VERSION_STRING
Definition: pi.h:171
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_NATIVE
Definition: pi.h:913
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:1194
_pi_platform_info
Definition: pi.h:226
@ PI_PLATFORM_INFO_VENDOR
Definition: pi.h:230
@ PI_PLATFORM_INFO_EXTENSIONS
Definition: pi.h:227
@ PI_PLATFORM_INFO_PROFILE
Definition: pi.h:229
@ PI_EXT_PLATFORM_INFO_BACKEND
Definition: pi.h:232
@ PI_PLATFORM_INFO_NAME
Definition: pi.h:228
@ PI_PLATFORM_INFO_VERSION
Definition: pi.h:231
constexpr pi_mem_flags PI_MEM_FLAGS_HOST_PTR_COPY
Definition: pi.h:735
pi_bitfield pi_mem_flags
Definition: pi.h:729
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_SPIRV
Definition: pi.h:916
constexpr pi_mem_flags PI_MEM_FLAGS_HOST_PTR_USE
Definition: pi.h:734
void(* pi_context_extended_deleter)(void *user_data)
Definition: pi.h:1308
pi_result piPluginInit(pi_plugin *plugin_info)
Definition: pi_cuda.cpp:1231
@ _PI_SANITIZE_TYPE_ADDRESS
Definition: pi.h:2802
@ _PI_SANITIZE_TYPE_NONE
Definition: pi.h:2801
constexpr pi_mem_flags PI_MEM_FLAGS_ACCESS_RW
Definition: pi.h:731
pi_result piextContextSetExtendedDeleter(pi_context context, pi_context_extended_deleter func, void *user_data)
Definition: pi_cuda.cpp:132
static constexpr pi_device_binary_type PI_DEVICE_BINARY_TYPE_NONE
Definition: pi.h:911
C++ wrapper of extern "C" PI interfaces.
constexpr int GMajVer
Definition: tracing.cpp:27
constexpr int GMinVer
Definition: tracing.cpp:28
constexpr auto GVerStr
Definition: tracing.cpp:26