//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include #include #include #include _LIBSYCL_BEGIN_NAMESPACE_SYCL static constexpr int MatchedTypeDefaultScore = 1000; static constexpr int GPUDeviceDefaultScore = 500; static constexpr int CPUDeviceDefaultScore = 300; static constexpr int AccDeviceDefaultScore = 75; static constexpr int RejectDeviceScore = -1; static int getDevicePreference(const device &Device) { int Score = 0; const auto &DeviceImpl = detail::getSyclObjImpl(Device); // TODO: increase score for devices with compatible program images. if (DeviceImpl->getBackend() == backend::level_zero) Score += 50; return Score; } _LIBSYCL_EXPORT int default_selector_v(const device &dev) { int Score = getDevicePreference(dev); if (dev.is_gpu()) Score += GPUDeviceDefaultScore; else if (dev.is_cpu()) Score += CPUDeviceDefaultScore; else if (dev.is_accelerator()) Score += AccDeviceDefaultScore; return Score; } _LIBSYCL_EXPORT int gpu_selector_v(const device &Dev) { return Dev.is_gpu() ? MatchedTypeDefaultScore + getDevicePreference(Dev) : RejectDeviceScore; } _LIBSYCL_EXPORT int cpu_selector_v(const device &Dev) { return Dev.is_cpu() ? MatchedTypeDefaultScore + getDevicePreference(Dev) : RejectDeviceScore; } _LIBSYCL_EXPORT int accelerator_selector_v(const device &Dev) { return Dev.is_accelerator() ? MatchedTypeDefaultScore + getDevicePreference(Dev) : RejectDeviceScore; } _LIBSYCL_EXPORT detail::DeviceSelectorInvocableType aspect_selector(const std::vector &RequireList, const std::vector &DenyList) { return [=](const sycl::device &Dev) { // 4.6.1.1. Device selector: // If no aspects are passed in, the generated selector behaves like // default_selector_v. if (RequireList.empty() && DenyList.empty()) return default_selector_v(Dev); auto HasAspect = [&Dev](const aspect &Aspect) -> bool { return Dev.has(Aspect); }; if (!std::all_of(RequireList.begin(), RequireList.end(), HasAspect)) return RejectDeviceScore; if (std::any_of(DenyList.begin(), DenyList.end(), HasAspect)) return RejectDeviceScore; return MatchedTypeDefaultScore + getDevicePreference(Dev); }; } namespace detail { _LIBSYCL_EXPORT device SelectDevice(const DeviceSelectorInvocableType &DeviceSelector) { int ChosenDeviceScore = RejectDeviceScore; const device *ChosenDevice = nullptr; std::vector Devices = device::get_devices(); for (const auto &Device : Devices) { int CurrentDevScore = DeviceSelector(Device); if (CurrentDevScore < 0) continue; if ((ChosenDeviceScore < CurrentDevScore) || ((ChosenDeviceScore == CurrentDevScore) && (getDevicePreference(*ChosenDevice) < getDevicePreference(Device)))) { ChosenDevice = &Device; ChosenDeviceScore = CurrentDevScore; } } if (ChosenDevice != nullptr) return *ChosenDevice; throw exception(make_error_code(errc::runtime), "No device of requested type is available"); } } // namespace detail _LIBSYCL_END_NAMESPACE_SYCL