DPC++ Runtime
Runtime libraries for oneAPI DPC++
ur.hpp
Go to the documentation of this file.
1 //===--------- ur.hpp - Unified Runtime ----------------------------------===//
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 #pragma once
9 
10 #include <atomic>
11 #include <cassert>
12 #include <cstdint>
13 #include <cstring>
14 #include <functional>
15 #include <iostream>
16 #include <mutex>
17 #include <shared_mutex>
18 #include <string>
19 #include <thread>
20 #include <vector>
21 
22 #include <ur_api.h>
23 
24 template <class To, class From> To ur_cast(From Value) {
25  // TODO: see if more sanity checks are possible.
26  assert(sizeof(From) == sizeof(To));
27  return (To)(Value);
28 }
29 
30 template <> uint32_t inline ur_cast(uint64_t Value) {
31  // Cast value and check that we don't lose any information.
32  uint32_t CastedValue = (uint32_t)(Value);
33  assert((uint64_t)CastedValue == Value);
34  return CastedValue;
35 }
36 
37 // TODO: promote all of the below extensions to the Unified Runtime
38 // and get rid of these ZER_EXT constants.
39 const ur_device_info_t UR_EXT_DEVICE_INFO_OPENCL_C_VERSION =
40  (ur_device_info_t)0x103D;
41 
42 const ur_command_t UR_EXT_COMMAND_TYPE_USER =
43  (ur_command_t)((uint32_t)UR_COMMAND_FORCE_UINT32 - 1);
44 
47 #define __SYCL_UR_PROGRAM_METADATA_TAG_REQD_WORK_GROUP_SIZE \
48  "@reqd_work_group_size"
49 #define __SYCL_UR_PROGRAM_METADATA_GLOBAL_ID_MAPPING "@global_id_mapping"
50 
51 // Terminates the process with a catastrophic error message.
52 [[noreturn]] inline void die(const char *Message) {
53  std::cerr << "die: " << Message << std::endl;
54  std::terminate();
55 }
56 
57 // A single-threaded app has an opportunity to enable this mode to avoid
58 // overhead from mutex locking. Default value is 0 which means that single
59 // thread mode is disabled.
60 static const bool SingleThreadMode = [] {
61  const char *UrRet = std::getenv("UR_L0_SINGLE_THREAD_MODE");
62  const char *PiRet = std::getenv("SYCL_PI_LEVEL_ZERO_SINGLE_THREAD_MODE");
63  const bool RetVal = UrRet ? std::stoi(UrRet) : (PiRet ? std::stoi(PiRet) : 0);
64  return RetVal;
65 }();
66 
67 // Class which acts like shared_mutex if SingleThreadMode variable is not set.
68 // If SingleThreadMode variable is set then mutex operations are turned into
69 // nop.
71  std::shared_mutex Mutex;
72 
73 public:
74  void lock() {
75  if (!SingleThreadMode)
76  Mutex.lock();
77  }
78  bool try_lock() { return SingleThreadMode ? true : Mutex.try_lock(); }
79  void unlock() {
80  if (!SingleThreadMode)
81  Mutex.unlock();
82  }
83 
84  void lock_shared() {
85  if (!SingleThreadMode)
86  Mutex.lock_shared();
87  }
88  bool try_lock_shared() {
89  return SingleThreadMode ? true : Mutex.try_lock_shared();
90  }
91  void unlock_shared() {
92  if (!SingleThreadMode)
93  Mutex.unlock_shared();
94  }
95 };
96 
97 // Class which acts like std::mutex if SingleThreadMode variable is not set.
98 // If SingleThreadMode variable is set then mutex operations are turned into
99 // nop.
100 class ur_mutex {
101  std::mutex Mutex;
102 
103 public:
104  void lock() {
105  if (!SingleThreadMode)
106  Mutex.lock();
107  }
108  bool try_lock() { return SingleThreadMode ? true : Mutex.try_lock(); }
109  void unlock() {
110  if (!SingleThreadMode)
111  Mutex.unlock();
112  }
113 };
114 
123 class SpinLock {
124 public:
125  void lock() {
126  while (MLock.test_and_set(std::memory_order_acquire))
127  std::this_thread::yield();
128  }
129  void unlock() { MLock.clear(std::memory_order_release); }
130 
131 private:
132  std::atomic_flag MLock = ATOMIC_FLAG_INIT;
133 };
134 
135 // The wrapper for immutable data.
136 // The data is initialized only once at first access (via ->) with the
137 // initialization function provided in Init. All subsequent access to
138 // the data just returns the already stored data.
139 //
140 template <class T> struct ZeCache : private T {
141  // The initialization function takes a reference to the data
142  // it is going to initialize, since it is private here in
143  // order to disallow access other than through "->".
144  //
145  using InitFunctionType = std::function<void(T &)>;
147  std::once_flag Computed;
148 
149  ZeCache() : T{} {}
150 
151  // Access to the fields of the original T data structure.
152  T *operator->() {
153  std::call_once(Computed, Compute, static_cast<T &>(*this));
154  return this;
155  }
156 };
157 
158 // Helper for one-liner validation
159 #define UR_ASSERT(condition, error) \
160  if (!(condition)) \
161  return error;
162 
163 // TODO: populate with target agnostic handling of UR platforms
164 struct _ur_platform {};
165 
166 // Controls tracing UR calls from within the UR itself.
167 extern bool PrintTrace;
168 
169 // Apparatus for maintaining immutable cache of platforms.
170 //
171 // Note we only create a simple pointer variables such that C++ RT won't
172 // deallocate them automatically at the end of the main program.
173 // The heap memory allocated for these global variables reclaimed only at
174 // explicit tear-down.
175 extern std::vector<ur_platform_handle_t> *URPlatformsCache;
177 extern bool URPlatformCachePopulated;
178 
179 // The getInfo*/ReturnHelper facilities provide shortcut way of
180 // writing return bytes for the various getInfo APIs.
181 namespace ur {
182 template <typename T, typename Assign>
183 ur_result_t getInfoImpl(size_t param_value_size, void *param_value,
184  size_t *param_value_size_ret, T value,
185  size_t value_size, Assign &&assign_func) {
186  if (!param_value && !param_value_size_ret) {
187  return UR_RESULT_ERROR_INVALID_NULL_POINTER;
188  }
189 
190  if (param_value != nullptr) {
191 
192  if (param_value_size < value_size) {
193  return UR_RESULT_ERROR_INVALID_SIZE;
194  }
195 
196  assign_func(param_value, value, value_size);
197  }
198 
199  if (param_value_size_ret != nullptr) {
200  *param_value_size_ret = value_size;
201  }
202 
203  return UR_RESULT_SUCCESS;
204 }
205 
206 template <typename T>
207 ur_result_t getInfo(size_t param_value_size, void *param_value,
208  size_t *param_value_size_ret, T value) {
209 
210  auto assignment = [](void *param_value, T value, size_t value_size) {
211  std::ignore = value_size;
212  *static_cast<T *>(param_value) = value;
213  };
214 
215  return getInfoImpl(param_value_size, param_value, param_value_size_ret, value,
216  sizeof(T), assignment);
217 }
218 
219 template <typename T>
220 ur_result_t getInfoArray(size_t array_length, size_t param_value_size,
221  void *param_value, size_t *param_value_size_ret,
222  const T *value) {
223  return getInfoImpl(param_value_size, param_value, param_value_size_ret, value,
224  array_length * sizeof(T), memcpy);
225 }
226 
227 template <typename T, typename RetType>
228 ur_result_t getInfoArray(size_t array_length, size_t param_value_size,
229  void *param_value, size_t *param_value_size_ret,
230  const T *value) {
231  if (param_value) {
232  memset(param_value, 0, param_value_size);
233  for (uint32_t I = 0; I < array_length; I++)
234  ((RetType *)param_value)[I] = (RetType)value[I];
235  }
236  if (param_value_size_ret)
237  *param_value_size_ret = array_length * sizeof(RetType);
238  return UR_RESULT_SUCCESS;
239 }
240 
241 template <>
242 inline ur_result_t
243 getInfo<const char *>(size_t param_value_size, void *param_value,
244  size_t *param_value_size_ret, const char *value) {
245  return getInfoArray(strlen(value) + 1, param_value_size, param_value,
246  param_value_size_ret, value);
247 }
248 } // namespace ur
249 
251 public:
253  size_t *param_value_size_ret)
256 
257  // A version where in/out info size is represented by a single pointer
258  // to a value which is updated on return
262 
263  // Scalar return value
264  template <class T> ur_result_t operator()(const T &t) {
266  }
267 
268  // Array return value
269  template <class T> ur_result_t operator()(const T *t, size_t s) {
272  }
273 
274  // Array return value where element type is differrent from T
275  template <class RetType, class T>
276  ur_result_t operator()(const T *t, size_t s) {
277  return ur::getInfoArray<T, RetType>(s, param_value_size, param_value,
279  }
280 
281 protected:
283  void *param_value;
285 };
ur::getInfoArray
ur_result_t getInfoArray(size_t array_length, size_t param_value_size, void *param_value, size_t *param_value_size_ret, const T *value)
Definition: ur.hpp:220
T
ur::getInfo
ur_result_t getInfo(size_t param_value_size, void *param_value, size_t *param_value_size_ret, T value)
Definition: ur.hpp:207
SpinLock::lock
void lock()
Definition: ur.hpp:125
ur::getInfoImpl
ur_result_t getInfoImpl(size_t param_value_size, void *param_value, size_t *param_value_size_ret, T value, size_t value_size, Assign &&assign_func)
Definition: ur.hpp:183
syclcompat::detail::memset
static sycl::event memset(sycl::queue q, void *dev_ptr, int value, size_t size)
Set value to the first size bytes starting from dev_ptr in q.
Definition: memory.hpp:202
URPlatformCachePopulated
bool URPlatformCachePopulated
Definition: ur.cpp:28
sycl::_V1::detail::memcpy
void memcpy(void *Dst, const void *Src, size_t Size)
Definition: memcpy.hpp:16
ur::getInfo< const char * >
ur_result_t getInfo< const char * >(size_t param_value_size, void *param_value, size_t *param_value_size_ret, const char *value)
Definition: ur.hpp:243
ZeCache::ZeCache
ZeCache()
Definition: ur.hpp:149
sycl
Definition: access.hpp:18
UrReturnHelper::operator()
ur_result_t operator()(const T *t, size_t s)
Definition: ur.hpp:269
sycl::_V1::memory_order_acquire
constexpr auto memory_order_acquire
Definition: memory_enums.hpp:44
ZeCache::Computed
std::once_flag Computed
Definition: ur.hpp:147
ur_shared_mutex
Definition: ur.hpp:70
ZeCache::operator->
T * operator->()
Definition: ur.hpp:152
ur_cast
To ur_cast(From Value)
Definition: ur.hpp:24
ur_mutex::try_lock
bool try_lock()
Definition: ur.hpp:108
ur_shared_mutex::unlock_shared
void unlock_shared()
Definition: ur.hpp:91
SingleThreadMode
static const bool SingleThreadMode
Definition: ur.hpp:60
ZeCache< ZeStruct< ze_device_memory_access_properties_t > >::InitFunctionType
std::function< void(ZeStruct< ze_device_memory_access_properties_t > &)> InitFunctionType
Definition: ur.hpp:145
UrReturnHelper::UrReturnHelper
UrReturnHelper(size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Definition: ur.hpp:252
ur_mutex
Definition: ur.hpp:100
PrintTrace
bool PrintTrace
Definition: ur.cpp:14
ZeCache
Definition: ur.hpp:140
std::cerr
__SYCL_EXTERN_STREAM_ATTRS ostream cerr
Linked to standard error (unbuffered)
UrReturnHelper::param_value
void * param_value
Definition: ur.hpp:283
ur_mutex::unlock
void unlock()
Definition: ur.hpp:109
ur_shared_mutex::lock
void lock()
Definition: ur.hpp:74
ZeCache::Compute
InitFunctionType Compute
Definition: ur.hpp:146
_ur_platform
Definition: ur.hpp:164
ur_shared_mutex::lock_shared
void lock_shared()
Definition: ur.hpp:84
UrReturnHelper::param_value_size_ret
size_t * param_value_size_ret
Definition: ur.hpp:284
UrReturnHelper::UrReturnHelper
UrReturnHelper(size_t *param_value_size, void *param_value)
Definition: ur.hpp:259
ur_shared_mutex::try_lock
bool try_lock()
Definition: ur.hpp:78
ur_mutex::lock
void lock()
Definition: ur.hpp:104
ur
Definition: ur.hpp:181
UR_EXT_DEVICE_INFO_OPENCL_C_VERSION
const ur_device_info_t UR_EXT_DEVICE_INFO_OPENCL_C_VERSION
Definition: ur.hpp:39
URPlatformsCacheMutex
SpinLock * URPlatformsCacheMutex
Definition: ur.cpp:27
SpinLock
SpinLock is a synchronization primitive, that uses atomic variable and causes thread trying acquire l...
Definition: ur.hpp:123
UrReturnHelper::operator()
ur_result_t operator()(const T &t)
Definition: ur.hpp:264
ur_shared_mutex::unlock
void unlock()
Definition: ur.hpp:79
URPlatformsCache
std::vector< ur_platform_handle_t > * URPlatformsCache
Definition: ur.cpp:25
SpinLock::unlock
void unlock()
Definition: ur.hpp:129
ur_shared_mutex::try_lock_shared
bool try_lock_shared()
Definition: ur.hpp:88
UrReturnHelper
Definition: ur.hpp:250
die
void die(const char *Message)
Definition: ur.hpp:52
UrReturnHelper::operator()
ur_result_t operator()(const T *t, size_t s)
Definition: ur.hpp:276
UR_EXT_COMMAND_TYPE_USER
const ur_command_t UR_EXT_COMMAND_TYPE_USER
Definition: ur.hpp:42
sycl::_V1::memory_order_release
constexpr auto memory_order_release
Definition: memory_enums.hpp:45
UrReturnHelper::param_value_size
size_t param_value_size
Definition: ur.hpp:282