blob: 0525cee4535c73dc14e3d6f98282fb62624255a2 [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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 <detail/context_impl.hpp>
#include <detail/platform_impl.hpp>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
namespace detail {
ContextImpl::ContextImpl(std::vector<DeviceImpl *> &&DeviceList,
const async_handler &AsyncHandler,
const property_list &PropList, Private)
: MAsyncHandler(AsyncHandler), MDevices(std::move(DeviceList)) {
// TODO: Remove this when property_list is implemented
std::ignore = PropList;
std::vector<ol_device_handle_t> DeviceIds;
DeviceIds.reserve(MDevices.size());
for (DeviceImpl *D : MDevices) {
assert(D && "Device list must not contain null entries");
DeviceIds.push_back(D->getOLHandle());
}
auto Result = callNoCheck(olCreateContext, DeviceIds.size(), DeviceIds.data(),
&MOffloadContext);
if (isFailed(Result)) {
if (Result->Code == OL_ERRC_INVALID_SIZE)
throw sycl::exception(make_error_code(errc::invalid),
"Device list must not be empty");
checkAndThrow(Result);
}
}
ContextImpl::~ContextImpl() {
assert(MOffloadContext && "Context must be created in ctor");
// liboffload does not reference-count contexts: every resource tied to a
// context must be released before olDestroyContext, otherwise it is left in
// an undefined state. MPrograms is a member, so it would be destroyed only
// after this destructor body has run.
releaseAllPrograms();
std::ignore = olDestroyContext(MOffloadContext);
}
PlatformImpl &ContextImpl::getPlatformImpl() const {
return MDevices[0]->getPlatformImpl();
}
void ContextImpl::iterateDevices(
const std::function<void(DeviceImpl *)> &callback) const {
for (DeviceImpl *Device : MDevices)
callback(Device);
}
backend ContextImpl::getBackend() const { return MDevices[0]->getBackend(); }
ol_symbol_handle_t
ContextImpl::getOrCreateKernel(const DeviceImageManager &DeviceImage,
ol_device_handle_t DeviceHandle,
std::string_view KernelName) {
std::lock_guard<std::mutex> Guard(MProgramCacheMutex);
auto ImageIt = MPrograms.try_emplace(&DeviceImage).first;
ProgramsByDeviceT &ProgramsForImage = ImageIt->second;
auto ProgramIt = ProgramsForImage.find(DeviceHandle);
if (ProgramIt == ProgramsForImage.end()) {
// Constructing a ProgramWrapper calls olCreateProgram, so try_emplace is
// used rather than emplace: the latter would build a program even when one
// is already cached, only to destroy it again.
try {
ProgramIt = ProgramsForImage
.try_emplace(DeviceHandle, MOffloadContext, DeviceHandle,
DeviceImage)
.first;
} catch (...) {
// Do not leave an empty entry behind if program creation failed.
if (ProgramsForImage.empty())
MPrograms.erase(ImageIt);
throw;
}
}
return ProgramIt->second.getOrCreateKernel(KernelName);
}
void ContextImpl::releaseProgramsForImage(
const DeviceImageManager &DeviceImage) {
std::lock_guard<std::mutex> Guard(MProgramCacheMutex);
MPrograms.erase(&DeviceImage);
}
void ContextImpl::releaseAllPrograms() {
std::lock_guard<std::mutex> Guard(MProgramCacheMutex);
MPrograms.clear();
}
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL