Skip to content

Commit 7146426

Browse files
Ruykbader
andauthored
[SYCL][CUDA] Improvements to CUDA device selection (#1689)
* Prevents NVIDIA OpenCL platform to be selected by a SYCL application * NVIDIA OpenCL is not reported as a valid GPU platform for LIT testing * Introduces device selection logic to reject devices * Changes name of NVIDIA CUDA Backend to differentiate from OpenCL * Provides better error message when SPIRV is passed to CUDA backend * Using backend types to check for CUDA backend instead of strings Signed-off-by: Ruyman Reyes <[email protected]> Co-authored-by: Alexey Bader <[email protected]>
1 parent 9d45ead commit 7146426

File tree

8 files changed

+76
-43
lines changed

8 files changed

+76
-43
lines changed

sycl/include/CL/sycl/device_selector.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ namespace sycl {
1919
class device;
2020

2121
class __SYCL_EXPORT device_selector {
22+
protected:
23+
// SYCL 1.2.1 defines a negative score to reject a device from selection
24+
static constexpr int REJECT_DEVICE_SCORE = -1;
25+
2226
public:
2327
virtual ~device_selector() = default;
2428

sycl/plugins/cuda/pi_cuda.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ pi_result cuda_piPlatformGetInfo(pi_platform platform,
684684
switch (param_name) {
685685
case PI_PLATFORM_INFO_NAME:
686686
return getInfo(param_value_size, param_value, param_value_size_ret,
687-
"NVIDIA CUDA");
687+
"NVIDIA CUDA BACKEND");
688688
case PI_PLATFORM_INFO_VENDOR:
689689
return getInfo(param_value_size, param_value, param_value_size_ret,
690690
"NVIDIA Corporation");

sycl/source/detail/context_impl.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ context_impl::context_impl(const vector_class<cl::sycl::device> Devices,
4141
DeviceIds.push_back(getSyclObjImpl(D)->getHandleRef());
4242
}
4343

44-
if (MPlatform->is_cuda()) {
44+
const auto Backend = getPlugin().getBackend();
45+
if (Backend == backend::cuda) {
4546
#if USE_PI_CUDA
4647
const pi_context_properties props[] = {
4748
static_cast<pi_context_properties>(PI_CONTEXT_PROPERTIES_CUDA_PRIMARY),

sycl/source/detail/platform_impl.cpp

+29-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,33 @@ __SYCL_INLINE_NAMESPACE(cl) {
2020
namespace sycl {
2121
namespace detail {
2222

23+
static bool IsBannedPlatform(platform Platform) {
24+
// The NVIDIA OpenCL platform is currently not compatible with DPC++
25+
// since it is only 1.2 but gets selected by default in many systems
26+
// There is also no support on the PTX backend for OpenCL consumption,
27+
// and there have been some internal reports.
28+
// To avoid problems on default users and deployment of DPC++ on platforms
29+
// where CUDA is available, the OpenCL support is disabled.
30+
//
31+
auto IsNVIDIAOpenCL = [](platform Platform) {
32+
if (Platform.is_host())
33+
return false;
34+
35+
const bool HasCUDA = Platform.get_info<info::platform::name>().find(
36+
"NVIDIA CUDA") != std::string::npos;
37+
const auto Backend =
38+
detail::getSyclObjImpl(Platform)->getPlugin().getBackend();
39+
const bool IsCUDAOCL = (HasCUDA && Backend == backend::opencl);
40+
if (detail::pi::trace(detail::pi::TraceLevel::PI_TRACE_ALL) && IsCUDAOCL) {
41+
std::cout << "SYCL_PI_TRACE[all]: "
42+
<< "NVIDIA CUDA OpenCL platform found but is not compatible."
43+
<< std::endl;
44+
}
45+
return IsCUDAOCL;
46+
};
47+
return IsNVIDIAOpenCL(Platform);
48+
}
49+
2350
vector_class<platform> platform_impl::get_platforms() {
2451
vector_class<platform> Platforms;
2552
vector_class<plugin> Plugins = RT::initialize();
@@ -39,7 +66,8 @@ vector_class<platform> platform_impl::get_platforms() {
3966
platform Platform = detail::createSyclObjFromImpl<platform>(
4067
std::make_shared<platform_impl>(PiPlatform, Plugins[i]));
4168
// Skip platforms which do not contain requested device types
42-
if (!Platform.get_devices(ForcedType).empty())
69+
if (!Platform.get_devices(ForcedType).empty() &&
70+
!IsBannedPlatform(Platform))
4371
Platforms.push_back(Platform);
4472
}
4573
}

sycl/source/detail/platform_impl.hpp

-8
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,6 @@ class platform_impl {
7373
/// \return true if this SYCL platform is a host platform.
7474
bool is_host() const { return MHostPlatform; };
7575

76-
bool is_cuda() const {
77-
const string_class CUDA_PLATFORM_STRING = "NVIDIA CUDA";
78-
const string_class PlatformName =
79-
get_platform_info<string_class, info::platform::name>::get(MPlatform,
80-
getPlugin());
81-
return PlatformName == CUDA_PLATFORM_STRING;
82-
}
83-
8476
/// \return an instance of OpenCL cl_platform_id.
8577
cl_platform_id get() const {
8678
if (is_host())

sycl/source/detail/program_manager/program_manager.cpp

+11-24
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,10 @@ static RT::PiProgram createBinaryProgram(const ContextImplPtr Context,
8686

8787
RT::PiProgram Program;
8888

89-
bool IsCUDA = false;
90-
9189
// TODO: Implement `piProgramCreateWithBinary` to not require extra logic for
9290
// the CUDA backend.
93-
#if USE_PI_CUDA
94-
// All devices in a context are from the same platform.
95-
RT::PiDevice Device = getFirstDevice(Context);
96-
RT::PiPlatform Platform = nullptr;
97-
Plugin.call<PiApiKind::piDeviceGetInfo>(Device, PI_DEVICE_INFO_PLATFORM, sizeof(Platform),
98-
&Platform, nullptr);
99-
size_t PlatformNameSize = 0u;
100-
Plugin.call<PiApiKind::piPlatformGetInfo>(Platform, PI_PLATFORM_INFO_NAME, 0u, nullptr,
101-
&PlatformNameSize);
102-
std::vector<char> PlatformName(PlatformNameSize, '\0');
103-
Plugin.call<PiApiKind::piPlatformGetInfo>(Platform, PI_PLATFORM_INFO_NAME,
104-
PlatformName.size(), PlatformName.data(), nullptr);
105-
if (PlatformNameSize > 0u &&
106-
std::strncmp(PlatformName.data(), "NVIDIA CUDA", PlatformNameSize) == 0) {
107-
IsCUDA = true;
108-
}
109-
#endif // USE_PI_CUDA
110-
111-
if (IsCUDA) {
91+
const auto Backend = Context->getPlugin().getBackend();
92+
if (Backend == backend::cuda) {
11293
// TODO: Reemplace CreateWithSource with CreateWithBinary in CUDA backend
11394
const char *SignedData = reinterpret_cast<const char *>(Data);
11495
Plugin.call<PiApiKind::piclProgramCreateWithSource>(Context->getHandleRef(), 1 /*one binary*/, &SignedData,
@@ -259,6 +240,13 @@ RetT *getOrBuild(KernelProgramCache &KPCache, KeyT &&CacheKey,
259240

260241
static bool isDeviceBinaryTypeSupported(const context &C,
261242
RT::PiDeviceBinaryType Format) {
243+
const backend ContextBackend =
244+
detail::getSyclObjImpl(C)->getPlugin().getBackend();
245+
246+
// The CUDA backend cannot use SPIRV
247+
if (ContextBackend == backend::cuda && Format == PI_DEVICE_BINARY_TYPE_SPIRV)
248+
return false;
249+
262250
// All formats except PI_DEVICE_BINARY_TYPE_SPIRV are supported.
263251
if (Format != PI_DEVICE_BINARY_TYPE_SPIRV)
264252
return true;
@@ -272,8 +260,7 @@ static bool isDeviceBinaryTypeSupported(const context &C,
272260
}
273261

274262
// OpenCL 2.1 and greater require clCreateProgramWithIL
275-
backend CBackend = (detail::getSyclObjImpl(C)->getPlugin()).getBackend();
276-
if ((CBackend == backend::opencl) &&
263+
if ((ContextBackend == backend::opencl) &&
277264
C.get_platform().get_info<info::platform::version>() >= "2.1")
278265
return true;
279266

@@ -337,7 +324,7 @@ RT::PiProgram ProgramManager::createPIProgram(const RTDeviceBinaryImage &Img,
337324

338325
if (!isDeviceBinaryTypeSupported(Context, Format))
339326
throw feature_not_supported(
340-
"Online compilation is not supported in this context",
327+
"SPIR-V online compilation is not supported in this context",
341328
PI_INVALID_OPERATION);
342329

343330
// Load the image

sycl/source/device_selector.cpp

+17-8
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,36 @@ static bool isDeviceOfPreferredSyclBe(const device &Device) {
3030

3131
device device_selector::select_device() const {
3232
vector_class<device> devices = device::get_devices();
33-
int score = -1;
33+
int score = REJECT_DEVICE_SCORE;
3434
const device *res = nullptr;
35+
3536
for (const auto &dev : devices) {
3637
int dev_score = (*this)(dev);
38+
3739
if (detail::pi::trace(detail::pi::TraceLevel::PI_TRACE_ALL)) {
3840
string_class PlatformVersion = dev.get_info<info::device::platform>()
3941
.get_info<info::platform::version>();
4042
string_class DeviceName = dev.get_info<info::device::name>();
4143
std::cout << "SYCL_PI_TRACE[all]: "
42-
<< "select_device(): -> score = " << score << std::endl
44+
<< "select_device(): -> score = " << score
45+
<< ((score == REJECT_DEVICE_SCORE) ? "(REJECTED)" : " ")
46+
<< std::endl
4347
<< "SYCL_PI_TRACE[all]: "
4448
<< " platform: " << PlatformVersion << std::endl
4549
<< "SYCL_PI_TRACE[all]: "
4650
<< " device: " << DeviceName << std::endl;
4751
}
4852

53+
// Device is discarded if is marked with REJECT_DEVICE_SCORE
54+
if (dev_score == REJECT_DEVICE_SCORE)
55+
continue;
56+
4957
// SYCL spec says: "If more than one device receives the high score then
5058
// one of those tied devices will be returned, but which of the devices
5159
// from the tied set is to be returned is not defined". Here we give a
5260
// preference to the device of the preferred BE.
5361
//
54-
if (score < dev_score ||
62+
if ((score < dev_score) ||
5563
(score == dev_score && isDeviceOfPreferredSyclBe(dev))) {
5664
res = &dev;
5765
score = dev_score;
@@ -79,7 +87,7 @@ device device_selector::select_device() const {
7987

8088
int default_selector::operator()(const device &dev) const {
8189

82-
int Score = -1;
90+
int Score = REJECT_DEVICE_SCORE;
8391

8492
// Give preference to device of SYCL BE.
8593
if (isDeviceOfPreferredSyclBe(dev))
@@ -102,7 +110,8 @@ int default_selector::operator()(const device &dev) const {
102110
}
103111

104112
int gpu_selector::operator()(const device &dev) const {
105-
int Score = -1;
113+
int Score = REJECT_DEVICE_SCORE;
114+
106115
if (dev.is_gpu()) {
107116
Score = 1000;
108117
// Give preference to device of SYCL BE.
@@ -113,7 +122,7 @@ int gpu_selector::operator()(const device &dev) const {
113122
}
114123

115124
int cpu_selector::operator()(const device &dev) const {
116-
int Score = -1;
125+
int Score = REJECT_DEVICE_SCORE;
117126
if (dev.is_cpu()) {
118127
Score = 1000;
119128
// Give preference to device of SYCL BE.
@@ -124,7 +133,7 @@ int cpu_selector::operator()(const device &dev) const {
124133
}
125134

126135
int accelerator_selector::operator()(const device &dev) const {
127-
int Score = -1;
136+
int Score = REJECT_DEVICE_SCORE;
128137
if (dev.is_accelerator()) {
129138
Score = 1000;
130139
// Give preference to device of SYCL BE.
@@ -135,7 +144,7 @@ int accelerator_selector::operator()(const device &dev) const {
135144
}
136145

137146
int host_selector::operator()(const device &dev) const {
138-
int Score = -1;
147+
int Score = REJECT_DEVICE_SCORE;
139148
if (dev.is_host()) {
140149
Score = 1000;
141150
// Give preference to device of SYCL BE.

sycl/tools/get_device_count_by_type.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <algorithm>
2323
#include <cstdlib>
24+
#include <cstring>
2425
#include <iostream>
2526
#include <sstream>
2627
#include <string>
@@ -88,6 +89,17 @@ static bool queryOpenCL(cl_device_type deviceType, cl_uint &deviceCount,
8889
}
8990

9091
for (cl_uint i = 0; i < platformCount; i++) {
92+
const size_t MAX_PLATFORM_VENDOR = 100u;
93+
char info[MAX_PLATFORM_VENDOR];
94+
// get platform attribute value
95+
clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, MAX_PLATFORM_VENDOR,
96+
info, NULL);
97+
const auto IsNVIDIAOpenCL = strstr(info, "NVIDIA") != NULL;
98+
if (IsNVIDIAOpenCL) {
99+
// Ignore NVIDIA OpenCL platform for testing
100+
continue;
101+
}
102+
91103
cl_uint deviceCountPart = 0;
92104
iRet =
93105
clGetDeviceIDs(platforms[i], deviceType, 0, nullptr, &deviceCountPart);

0 commit comments

Comments
 (0)