DPC++ Runtime
Runtime libraries for oneAPI Data Parallel C++
platform_impl.cpp
Go to the documentation of this file.
1 //==----------- platform_impl.cpp ------------------------------------------==//
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 #include <CL/sycl/device.hpp>
10 #include <detail/allowlist.hpp>
11 #include <detail/config.hpp>
12 #include <detail/device_impl.hpp>
13 #include <detail/force_device.hpp>
15 #include <detail/platform_impl.hpp>
16 #include <detail/platform_info.hpp>
17 
18 #include <algorithm>
19 #include <cstring>
20 #include <mutex>
21 #include <string>
22 #include <vector>
23 
25 namespace sycl {
26 namespace detail {
27 
28 using PlatformImplPtr = std::shared_ptr<platform_impl>;
29 
30 PlatformImplPtr platform_impl::getHostPlatformImpl() {
31  static PlatformImplPtr HostImpl = std::make_shared<platform_impl>();
32 
33  return HostImpl;
34 }
35 
36 PlatformImplPtr platform_impl::getOrMakePlatformImpl(RT::PiPlatform PiPlatform,
37  const plugin &Plugin) {
38  PlatformImplPtr Result;
39  {
40  const std::lock_guard<std::mutex> Guard(
41  GlobalHandler::instance().getPlatformMapMutex());
42 
43  std::vector<PlatformImplPtr> &PlatformCache =
44  GlobalHandler::instance().getPlatformCache();
45 
46  // If we've already seen this platform, return the impl
47  for (const auto &PlatImpl : PlatformCache) {
48  if (PlatImpl->getHandleRef() == PiPlatform)
49  return PlatImpl;
50  }
51 
52  // Otherwise make the impl
53  Result = std::make_shared<platform_impl>(PiPlatform, Plugin);
54  PlatformCache.emplace_back(Result);
55  }
56 
57  return Result;
58 }
59 
60 PlatformImplPtr platform_impl::getPlatformFromPiDevice(RT::PiDevice PiDevice,
61  const plugin &Plugin) {
62  RT::PiPlatform Plt = nullptr; // TODO catch an exception and put it to list
63  // of asynchronous exceptions
65  sizeof(Plt), &Plt, nullptr);
66  return getOrMakePlatformImpl(Plt, Plugin);
67 }
68 
69 static bool IsBannedPlatform(platform Platform) {
70  // The NVIDIA OpenCL platform is currently not compatible with DPC++
71  // since it is only 1.2 but gets selected by default in many systems
72  // There is also no support on the PTX backend for OpenCL consumption,
73  // and there have been some internal reports.
74  // To avoid problems on default users and deployment of DPC++ on platforms
75  // where CUDA is available, the OpenCL support is disabled.
76  //
77  auto IsNVIDIAOpenCL = [](platform Platform) {
78  if (Platform.is_host())
79  return false;
80 
81  const bool HasCUDA = Platform.get_info<info::platform::name>().find(
82  "NVIDIA CUDA") != std::string::npos;
83  const auto Backend =
84  detail::getSyclObjImpl(Platform)->getPlugin().getBackend();
85  const bool IsCUDAOCL = (HasCUDA && Backend == backend::opencl);
87  std::cout << "SYCL_PI_TRACE[all]: "
88  << "NVIDIA CUDA OpenCL platform found but is not compatible."
89  << std::endl;
90  }
91  return IsCUDAOCL;
92  };
93  return IsNVIDIAOpenCL(Platform);
94 }
95 
96 std::vector<platform> platform_impl::get_platforms() {
97  std::vector<platform> Platforms;
98  std::vector<plugin> &Plugins = RT::initialize();
100  for (plugin &Plugin : Plugins) {
101  pi_uint32 NumPlatforms = 0;
102  // Move to the next plugin if the plugin fails to initialize.
103  // This way platforms from other plugins get a chance to be discovered.
104  if (Plugin.call_nocheck<PiApiKind::piPlatformsGet>(
105  0, nullptr, &NumPlatforms) != PI_SUCCESS)
106  continue;
107 
108  if (NumPlatforms) {
109  std::vector<RT::PiPlatform> PiPlatforms(NumPlatforms);
110  if (Plugin.call_nocheck<PiApiKind::piPlatformsGet>(
111  NumPlatforms, PiPlatforms.data(), nullptr) != PI_SUCCESS)
112  return Platforms;
113 
114  for (const auto &PiPlatform : PiPlatforms) {
115  platform Platform = detail::createSyclObjFromImpl<platform>(
116  getOrMakePlatformImpl(PiPlatform, Plugin));
117  {
118  std::lock_guard<std::mutex> Guard(*Plugin.getPluginMutex());
119  // insert PiPlatform into the Plugin
120  Plugin.getPlatformId(PiPlatform);
121  }
122  // Skip platforms which do not contain requested device types
123  if (!Platform.get_devices(ForcedType).empty() &&
124  !IsBannedPlatform(Platform))
125  Platforms.push_back(Platform);
126  }
127  }
128  }
129 
130  // The host platform should always be available unless not allowed by the
131  // SYCL_DEVICE_FILTER
132  detail::device_filter_list *FilterList =
134  if (!FilterList || FilterList->backendCompatible(backend::host))
135  Platforms.emplace_back(platform());
136 
137  return Platforms;
138 }
139 
140 // Filter out the devices that are not compatible with SYCL_DEVICE_FILTER.
141 // All three entries (backend:device_type:device_num) are optional.
142 // The missing entries are constructed using '*', which means 'any' | 'all'
143 // by the device_filter constructor.
144 // This function matches devices in the order of backend, device_type, and
145 // device_num.
146 static void filterDeviceFilter(std::vector<RT::PiDevice> &PiDevices,
147  RT::PiPlatform Platform) {
149  if (!FilterList)
150  return;
151 
152  std::vector<plugin> &Plugins = RT::initialize();
153  auto It =
154  std::find_if(Plugins.begin(), Plugins.end(), [Platform](plugin &Plugin) {
155  return Plugin.containsPiPlatform(Platform);
156  });
157  if (It == Plugins.end())
158  return;
159 
160  plugin &Plugin = *It;
161  backend Backend = Plugin.getBackend();
162  int InsertIDx = 0;
163  // DeviceIds should be given consecutive numbers across platforms in the same
164  // backend
165  std::lock_guard<std::mutex> Guard(*Plugin.getPluginMutex());
166  int DeviceNum = Plugin.getStartingDeviceId(Platform);
167  for (RT::PiDevice Device : PiDevices) {
168  RT::PiDeviceType PiDevType;
170  sizeof(RT::PiDeviceType),
171  &PiDevType, nullptr);
172  // Assumption here is that there is 1-to-1 mapping between PiDevType and
173  // Sycl device type for GPU, CPU, and ACC.
174  info::device_type DeviceType = pi::cast<info::device_type>(PiDevType);
175 
176  for (const device_filter &Filter : FilterList->get()) {
177  backend FilterBackend = Filter.Backend;
178  // First, match the backend entry
179  if (FilterBackend == Backend || FilterBackend == backend::all) {
180  info::device_type FilterDevType = Filter.DeviceType;
181  // Next, match the device_type entry
182  if (FilterDevType == info::device_type::all) {
183  // Last, match the device_num entry
184  if (!Filter.HasDeviceNum || DeviceNum == Filter.DeviceNum) {
185  PiDevices[InsertIDx++] = Device;
186  break;
187  }
188  } else if (FilterDevType == DeviceType) {
189  if (!Filter.HasDeviceNum || DeviceNum == Filter.DeviceNum) {
190  PiDevices[InsertIDx++] = Device;
191  break;
192  }
193  }
194  }
195  }
196  DeviceNum++;
197  }
198  PiDevices.resize(InsertIDx);
199  // remember the last backend that has gone through this filter function
200  // to assign a unique device id number across platforms that belong to
201  // the same backend. For example, opencl:cpu:0, opencl:acc:1, opencl:gpu:2
202  Plugin.setLastDeviceId(Platform, DeviceNum);
203 }
204 
205 std::shared_ptr<device_impl> platform_impl::getOrMakeDeviceImpl(
206  RT::PiDevice PiDevice, const std::shared_ptr<platform_impl> &PlatformImpl) {
207  const std::lock_guard<std::mutex> Guard(MDeviceMapMutex);
208 
209  // If we've already seen this device, return the impl
210  for (const std::weak_ptr<device_impl> &DeviceWP : MDeviceCache) {
211  if (std::shared_ptr<device_impl> Device = DeviceWP.lock()) {
212  if (Device->getHandleRef() == PiDevice)
213  return Device;
214  }
215  }
216 
217  // Otherwise make the impl
218  std::shared_ptr<device_impl> Result =
219  std::make_shared<device_impl>(PiDevice, PlatformImpl);
220  MDeviceCache.emplace_back(Result);
221 
222  return Result;
223 }
224 
225 std::vector<device>
226 platform_impl::get_devices(info::device_type DeviceType) const {
227  std::vector<device> Res;
228  if (is_host() && (DeviceType == info::device_type::host ||
229  DeviceType == info::device_type::all)) {
230  // If SYCL_DEVICE_FILTER is set, check if filter contains host.
232  if (!FilterList || FilterList->containsHost()) {
233  Res.push_back(device());
234  }
235  }
236 
237  // If any DeviceType other than host was requested for host platform,
238  // an empty vector will be returned.
239  if (is_host() || DeviceType == info::device_type::host)
240  return Res;
241 
242  pi_uint32 NumDevices = 0;
243  const detail::plugin &Plugin = getPlugin();
245  MPlatform, pi::cast<RT::PiDeviceType>(DeviceType), 0,
246  pi::cast<RT::PiDevice *>(nullptr), &NumDevices);
247 
248  if (NumDevices == 0)
249  return Res;
250 
251  std::vector<RT::PiDevice> PiDevices(NumDevices);
252  // TODO catch an exception and put it to list of asynchronous exceptions
253  Plugin.call<PiApiKind::piDevicesGet>(MPlatform,
254  pi::cast<RT::PiDeviceType>(DeviceType),
255  NumDevices, PiDevices.data(), nullptr);
256 
257  // Filter out devices that are not present in the SYCL_DEVICE_ALLOWLIST
259  applyAllowList(PiDevices, MPlatform, Plugin);
260 
261  // Filter out devices that are not compatible with SYCL_DEVICE_FILTER
262  filterDeviceFilter(PiDevices, MPlatform);
263 
264  PlatformImplPtr PlatformImpl = getOrMakePlatformImpl(MPlatform, Plugin);
265  std::transform(
266  PiDevices.begin(), PiDevices.end(), std::back_inserter(Res),
267  [PlatformImpl](const RT::PiDevice &PiDevice) -> device {
268  return detail::createSyclObjFromImpl<device>(
269  PlatformImpl->getOrMakeDeviceImpl(PiDevice, PlatformImpl));
270  });
271 
272  return Res;
273 }
274 
275 bool platform_impl::has_extension(const std::string &ExtensionName) const {
276  if (is_host())
277  return false;
278 
279  std::string AllExtensionNames =
281  MPlatform, getPlugin());
282  return (AllExtensionNames.find(ExtensionName) != std::string::npos);
283 }
284 
285 pi_native_handle platform_impl::getNative() const {
286  const auto &Plugin = getPlugin();
287  pi_native_handle Handle;
288  Plugin.call<PiApiKind::piextPlatformGetNativeHandle>(getHandleRef(), &Handle);
289  return Handle;
290 }
291 
292 template <info::platform param>
294 platform_impl::get_info() const {
295  if (is_host())
296  return get_platform_info_host<param>();
297 
298  return get_platform_info<
300  param>::get(this->getHandleRef(), getPlugin());
301 }
302 
303 // All devices on the platform must have the given aspect.
304 bool platform_impl::has(aspect Aspect) const {
305  for (const auto &dev : get_devices()) {
306  if (dev.has(Aspect) == false) {
307  return false;
308  }
309  }
310  return true;
311 }
312 
313 #define __SYCL_PARAM_TRAITS_SPEC(param_type, param, ret_type) \
314  template ret_type platform_impl::get_info<info::param_type::param>() const;
315 
316 #include <CL/sycl/info/platform_traits.def>
317 #undef __SYCL_PARAM_TRAITS_SPEC
318 
319 } // namespace detail
320 } // namespace sycl
321 } // __SYCL_INLINE_NAMESPACE(cl)
cl::sycl::backend
backend
Definition: backend_types.hpp:21
cl::sycl::detail::pi::getPlugin
const plugin & getPlugin()
Definition: pi.cpp:489
PI_SUCCESS
@ PI_SUCCESS
Definition: pi.h:82
cl::sycl::detail::IsBannedPlatform
static bool IsBannedPlatform(platform Platform)
Definition: platform_impl.cpp:69
cl::sycl::info::device
device
Definition: info_desc.hpp:49
cl::sycl::info::param_traits
Definition: info_desc.hpp:297
cl::sycl::detail::plugin::setLastDeviceId
void setLastDeviceId(RT::PiPlatform Platform, int Id)
Definition: plugin.hpp:226
cl::sycl::detail::pi::initialize
std::vector< plugin > & initialize()
Definition: pi.cpp:360
cl::sycl::detail::device_filter
Definition: device_filter.hpp:22
config.hpp
cl::sycl::detail::device_filter_list::get
std::vector< device_filter > & get()
Definition: device_filter.hpp:45
cl::sycl::detail::pi::PI_TRACE_ALL
@ PI_TRACE_ALL
Definition: pi.hpp:58
device.hpp
cl::sycl::detail::pi::PiDevice
::pi_device PiDevice
Definition: pi.hpp:102
cl::sycl::detail::SYCLConfig
Definition: config.hpp:104
cl::sycl::platform::get_info
info::param_traits< info::platform, param >::return_type get_info() const
Queries this SYCL platform for info.
Definition: platform.cpp:54
_pi_device_type
_pi_device_type
Definition: pi.h:162
cl::sycl::info::device_type
device_type
Definition: info_desc.hpp:170
PI_DEVICE_INFO_PLATFORM
@ PI_DEVICE_INFO_PLATFORM
Definition: pi.h:259
device_impl.hpp
cl::sycl::platform::get_devices
std::vector< device > get_devices(info::device_type DeviceType=info::device_type::all) const
Returns all SYCL devices associated with this platform.
Definition: platform.cpp:42
_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::plugin::getBackend
backend getBackend(void) const
Definition: plugin.hpp:194
cl::sycl::detail::plugin::getPluginMutex
std::shared_ptr< std::mutex > getPluginMutex()
Definition: plugin.hpp:236
pi_uint32
uint32_t pi_uint32
Definition: pi.h:68
cl::sycl::detail::get_forced_type
info::device_type get_forced_type()
Definition: force_device.cpp:24
platform_impl.hpp
cl::sycl::device
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:34
cl::sycl::detail::pi::PiDeviceType
::pi_device_type PiDeviceType
Definition: pi.hpp:103
cl::sycl::detail::device_filter_list::backendCompatible
bool backendCompatible(backend Backend)
Definition: device_filter.cpp:133
cl::sycl::detail::device_filter_list
Definition: device_filter.hpp:37
cl::sycl::detail::plugin::call
void call(ArgsT... Args) const
Calls the API, traces the call, checks the result.
Definition: plugin.hpp:182
piDeviceGetInfo
pi_result piDeviceGetInfo(pi_device device, pi_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Returns requested info for provided native device Return PI_DEVICE_INFO_EXTENSION_DEVICELIB_ASSERT fo...
Definition: pi_esimd_emulator.cpp:485
force_device.hpp
cl
We provide new interfaces for matrix muliply in this patch:
Definition: access.hpp:13
global_handler.hpp
cl::sycl::detail::plugin::getStartingDeviceId
int getStartingDeviceId(RT::PiPlatform Platform)
Definition: plugin.hpp:217
cl::sycl::aspect
aspect
Definition: aspects.hpp:15
platform_info.hpp
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
pi_native_handle
uintptr_t pi_native_handle
Definition: pi.h:72
piPlatformsGet
pi_result piPlatformsGet(pi_uint32 num_entries, pi_platform *platforms, pi_uint32 *num_platforms)
Definition: pi_esimd_emulator.cpp:357
std::get
constexpr tuple_element< I, tuple< Types... > >::type & get(cl::sycl::detail::tuple< Types... > &Arg) noexcept
Definition: tuple.hpp:199
cl::sycl::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:182
cl::sycl::detail::PlatformImplPtr
std::shared_ptr< detail::platform_impl > PlatformImplPtr
Definition: context_impl.hpp:30
cl::sycl::detail::device_filter_list::containsHost
bool containsHost()
Definition: device_filter.cpp:160
piextPlatformGetNativeHandle
pi_result piextPlatformGetNativeHandle(pi_platform platform, pi_native_handle *nativeHandle)
Gets the native handle of a PI platform object.
Definition: pi_esimd_emulator.cpp:417
cl::sycl::platform
Encapsulates a SYCL platform on which kernels may be executed.
Definition: platform.hpp:33
piDevicesGet
pi_result piDevicesGet(pi_platform platform, pi_device_type device_type, pi_uint32 num_entries, pi_device *devices, pi_uint32 *num_devices)
Definition: pi_esimd_emulator.cpp:425
cl::sycl::all
detail::enable_if_t< detail::is_sigeninteger< T >::value, int > all(T x) __NOEXC
Definition: builtins.hpp:1282
cl::sycl::detail::applyAllowList
void applyAllowList(std::vector< RT::PiDevice > &PiDevices, RT::PiPlatform PiPlatform, const plugin &Plugin)
Definition: allowlist.cpp:336
cl::sycl::info::platform
platform
Definition: info_desc.hpp:29
allowlist.hpp
PI_DEVICE_INFO_TYPE
@ PI_DEVICE_INFO_TYPE
Definition: pi.h:187
cl::sycl::detail::get_platform_info
Definition: platform_info.hpp:21
cl::sycl::detail::filterDeviceFilter
static void filterDeviceFilter(std::vector< RT::PiDevice > &PiDevices, RT::PiPlatform Platform)
Definition: platform_impl.cpp:146
cl::sycl::detail::pi::trace
bool trace(TraceLevel level)
Definition: pi.cpp:354
cl::sycl::detail::pi::PiPlatform
::pi_platform PiPlatform
Definition: pi.hpp:101
_pi_device
PI device mapping to a CUdevice.
Definition: pi_cuda.hpp:71
__SYCL_INLINE_NAMESPACE
#define __SYCL_INLINE_NAMESPACE(X)
Definition: defines_elementary.hpp:12