DPC++ Runtime
Runtime libraries for oneAPI Data Parallel C++
plugin.hpp
Go to the documentation of this file.
1 //==------------------------- plugin.hpp - SYCL platform -------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #pragma once
12 #include <CL/sycl/detail/pi.hpp>
14 #include <CL/sycl/stl.hpp>
16 #include <memory>
17 #include <mutex>
18 
19 #ifdef XPTI_ENABLE_INSTRUMENTATION
20 // Include the headers necessary for emitting traces using the trace framework
21 #include "xpti/xpti_trace_framework.h"
22 #endif
23 
25 namespace sycl {
26 namespace detail {
27 #ifdef XPTI_ENABLE_INSTRUMENTATION
28 extern xpti::trace_event_data_t *GPICallEvent;
29 extern xpti::trace_event_data_t *GPIArgCallEvent;
30 #endif
31 
32 template <PiApiKind Kind, size_t Idx, typename... Args>
34 
35 template <PiApiKind Kind> struct PiApiArgTuple;
36 
37 #define _PI_API(api) \
38  template <> struct PiApiArgTuple<PiApiKind::api> { \
39  using type = typename function_traits<decltype(api)>::args_type; \
40  };
41 
42 #include <CL/sycl/detail/pi.def>
43 #undef _PI_API
44 
45 template <PiApiKind Kind, size_t Idx, typename T>
46 struct array_fill_helper<Kind, Idx, T> {
47  static void fill(unsigned char *Dst, T &&Arg) {
48  using ArgsTuple = typename PiApiArgTuple<Kind>::type;
49  // C-style cast is required here.
50  auto RealArg = (std::tuple_element_t<Idx, ArgsTuple>)(Arg);
51  *(std::remove_cv_t<std::tuple_element_t<Idx, ArgsTuple>> *)Dst = RealArg;
52  }
53 };
54 
55 template <PiApiKind Kind, size_t Idx, typename T, typename... Args>
56 struct array_fill_helper<Kind, Idx, T, Args...> {
57  static void fill(unsigned char *Dst, const T &&Arg, Args &&... Rest) {
58  using ArgsTuple = typename PiApiArgTuple<Kind>::type;
59  // C-style cast is required here.
60  auto RealArg = (std::tuple_element_t<Idx, ArgsTuple>)(Arg);
61  *(std::remove_cv_t<std::tuple_element_t<Idx, ArgsTuple>> *)Dst = RealArg;
63  Dst + sizeof(decltype(RealArg)), std::forward<Args>(Rest)...);
64  }
65 };
66 
67 template <typename... Ts>
68 constexpr size_t totalSize(const std::tuple<Ts...> &) {
69  return (sizeof(Ts) + ...);
70 }
71 
72 template <PiApiKind Kind, typename... ArgsT>
73 auto packCallArguments(ArgsT &&... Args) {
74  using ArgsTuple = typename PiApiArgTuple<Kind>::type;
75 
76  constexpr size_t TotalSize = totalSize(ArgsTuple{});
77 
78  std::array<unsigned char, TotalSize> ArgsData;
80  std::forward<ArgsT>(Args)...);
81 
82  return ArgsData;
83 }
84 
89 class plugin {
90 public:
91  plugin() = delete;
92  plugin(const std::shared_ptr<RT::PiPlugin> &Plugin, backend UseBackend,
93  void *LibraryHandle)
94  : MPlugin(Plugin), MBackend(UseBackend), MLibraryHandle(LibraryHandle),
95  TracingMutex(std::make_shared<std::mutex>()),
96  MPluginMutex(std::make_shared<std::mutex>()) {}
97 
98  plugin &operator=(const plugin &) = default;
99  plugin(const plugin &) = default;
100  plugin &operator=(plugin &&other) noexcept = default;
101  plugin(plugin &&other) noexcept = default;
102 
103  ~plugin() = default;
104 
105  const RT::PiPlugin &getPiPlugin() const { return *MPlugin; }
106  RT::PiPlugin &getPiPlugin() { return *MPlugin; }
107  const std::shared_ptr<RT::PiPlugin> &getPiPluginPtr() const {
108  return MPlugin;
109  }
110 
114  template <typename Exception = cl::sycl::runtime_error>
117  }
118 
120  template <sycl::errc errc> void checkPiResult(RT::PiResult pi_result) const {
122  }
123 
124  void reportPiError(RT::PiResult pi_result, const char *context) const {
125  if (pi_result != PI_SUCCESS) {
126  throw cl::sycl::runtime_error(
127  std::string(context) + " API failed with error: " +
129  pi_result);
130  }
131  }
132 
143 
144  template <PiApiKind PiApiOffset, typename... ArgsT>
145  RT::PiResult call_nocheck(ArgsT... Args) const {
146  RT::PiFuncInfo<PiApiOffset> PiCallInfo;
147 #ifdef XPTI_ENABLE_INSTRUMENTATION
148  // Emit a function_begin trace for the PI API before the call is executed.
149  // If arguments need to be captured, then a data structure can be sent in
150  // the per_instance_user_data field.
151  const char *PIFnName = PiCallInfo.getFuncName();
152  uint64_t CorrelationID = pi::emitFunctionBeginTrace(PIFnName);
153  auto ArgsData =
154  packCallArguments<PiApiOffset>(std::forward<ArgsT>(Args)...);
155  uint64_t CorrelationIDWithArgs =
156  pi::emitFunctionWithArgsBeginTrace(static_cast<uint32_t>(PiApiOffset),
157  PIFnName, ArgsData.data(), *MPlugin);
158 #endif
159  RT::PiResult R;
161  std::lock_guard<std::mutex> Guard(*TracingMutex);
162  const char *FnName = PiCallInfo.getFuncName();
163  std::cout << "---> " << FnName << "(" << std::endl;
164  RT::printArgs(Args...);
165  R = PiCallInfo.getFuncPtr(*MPlugin)(Args...);
166  std::cout << ") ---> ";
167  RT::printArgs(R);
168  RT::printOuts(Args...);
169  std::cout << std::endl;
170  } else {
171  R = PiCallInfo.getFuncPtr(*MPlugin)(Args...);
172  }
173 #ifdef XPTI_ENABLE_INSTRUMENTATION
174  // Close the function begin with a call to function end
175  pi::emitFunctionEndTrace(CorrelationID, PIFnName);
176  pi::emitFunctionWithArgsEndTrace(CorrelationIDWithArgs,
177  static_cast<uint32_t>(PiApiOffset),
178  PIFnName, ArgsData.data(), R, *MPlugin);
179 #endif
180  return R;
181  }
182 
186  template <PiApiKind PiApiOffset, typename... ArgsT>
187  void call(ArgsT... Args) const {
188  RT::PiResult Err = call_nocheck<PiApiOffset>(Args...);
189  checkPiResult(Err);
190  }
191 
193  template <sycl::errc errc, PiApiKind PiApiOffset, typename... ArgsT>
194  void call(ArgsT... Args) const {
195  RT::PiResult Err = call_nocheck<PiApiOffset>(Args...);
196  checkPiResult<errc>(Err);
197  }
198 
199  backend getBackend(void) const { return MBackend; }
200  void *getLibraryHandle() const { return MLibraryHandle; }
201  void *getLibraryHandle() { return MLibraryHandle; }
202  int unload() { return RT::unloadPlugin(MLibraryHandle); }
203 
204  // return the index of PiPlatforms.
205  // If not found, add it and return its index.
206  // The function is expected to be called in a thread safe manner.
208  auto It = std::find(PiPlatforms.begin(), PiPlatforms.end(), Platform);
209  if (It != PiPlatforms.end())
210  return It - PiPlatforms.begin();
211 
212  PiPlatforms.push_back(Platform);
213  LastDeviceIds.push_back(0);
214  return PiPlatforms.size() - 1;
215  }
216 
217  // Device ids are consecutive across platforms within a plugin.
218  // We need to return the same starting index for the given platform.
219  // So, instead of returing the last device id of the given platform,
220  // return the last device id of the predecessor platform.
221  // The function is expected to be called in a thread safe manner.
223  int PlatformId = getPlatformId(Platform);
224  if (PlatformId == 0)
225  return 0;
226  return LastDeviceIds[PlatformId - 1];
227  }
228 
229  // set the id of the last device for the given platform
230  // The function is expected to be called in a thread safe manner.
231  void setLastDeviceId(RT::PiPlatform Platform, int Id) {
232  int PlatformId = getPlatformId(Platform);
233  LastDeviceIds[PlatformId] = Id;
234  }
235 
237  auto It = std::find(PiPlatforms.begin(), PiPlatforms.end(), Platform);
238  return It != PiPlatforms.end();
239  }
240 
241  std::shared_ptr<std::mutex> getPluginMutex() { return MPluginMutex; }
242 
243 private:
244  std::shared_ptr<RT::PiPlugin> MPlugin;
245  backend MBackend;
246  void *MLibraryHandle; // the handle returned from dlopen
247  std::shared_ptr<std::mutex> TracingMutex;
248  // Mutex to guard PiPlatforms and LastDeviceIds.
249  // Note that this is a temporary solution until we implement the global
250  // Device/Platform cache later.
251  std::shared_ptr<std::mutex> MPluginMutex;
252  // vector of PiPlatforms that belong to this plugin
253  std::vector<RT::PiPlatform> PiPlatforms;
254  // represents the unique ids of the last device of each platform
255  // index of this vector corresponds to the index in PiPlatforms vector.
256  std::vector<int> LastDeviceIds;
257 }; // class plugin
258 } // namespace detail
259 } // namespace sycl
260 } // __SYCL_INLINE_NAMESPACE(cl)
cl::sycl::backend
backend
Definition: backend_types.hpp:21
PI_SUCCESS
@ PI_SUCCESS
Definition: pi.h:82
__SYCL_CHECK_CODE_THROW_VIA_ERRC
#define __SYCL_CHECK_CODE_THROW_VIA_ERRC(X, ERRC)
Definition: common.hpp:178
cl::sycl::detail::plugin::call
void call(ArgsT... Args) const
Definition: plugin.hpp:194
type_traits.hpp
cl::sycl::detail::plugin::setLastDeviceId
void setLastDeviceId(RT::PiPlatform Platform, int Id)
Definition: plugin.hpp:231
stl.hpp
cl::sycl::detail::PiApiArgTuple
Definition: plugin.hpp:35
_pi_plugin
Definition: pi.h:1739
_pi_result
_pi_result
Definition: pi.h:81
cl::sycl::errc
errc
Definition: exception.hpp:27
cl::sycl::detail::plugin::getLibraryHandle
void * getLibraryHandle()
Definition: plugin.hpp:201
cl::sycl::detail::totalSize
constexpr size_t totalSize(const std::tuple< Ts... > &)
Definition: plugin.hpp:68
cl::sycl::detail::plugin::getPiPlugin
const RT::PiPlugin & getPiPlugin() const
Definition: plugin.hpp:105
cl::sycl::detail::pi::unloadPlugin
int unloadPlugin(void *Library)
Definition: pi.cpp:341
_pi_platform
A PI platform stores all known PI devices, in the CUDA plugin this is just a vector of available devi...
Definition: pi_cuda.hpp:62
cl::sycl::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:131
cl::sycl::detail::pi::PiFuncInfo
Definition: pi.hpp:163
pi.hpp
cl::sycl::detail::plugin::call_nocheck
RT::PiResult call_nocheck(ArgsT... Args) const
Calls the PiApi, traces the call, and returns the result.
Definition: plugin.hpp:145
cl::sycl::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:146
cl::sycl::detail::plugin::getPiPlugin
RT::PiPlugin & getPiPlugin()
Definition: plugin.hpp:106
cl::sycl::detail::pi::emitFunctionBeginTrace
uint64_t emitFunctionBeginTrace(const char *FName)
Emits an XPTI trace before a PI API call is made.
Definition: pi.cpp:87
cl::sycl::detail::PiApiKind
PiApiKind
Definition: pi.hpp:42
plugin_printers.hpp
cl::sycl::detail::pi::printArgs
void printArgs(void)
Definition: plugin_printers.hpp:122
cl::sycl::detail::plugin::getBackend
backend getBackend(void) const
Definition: plugin.hpp:199
cl::sycl::detail::plugin::getLibraryHandle
void * getLibraryHandle() const
Definition: plugin.hpp:200
cl::sycl::detail::array_fill_helper
Definition: plugin.hpp:33
cl::sycl::detail::plugin::getPluginMutex
std::shared_ptr< std::mutex > getPluginMutex()
Definition: plugin.hpp:241
cl::sycl::detail::packCallArguments
auto packCallArguments(ArgsT &&... Args)
Definition: plugin.hpp:73
cl::sycl::detail::plugin::plugin
plugin(const std::shared_ptr< RT::PiPlugin > &Plugin, backend UseBackend, void *LibraryHandle)
Definition: plugin.hpp:92
cl::sycl::detail::plugin::call
void call(ArgsT... Args) const
Calls the API, traces the call, checks the result.
Definition: plugin.hpp:187
cl
We provide new interfaces for matrix muliply in this patch:
Definition: access.hpp:13
cl::sycl::detail::plugin::getStartingDeviceId
int getStartingDeviceId(RT::PiPlatform Platform)
Definition: plugin.hpp:222
cl::sycl::detail::plugin
The plugin class provides a unified interface to the underlying low-level runtimes for the device-agn...
Definition: plugin.hpp:89
cl::sycl::detail::pi::printOuts
void printOuts(void)
Definition: plugin_printers.hpp:171
cl::sycl::detail::pi::PI_TRACE_CALLS
@ PI_TRACE_CALLS
Definition: pi.hpp:57
cl::sycl::detail::plugin::getPlatformId
int getPlatformId(RT::PiPlatform Platform)
Definition: plugin.hpp:207
cl::sycl::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:166
cl::sycl::detail::plugin::unload
int unload()
Definition: plugin.hpp:202
backend_types.hpp
cl::sycl::detail::plugin::checkPiResult
void checkPiResult(RT::PiResult pi_result) const
Checks return value from PI calls.
Definition: plugin.hpp:115
cl::sycl::detail::array_fill_helper< Kind, Idx, T, Args... >::fill
static void fill(unsigned char *Dst, const T &&Arg, Args &&... Rest)
Definition: plugin.hpp:57
std
Definition: accessor.hpp:2397
cl::sycl::detail::array_fill_helper< Kind, Idx, T >::fill
static void fill(unsigned char *Dst, T &&Arg)
Definition: plugin.hpp:47
cl::sycl::detail::codeToString
static std::string codeToString(cl_int code)
Definition: common.hpp:96
cl::sycl::context
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:35
cl::sycl::detail::plugin::containsPiPlatform
bool containsPiPlatform(RT::PiPlatform Platform)
Definition: plugin.hpp:236
cl::sycl::detail::plugin::getPiPluginPtr
const std::shared_ptr< RT::PiPlugin > & getPiPluginPtr() const
Definition: plugin.hpp:107
common.hpp
cl::sycl::detail::plugin::reportPiError
void reportPiError(RT::PiResult pi_result, const char *context) const
Definition: plugin.hpp:124
cl::sycl::detail::pi::trace
bool trace(TraceLevel level)
Definition: pi.cpp:368
__SYCL_CHECK_OCL_CODE_THROW
#define __SYCL_CHECK_OCL_CODE_THROW(X, EXC)
Definition: common.hpp:174
__SYCL_INLINE_NAMESPACE
#define __SYCL_INLINE_NAMESPACE(X)
Definition: defines_elementary.hpp:12