[llvm] [offload] Add context parameter to olCreateQueue (PR #213057)
Ćukasz Plewa via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 31 07:16:53 PDT 2026
https://github.com/lplewa updated https://github.com/llvm/llvm-project/pull/213057
>From d14dc6e1da93c5877abe2c199e8725464bb6b13e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Plewa?= <lukasz.plewa at intel.com>
Date: Wed, 8 Jul 2026 19:26:11 +0200
Subject: [PATCH 1/2] [offload] Add context parameter to olCreateQueue
Second patch in the context series.
Outstanding-queue bookkeeping (queues destroyed while still busy) moves
from ol_device_impl_t to ol_context_impl_t, keyed by device. This keeps
backend queue resources from being reused across native contexts and lets
olDestroyContext drain everything it owns.
On the Level Zero side, LevelZeroPluginContextTy owns a ze_context and an
L0QueueCacheTy pooling idle queues per device bound to that ze_context.
L0ContextTy holds a DefaultUserCtx used by the libomptarget path when no
user context is set on the async info. Queue creation, command-list
creation and initAsyncInfoImpl all thread the plugin context through so
queues are bound to the right ze_context.
Note: this patch temporarily passes null as the context in SYCL.
@KseniyaTikhomirova is currently working on proper context management
in libsycl - once that is implemented, this PR will be updated.
Assisted-by: Claude
---
libsycl/src/detail/queue_impl.cpp | 3 +-
libsycl/unittests/mock/helpers.cpp | 4 +-
libsycl/unittests/mock/helpers.hpp | 3 +-
libsycl/unittests/mock/mock.cpp | 5 +-
libsycl/unittests/queue/queue.cpp | 2 +-
.../tools/llvm-gpu-loader/llvm-gpu-loader.cpp | 6 +-
llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h | 11 +-
offload/liboffload/API/Queue.td | 15 +-
offload/liboffload/src/OffloadImpl.cpp | 148 ++++++++++--------
.../common/include/PluginInterface.h | 14 +-
.../common/src/PluginInterface.cpp | 11 +-
.../level_zero/include/L0Context.h | 14 +-
.../level_zero/include/L0Device.h | 23 +--
.../level_zero/include/L0Plugin.h | 11 +-
.../level_zero/include/L0Queue.h | 20 ++-
.../level_zero/src/L0Context.cpp | 12 ++
.../level_zero/src/L0Device.cpp | 31 ++--
.../level_zero/src/L0Plugin.cpp | 15 ++
.../level_zero/src/L0Queue.cpp | 32 ++--
.../include/mathtest/DeviceContext.hpp | 3 +
.../include/mathtest/OffloadForward.hpp | 3 +
.../Conformance/lib/DeviceContext.cpp | 7 +
.../unittests/OffloadAPI/common/Fixtures.hpp | 11 +-
.../OffloadAPI/context/olCreateContext.cpp | 16 +-
.../OffloadAPI/context/olGetContextInfo.cpp | 15 +-
.../context/olGetContextInfoSize.cpp | 15 +-
.../OffloadAPI/kernel/olLaunchKernel.cpp | 2 +-
.../unittests/OffloadAPI/memory/olMemcpy.cpp | 2 +-
.../OffloadAPI/queue/olCreateQueue.cpp | 22 ++-
.../OffloadAPI/queue/olGetQueueInfo.cpp | 8 +
.../OffloadAPI/queue/olGetQueueInfoSize.cpp | 6 +
.../OffloadAPI/queue/olLaunchHostFunction.cpp | 2 +-
.../OffloadAPI/queue/olWaitEvents.cpp | 10 +-
33 files changed, 334 insertions(+), 168 deletions(-)
diff --git a/libsycl/src/detail/queue_impl.cpp b/libsycl/src/detail/queue_impl.cpp
index 6116e2d787e6f..c1602ac52d142 100644
--- a/libsycl/src/detail/queue_impl.cpp
+++ b/libsycl/src/detail/queue_impl.cpp
@@ -66,7 +66,8 @@ QueueImpl::QueueImpl(DeviceImpl &deviceImpl, const async_handler &asyncHandler,
: MIsInorder(false), MAsyncHandler(asyncHandler), MPropList(propList),
MDevice(deviceImpl),
MContext(MDevice.getPlatformImpl().getDefaultContext()) {
- callAndThrow(olCreateQueue, MDevice.getOLHandle(), &MOffloadQueue);
+ // TODO: temporary, waiting for proper context support in sycl.
+ callAndThrow(olCreateQueue, nullptr, MDevice.getOLHandle(), &MOffloadQueue);
}
QueueImpl::~QueueImpl() {
diff --git a/libsycl/unittests/mock/helpers.cpp b/libsycl/unittests/mock/helpers.cpp
index 6b4460cd66113..562754ae68b4c 100644
--- a/libsycl/unittests/mock/helpers.cpp
+++ b/libsycl/unittests/mock/helpers.cpp
@@ -222,8 +222,10 @@ void mock::MockLiboffload::initDefault() {
});
ON_CALL(*this, olCreateQueue)
- .WillByDefault([this](ol_device_handle_t Device,
+ .WillByDefault([this](ol_context_handle_t Context,
+ ol_device_handle_t Device,
ol_queue_handle_t *Queue) -> ol_result_t {
+ std::ignore = Context;
if (!Device)
return makeEmptyStrError(OL_ERRC_INVALID_NULL_HANDLE);
if (!Queue)
diff --git a/libsycl/unittests/mock/helpers.hpp b/libsycl/unittests/mock/helpers.hpp
index 0690970f1f99b..50835284c73d9 100644
--- a/libsycl/unittests/mock/helpers.hpp
+++ b/libsycl/unittests/mock/helpers.hpp
@@ -90,7 +90,8 @@ class MockLiboffload {
(ol_device_iterate_cb_t Callback, void *UserData));
MOCK_METHOD(ol_result_t, olDestroyProgram, (ol_program_handle_t Program));
MOCK_METHOD(ol_result_t, olCreateQueue,
- (ol_device_handle_t Device, ol_queue_handle_t *Queue));
+ (ol_context_handle_t Context, ol_device_handle_t Device,
+ ol_queue_handle_t *Queue));
MOCK_METHOD(ol_result_t, olDestroyQueue, (ol_queue_handle_t Queue));
MOCK_METHOD(ol_result_t, olSyncQueue, (ol_queue_handle_t Queue));
MOCK_METHOD(ol_result_t, olDestroyEvent, (ol_event_handle_t Event));
diff --git a/libsycl/unittests/mock/mock.cpp b/libsycl/unittests/mock/mock.cpp
index 8f5db4b5cb6ec..f050eb13317e8 100644
--- a/libsycl/unittests/mock/mock.cpp
+++ b/libsycl/unittests/mock/mock.cpp
@@ -50,8 +50,9 @@ ol_result_t olDestroyProgram(ol_program_handle_t Program) {
return mock::getMockLiboffload().olDestroyProgram(Program);
}
-ol_result_t olCreateQueue(ol_device_handle_t Device, ol_queue_handle_t *Queue) {
- return mock::getMockLiboffload().olCreateQueue(Device, Queue);
+ol_result_t olCreateQueue(ol_context_handle_t Context,
+ ol_device_handle_t Device, ol_queue_handle_t *Queue) {
+ return mock::getMockLiboffload().olCreateQueue(Context, Device, Queue);
}
ol_result_t olDestroyQueue(ol_queue_handle_t Queue) {
diff --git a/libsycl/unittests/queue/queue.cpp b/libsycl/unittests/queue/queue.cpp
index 1234e5eb94281..c505f78ecbdd4 100644
--- a/libsycl/unittests/queue/queue.cpp
+++ b/libsycl/unittests/queue/queue.cpp
@@ -20,7 +20,7 @@ using namespace ::testing;
TEST(Queue, CommonQueriesAndLifetime) {
mock::MockWrapper Mock;
- EXPECT_CALL(Mock.get(), olCreateQueue(_, _)).Times(1);
+ EXPECT_CALL(Mock.get(), olCreateQueue(_, _, _)).Times(1);
EXPECT_CALL(Mock.get(), olDestroyQueue(_)).Times(1);
{
queue Q;
diff --git a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
index 2cd2cfaeebb6b..82a8815c8a380 100644
--- a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
+++ b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
@@ -244,12 +244,15 @@ int main(int argc, const char **argv, const char **envp) {
ol_device_handle_t Host = getHostDevice();
assert(Host && "Host device should always be present");
+ ol_context_handle_t Context;
+ OFFLOAD_ERR(olCreateContext(1, &Device, &Context));
+
ol_program_handle_t Program;
OFFLOAD_ERR(olCreateProgram(Device, Image.getBufferStart(),
Image.getBufferSize(), &Program));
ol_queue_handle_t Queue;
- OFFLOAD_ERR(olCreateQueue(Device, &Queue));
+ OFFLOAD_ERR(olCreateQueue(Context, Device, &Queue));
int DevArgc = static_cast<int>(NewArgv.size());
void *DevArgv = copyArgumentVector(NewArgv.size(), NewArgv.begin(), Device);
@@ -284,6 +287,7 @@ int main(int argc, const char **argv, const char **envp) {
OFFLOAD_ERR(olMemFree(DevArgv));
OFFLOAD_ERR(olMemFree(DevEnvp));
OFFLOAD_ERR(olDestroyQueue(Queue));
+ OFFLOAD_ERR(olDestroyContext(Context));
OFFLOAD_ERR(olDestroyProgram(Program));
OFFLOAD_ERR(olShutDown());
diff --git a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h
index 1e9ae3448e7a0..c257f2ea391b2 100644
--- a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h
+++ b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h
@@ -108,6 +108,7 @@ typedef struct ol_platform_impl_t *ol_platform_handle_t;
typedef struct ol_program_impl_t *ol_program_handle_t;
typedef struct ol_queue_impl_t *ol_queue_handle_t;
typedef struct ol_symbol_impl_t *ol_symbol_handle_t;
+typedef struct ol_context_impl_t *ol_context_handle_t;
typedef const struct ol_error_struct_t *ol_result_t;
typedef bool (*ol_device_iterate_cb_t)(ol_device_handle_t Device,
@@ -138,7 +139,13 @@ ol_result_t (*olLaunchKernel)(
const ol_kernel_launch_prop_t *Properties, size_t NumArgs, void **ArgPtrs,
const size_t *ArgSizes);
-ol_result_t (*olCreateQueue)(ol_device_handle_t Device,
+ol_result_t (*olCreateContext)(size_t DevicesCount, ol_device_handle_t *Devices,
+ ol_context_handle_t *Context);
+
+ol_result_t (*olDestroyContext)(ol_context_handle_t Context);
+
+ol_result_t (*olCreateQueue)(ol_context_handle_t Context,
+ ol_device_handle_t Device,
ol_queue_handle_t *Queue);
ol_result_t (*olDestroyQueue)(ol_queue_handle_t Queue);
@@ -195,6 +202,8 @@ llvm::Error loadLLVMOffload() {
DYNAMIC_INIT(olDestroyProgram);
DYNAMIC_INIT(olGetSymbol);
DYNAMIC_INIT(olLaunchKernel);
+ DYNAMIC_INIT(olCreateContext);
+ DYNAMIC_INIT(olDestroyContext);
DYNAMIC_INIT(olCreateQueue);
DYNAMIC_INIT(olDestroyQueue);
DYNAMIC_INIT(olSyncQueue);
diff --git a/offload/liboffload/API/Queue.td b/offload/liboffload/API/Queue.td
index 4008432375753..b03ad6d46a1e8 100644
--- a/offload/liboffload/API/Queue.td
+++ b/offload/liboffload/API/Queue.td
@@ -11,13 +11,21 @@
//===----------------------------------------------------------------------===//
def olCreateQueue : Function {
- let desc = "Create a queue for the given device.";
- let details = [];
+ let desc = "Create a queue for the given device within the given context.";
+ let details = [
+ "The queue is scoped to `Context` and `Device` must belong to it.",
+ "The queue can only operate on resources (memory allocations, programs) that were created in the same context."
+ ];
let params = [
+ Param<"ol_context_handle_t", "Context", "handle of the context", PARAM_IN>,
Param<"ol_device_handle_t", "Device", "handle of the device", PARAM_IN>,
Param<"ol_queue_handle_t*", "Queue", "output pointer for the created queue", PARAM_OUT>
];
- let returns = [];
+ let returns = [
+ Return<"OL_ERRC_INVALID_DEVICE", [
+ "Device does not belong to `Context`"
+ ]>
+ ];
}
def olDestroyQueue : Function {
@@ -61,6 +69,7 @@ def ol_queue_info_t : Enum {
let is_typed = 1;
let etors = [
TaggedEtor<"DEVICE", "ol_device_handle_t", "The handle of the device associated with the queue.">,
+ TaggedEtor<"CONTEXT", "ol_context_handle_t", "The handle of the context associated with the queue.">,
TaggedEtor<"EMPTY", "bool", "True if the queue is known to be empty. May be unconditionally false if the device does not support status queries.">,
];
}
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index 63fe726fbe544..d6a2b466cb92d 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -71,70 +71,17 @@ struct ol_device_impl_t {
: DeviceNum(DeviceNum), Device(Device), Platform(Platform),
Info(std::forward<InfoTreeNode>(DevInfo)) {}
- ~ol_device_impl_t() {
- assert(!OutstandingQueues.size() &&
- "Device object dropped with outstanding queues");
- }
-
int DeviceNum;
GenericDeviceTy *Device;
ol_platform_impl_t &Platform;
InfoTreeNode Info;
-
- llvm::SmallVector<__tgt_async_info *> OutstandingQueues;
- std::mutex OutstandingQueuesMutex;
-
- /// If the device has any outstanding queues that are now complete, remove it
- /// from the list and return it.
- ///
- /// Queues may be added to the outstanding queue list by olDestroyQueue if
- /// they are destroyed but not completed.
- __tgt_async_info *getOutstandingQueue() {
- // Not locking the `size()` access is fine here - In the worst case we
- // either miss a queue that exists or loop through an empty array after
- // taking the lock. Both are sub-optimal but not that bad.
- if (OutstandingQueues.size()) {
- std::lock_guard<std::mutex> Lock(OutstandingQueuesMutex);
-
- // As queues are pulled and popped from this list, longer running queues
- // naturally bubble to the start of the array. Hence looping backwards.
- for (auto Q = OutstandingQueues.rbegin(); Q != OutstandingQueues.rend();
- Q++) {
- if (!Device->hasPendingWork(*Q)) {
- auto OutstandingQueue = *Q;
- *Q = OutstandingQueues.back();
- OutstandingQueues.pop_back();
- return OutstandingQueue;
- }
- }
- }
- return nullptr;
- }
-
- /// Complete all pending work for this device and perform any needed cleanup.
- ///
- /// After calling this function, no liboffload functions should be called with
- /// this device handle.
- llvm::Error destroy() {
- llvm::Error Result = Plugin::success();
- for (auto Q : OutstandingQueues)
- if (auto Err = Device->synchronize(Q, /*Release=*/true))
- Result = llvm::joinErrors(std::move(Result), std::move(Err));
- OutstandingQueues.clear();
- return Result;
- }
};
llvm::Error ol_platform_impl_t::destroy() {
- llvm::Error Result = Plugin::success();
- for (auto &D : Devices)
- if (auto Err = D->destroy())
- Result = llvm::joinErrors(std::move(Result), std::move(Err));
-
if (auto Res = Plugin->deinit())
- Result = llvm::joinErrors(std::move(Result), std::move(Res));
+ return Res;
- return Result;
+ return llvm::Error::success();
}
llvm::Error ol_platform_impl_t::init() {
@@ -160,9 +107,12 @@ llvm::Error ol_platform_impl_t::init() {
}
struct ol_queue_impl_t {
- ol_queue_impl_t(__tgt_async_info *AsyncInfo, ol_device_handle_t Device)
- : AsyncInfo(AsyncInfo), Device(Device), Id(IdCounter++) {}
+ ol_queue_impl_t(__tgt_async_info *AsyncInfo, ol_context_handle_t Context,
+ ol_device_handle_t Device)
+ : AsyncInfo(AsyncInfo), Context(Context), Device(Device),
+ Id(IdCounter++) {}
__tgt_async_info *AsyncInfo;
+ ol_context_handle_t Context;
ol_device_handle_t Device;
// A unique identifier for the queue
size_t Id;
@@ -218,6 +168,66 @@ struct ol_context_impl_t {
ol_platform_impl_t *Platform;
llvm::SmallVector<ol_device_handle_t> Devices;
std::unique_ptr<plugin::PluginContextTy> PluginCtx;
+
+ bool contains(ol_device_handle_t Device) const {
+ return llvm::is_contained(Devices, Device);
+ }
+
+ /// Queues destroyed while still busy, keyed by owning device. Per-context
+ /// so their backend resources are not reused across native contexts.
+ llvm::DenseMap<ol_device_handle_t, llvm::SmallVector<__tgt_async_info *>>
+ OutstandingQueues;
+ std::mutex OutstandingQueuesMutex;
+
+ /// If the context has any outstanding queues for \p Device that are now
+ /// complete, remove it from the list and return it.
+ ///
+ /// Queues may be added to the outstanding queue list by olDestroyQueue if
+ /// they are destroyed but not completed.
+ __tgt_async_info *getOutstandingQueue(ol_device_handle_t Device) {
+ std::lock_guard<std::mutex> Lock(OutstandingQueuesMutex);
+ auto It = OutstandingQueues.find(Device);
+ if (It == OutstandingQueues.end() || It->second.empty())
+ return nullptr;
+ auto &Bucket = It->second;
+
+ // As queues are pulled and popped from this list, longer running queues
+ // naturally bubble to the start of the array. Hence looping backwards.
+ for (auto Q = Bucket.rbegin(); Q != Bucket.rend(); Q++) {
+ if (!Device->Device->hasPendingWork(*Q)) {
+ auto OutstandingQueue = *Q;
+ *Q = Bucket.back();
+ Bucket.pop_back();
+ return OutstandingQueue;
+ }
+ }
+ return nullptr;
+ }
+
+ /// Record \p AsyncInfo on the outstanding queue list for \p Device.
+ void addOutstandingQueue(ol_device_handle_t Device,
+ __tgt_async_info *AsyncInfo) {
+ std::lock_guard<std::mutex> Lock(OutstandingQueuesMutex);
+ OutstandingQueues[Device].push_back(AsyncInfo);
+ }
+
+ /// Complete all pending work for this context. Called from olDestroyContext.
+ llvm::Error drainOutstandingQueues() {
+ llvm::Error Result = Plugin::success();
+ for (auto &Bucket : OutstandingQueues) {
+ auto *Device = Bucket.first;
+ for (auto *AI : Bucket.second)
+ if (auto Err = Device->Device->synchronize(AI, /*Release=*/true))
+ Result = llvm::joinErrors(std::move(Result), std::move(Err));
+ }
+ OutstandingQueues.clear();
+ return Result;
+ }
+
+ ~ol_context_impl_t() {
+ assert(OutstandingQueues.empty() &&
+ "Context dropped with outstanding queues");
+ }
};
namespace llvm {
@@ -629,6 +639,8 @@ Error olCreateContext_impl(size_t DevicesCount, ol_device_handle_t *Devices,
}
Error olDestroyContext_impl(ol_context_handle_t Context) {
+ if (auto Err = Context->drainOutstandingQueues())
+ return Err;
return olDestroy(Context);
}
@@ -845,10 +857,16 @@ Error olGetMemInfoSize_impl(const void *Ptr, ol_mem_info_t PropName,
return olGetMemInfoImplDetail(Ptr, PropName, 0, nullptr, PropSizeRet);
}
-Error olCreateQueue_impl(ol_device_handle_t Device, ol_queue_handle_t *Queue) {
- auto CreatedQueue = std::make_unique<ol_queue_impl_t>(nullptr, Device);
+Error olCreateQueue_impl(ol_context_handle_t Context, ol_device_handle_t Device,
+ ol_queue_handle_t *Queue) {
+ if (!Context->contains(Device))
+ return createOffloadError(ErrorCode::INVALID_DEVICE,
+ "device does not belong to the given context");
+
+ auto CreatedQueue =
+ std::make_unique<ol_queue_impl_t>(nullptr, Context, Device);
- auto OutstandingQueue = Device->getOutstandingQueue();
+ auto OutstandingQueue = Context->getOutstandingQueue(Device);
if (OutstandingQueue) {
// The queue is empty, but we still need to sync it to release any temporary
// memory allocations or do other cleanup.
@@ -856,8 +874,8 @@ Error olCreateQueue_impl(ol_device_handle_t Device, ol_queue_handle_t *Queue) {
Device->Device->synchronize(OutstandingQueue, /*Release=*/false))
return Err;
CreatedQueue->AsyncInfo = OutstandingQueue;
- } else if (auto Err =
- Device->Device->initAsyncInfo(&(CreatedQueue->AsyncInfo))) {
+ } else if (auto Err = Device->Device->initAsyncInfo(
+ &(CreatedQueue->AsyncInfo), Context->PluginCtx.get())) {
return Err;
}
@@ -867,6 +885,7 @@ Error olCreateQueue_impl(ol_device_handle_t Device, ol_queue_handle_t *Queue) {
Error olDestroyQueue_impl(ol_queue_handle_t Queue) {
auto *Device = Queue->Device;
+ auto *Context = Queue->Context;
// This is safe; as soon as olDestroyQueue is called it is not possible to add
// any more work to the queue, so if it's finished now it will remain finished
// forever.
@@ -881,8 +900,7 @@ Error olDestroyQueue_impl(ol_queue_handle_t Queue) {
return Err;
} else {
// The queue still has outstanding work. Store it so we can check it later.
- std::lock_guard<std::mutex> Lock(Device->OutstandingQueuesMutex);
- Device->OutstandingQueues.push_back(Queue->AsyncInfo);
+ Context->addOutstandingQueue(Device, Queue->AsyncInfo);
}
return olDestroy(Queue);
@@ -933,6 +951,8 @@ Error olGetQueueInfoImplDetail(ol_queue_handle_t Queue,
switch (PropName) {
case OL_QUEUE_INFO_DEVICE:
return Info.write<ol_device_handle_t>(Queue->Device);
+ case OL_QUEUE_INFO_CONTEXT:
+ return Info.write<ol_context_handle_t>(Queue->Context);
case OL_QUEUE_INFO_EMPTY: {
auto Pending = Queue->Device->Device->hasPendingWork(Queue->AsyncInfo);
if (auto Err = Pending.takeError())
diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index 67ebfbc943fdc..250f9d66a1afd 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -109,7 +109,8 @@ template <typename... ArgsTy>
/// operations when calling AsyncInfoWrapperTy::finalize(). This latter function
/// must be called before destroying the wrapper object.
struct AsyncInfoWrapperTy {
- AsyncInfoWrapperTy(GenericDeviceTy &Device, __tgt_async_info *AsyncInfoPtr);
+ AsyncInfoWrapperTy(GenericDeviceTy &Device, __tgt_async_info *AsyncInfoPtr,
+ PluginContextTy *Context = nullptr);
~AsyncInfoWrapperTy() {
assert(!AsyncInfoPtr && "AsyncInfoWrapperTy not finalized");
@@ -118,6 +119,10 @@ struct AsyncInfoWrapperTy {
/// Get the raw __tgt_async_info pointer.
operator __tgt_async_info *() const { return AsyncInfoPtr; }
+ /// Optional plugin-side context this async info is scoped to; null on the
+ /// libomptarget path.
+ PluginContextTy *getContext() const { return Context; }
+
/// Indicate whether there is queue.
bool hasQueue() const { return (AsyncInfoPtr->Queue != nullptr); }
@@ -177,6 +182,7 @@ struct AsyncInfoWrapperTy {
GenericDeviceTy &Device;
__tgt_async_info LocalAsyncInfo;
__tgt_async_info *AsyncInfoPtr;
+ PluginContextTy *Context = nullptr;
};
enum class DeviceInfo {
@@ -1104,8 +1110,10 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
KernelExtraArgsTy *KernelExtraArgs,
__tgt_async_info *AsyncInfo);
- /// Initialize a __tgt_async_info structure.
- Error initAsyncInfo(__tgt_async_info **AsyncInfoPtr);
+ /// Initialize a __tgt_async_info structure. \p Context is optional and is
+ /// forwarded on the wrapper for plugin impls that need it.
+ Error initAsyncInfo(__tgt_async_info **AsyncInfoPtr,
+ PluginContextTy *Context = nullptr);
virtual Error initAsyncInfoImpl(AsyncInfoWrapperTy &AsyncInfoWrapper) = 0;
/// Enqueue a host call to AsyncInfo
diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index 7b821e77df179..4c0f639e475a3 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -45,9 +45,11 @@ using namespace error;
using namespace llvm::offload::debug;
AsyncInfoWrapperTy::AsyncInfoWrapperTy(GenericDeviceTy &Device,
- __tgt_async_info *AsyncInfoPtr)
+ __tgt_async_info *AsyncInfoPtr,
+ PluginContextTy *Context)
: Device(Device),
- AsyncInfoPtr(AsyncInfoPtr ? AsyncInfoPtr : &LocalAsyncInfo) {}
+ AsyncInfoPtr(AsyncInfoPtr ? AsyncInfoPtr : &LocalAsyncInfo),
+ Context(Context) {}
Error AsyncInfoWrapperTy::synchronize() {
assert(AsyncInfoPtr && "AsyncInfoWrapperTy already finalized");
@@ -1206,12 +1208,13 @@ Error GenericDeviceTy::launchKernel(void *EntryPtr, void **ArgPtrs,
return Err;
}
-Error GenericDeviceTy::initAsyncInfo(__tgt_async_info **AsyncInfoPtr) {
+Error GenericDeviceTy::initAsyncInfo(__tgt_async_info **AsyncInfoPtr,
+ PluginContextTy *Context) {
assert(AsyncInfoPtr && "Invalid async info");
*AsyncInfoPtr = new __tgt_async_info();
- AsyncInfoWrapperTy AsyncInfoWrapper(*this, *AsyncInfoPtr);
+ AsyncInfoWrapperTy AsyncInfoWrapper(*this, *AsyncInfoPtr, Context);
auto Err = initAsyncInfoImpl(AsyncInfoWrapper);
AsyncInfoWrapper.finalize(Err);
diff --git a/offload/plugins-nextgen/level_zero/include/L0Context.h b/offload/plugins-nextgen/level_zero/include/L0Context.h
index 7bd082571b1a1..e052a274ec07a 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Context.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Context.h
@@ -20,6 +20,7 @@
namespace llvm::omp::target::plugin {
class LevelZeroPluginTy;
+class LevelZeroPluginContextTy;
class L0ContextTLSTy {
StagingBufferTy StagingBuffer;
@@ -65,6 +66,9 @@ class L0ContextTy {
/// Host Memory allocator for this driver.
MemAllocatorTy HostMemAllocator;
+ /// Default plugin-side context used by the libomptarget path.
+ std::unique_ptr<LevelZeroPluginContextTy> DefaultUserCtx;
+
public:
/// Named constants for checking the imported external pointer regions.
static constexpr int32_t ImportNotExist = -1;
@@ -73,8 +77,7 @@ class L0ContextTy {
/// Create context, initialize event pool and extension functions.
L0ContextTy(LevelZeroPluginTy &Plugin, ze_driver_handle_t zeDriver,
- int32_t DriverId)
- : Plugin(Plugin), zeDriver(zeDriver) {}
+ int32_t DriverId);
L0ContextTy(const L0ContextTy &) = delete;
L0ContextTy(L0ContextTy &&) = delete;
@@ -82,7 +85,7 @@ class L0ContextTy {
L0ContextTy &operator=(const L0ContextTy &&) = delete;
/// Release resources.
- ~L0ContextTy() = default;
+ ~L0ContextTy();
Error init();
Error deinit();
@@ -122,6 +125,11 @@ class L0ContextTy {
/// Return context associated with the driver.
ze_context_handle_t getZeContext() const { return zeContext; }
+ /// Return the default plugin-side context used by the libomptarget path.
+ LevelZeroPluginContextTy &getDefaultUserCtx() const {
+ return *DefaultUserCtx;
+ }
+
/// Return driver API version.
ze_api_version_t getDriverAPIVersion() const { return APIVersion; }
diff --git a/offload/plugins-nextgen/level_zero/include/L0Device.h b/offload/plugins-nextgen/level_zero/include/L0Device.h
index 3e8129d057095..314b2df3e9ddd 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Device.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Device.h
@@ -143,9 +143,6 @@ class L0DeviceTy final : public GenericDeviceTy {
/// MemAllocator for this device.
MemAllocatorTy MemAllocator;
- /// Cache of queues for this device.
- L0QueueCacheTy QueueCache;
-
DeviceArchTy computeArch() const;
/// Scan the device's command queue groups, selecting the default compute
@@ -163,7 +160,7 @@ class L0DeviceTy final : public GenericDeviceTy {
const std::string_view zeId, int32_t ComputeIndex)
: GenericDeviceTy(Plugin, DeviceId, NumDevices, SPIRVGridValues),
L0Context(DriverInfo), zeDevice(zeDevice), zeId(zeId),
- ComputeIndex(ComputeIndex), QueueCache(*this) {
+ ComputeIndex(ComputeIndex) {
DeviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES;
DeviceProperties.pNext = nullptr;
ComputeProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_COMPUTE_PROPERTIES;
@@ -369,11 +366,15 @@ class L0DeviceTy final : public GenericDeviceTy {
/// Create an immediate command list.
Expected<ze_command_list_handle_t>
- createImmCmdList(uint32_t Ordinal, uint32_t Index, bool InOrder = false);
+ createImmCmdList(uint32_t Ordinal, uint32_t Index, bool InOrder = false,
+ ze_context_handle_t UserZeCtx = nullptr);
/// Create an immediate command list for computing.
- Expected<ze_command_list_handle_t> createImmCmdList(bool InOrder = false) {
- return createImmCmdList(getComputeEngine(), getComputeIndex(), InOrder);
+ Expected<ze_command_list_handle_t>
+ createImmCmdList(bool InOrder = false,
+ ze_context_handle_t UserZeCtx = nullptr) {
+ return createImmCmdList(getComputeEngine(), getComputeIndex(), InOrder,
+ UserZeCtx);
}
/// Release an immediate command list.
@@ -382,8 +383,10 @@ class L0DeviceTy final : public GenericDeviceTy {
return Plugin::success();
}
- Expected<L0CmdListManagerTy *> getCmdListManager(bool InOrder = false) {
- auto CmdListOrErr = createImmCmdList(InOrder);
+ Expected<L0CmdListManagerTy *>
+ getCmdListManager(bool InOrder = false,
+ ze_context_handle_t UserZeCtx = nullptr) {
+ auto CmdListOrErr = createImmCmdList(InOrder, UserZeCtx);
if (!CmdListOrErr)
return CmdListOrErr.takeError();
return new L0CmdListManagerTy(*CmdListOrErr, L0Context);
@@ -470,7 +473,7 @@ class L0DeviceTy final : public GenericDeviceTy {
/// Returns the Queue from an async info object, or creates a new one if
/// the async info does not have a queue yet.
Expected<L0QueueTy *> getOrCreateQueue(__tgt_async_info *AsyncInfo);
- void releaseQueue(L0QueueTy *Queue) { QueueCache.releaseQueue(Queue); }
+ void releaseQueue(L0QueueTy *Queue);
// Allocation related routines.
diff --git a/offload/plugins-nextgen/level_zero/include/L0Plugin.h b/offload/plugins-nextgen/level_zero/include/L0Plugin.h
index 56a708b7609a4..f84e7cbeca0d2 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Plugin.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Plugin.h
@@ -17,6 +17,7 @@
#include "L0Memory.h"
#include "L0Options.h"
#include "L0Program.h"
+#include "L0Queue.h"
namespace llvm::omp::target::plugin {
@@ -29,17 +30,25 @@ class LevelZeroPluginContextTy final : public PluginContextTy {
ze_driver_handle_t Driver,
ze_context_handle_t ZeContext, bool OwnsZeContext)
: PluginContextTy(Plugin, Devices), Driver(Driver), ZeContext(ZeContext),
- OwnsZeContext(OwnsZeContext) {}
+ OwnsZeContext(OwnsZeContext), QueueCache(*this) {}
~LevelZeroPluginContextTy() override;
ze_driver_handle_t getZeDriver() const { return Driver; }
ze_context_handle_t getZeContext() const { return ZeContext; }
+ /// Pop an idle queue for \p Device from the cache, or create a new one.
+ Expected<L0QueueTy *> takeCachedQueue(L0DeviceTy *Device);
+
+ /// Return an idle queue to the cache.
+ void returnCachedQueue(L0DeviceTy *Device, L0QueueTy *Queue);
+
private:
ze_driver_handle_t Driver;
ze_context_handle_t ZeContext;
bool OwnsZeContext;
+
+ L0QueueCacheTy QueueCache;
};
/// Class implementing the LevelZero specific functionalities of the plugin.
diff --git a/offload/plugins-nextgen/level_zero/include/L0Queue.h b/offload/plugins-nextgen/level_zero/include/L0Queue.h
index 4ef2232c8da06..b027fdea63ced 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Queue.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Queue.h
@@ -25,6 +25,7 @@
namespace llvm::omp::target::plugin {
class L0DeviceTy;
+class LevelZeroPluginContextTy;
struct L0LaunchEnvTy;
/// Abstract queue that supports asynchronous command submission.
@@ -36,16 +37,21 @@ class L0QueueTy {
L0CmdListManagerTy *CmdList = nullptr;
/// Whether the queue is in-order or out-of-order.
bool CreateQueueInOrder;
+ /// Owning plugin-side context (never null on an active queue).
+ LevelZeroPluginContextTy *UserCtx = nullptr;
public:
L0QueueTy(L0DeviceTy &Device, bool IsInorder = true)
: Device(Device), CreateQueueInOrder(IsInorder) {}
virtual ~L0QueueTy() {}
+ LevelZeroPluginContextTy *getUserCtx() const { return UserCtx; }
+ void setUserCtx(LevelZeroPluginContextTy *Ctx) { UserCtx = Ctx; }
+
/// Clear data.
void reset() { resetImpl(); }
- Error init();
+ Error init(ze_context_handle_t UserZeCtx = nullptr);
Error deinit();
Error synchronize() { return synchronizeImpl(); }
Expected<bool> hasPendingWork() { return hasPendingWorkImpl(); }
@@ -271,17 +277,15 @@ class L0SyncQueueTy : public L0InorderQueueTy {
/// Simple cache for queue objects.
class L0QueueCacheTy {
- L0DeviceTy &Device;
- llvm::SmallVector<L0QueueTy *> Queues;
+ LevelZeroPluginContextTy &UserCtx;
+ llvm::DenseMap<L0DeviceTy *, llvm::SmallVector<L0QueueTy *>> Queues;
std::mutex Mtx;
- CommandModeTy CachedCmdMode = CommandModeTy::InOrder;
public:
- L0QueueCacheTy(L0DeviceTy &Device) : Device(Device) {}
- Expected<L0QueueTy *> getQueue();
- void releaseQueue(L0QueueTy *Queue);
+ L0QueueCacheTy(LevelZeroPluginContextTy &Ctx) : UserCtx(Ctx) {}
+ Expected<L0QueueTy *> getQueue(L0DeviceTy &Device);
+ void releaseQueue(L0DeviceTy &Device, L0QueueTy *Queue);
Error deinit();
- void setCommandMode(CommandModeTy CmdMode) { CachedCmdMode = CmdMode; }
};
} // namespace llvm::omp::target::plugin
diff --git a/offload/plugins-nextgen/level_zero/src/L0Context.cpp b/offload/plugins-nextgen/level_zero/src/L0Context.cpp
index be21a2fdc22ed..4cab00ff0b5e1 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Context.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Context.cpp
@@ -15,6 +15,12 @@
namespace llvm::omp::target::plugin {
+L0ContextTy::L0ContextTy(LevelZeroPluginTy &Plugin, ze_driver_handle_t zeDriver,
+ int32_t DriverId)
+ : Plugin(Plugin), zeDriver(zeDriver) {}
+
+L0ContextTy::~L0ContextTy() = default;
+
Error L0ContextTy::init() {
auto CleanupOnError = [&]() {
if (zeContext) {
@@ -68,10 +74,16 @@ Error L0ContextTy::init() {
if (RC != ZE_RESULT_SUCCESS)
zeDriverGetDefaultContext = nullptr;
+ DefaultUserCtx = std::make_unique<LevelZeroPluginContextTy>(
+ Plugin, /*Devices=*/llvm::ArrayRef<GenericDeviceTy *>{}, zeDriver,
+ zeContext, /*OwnsZeContext=*/false);
+
return Plugin::success();
}
Error L0ContextTy::deinit() {
+ // Release the default context (drains its queue cache) before zeContext.
+ DefaultUserCtx.reset();
if (auto Err = EventPool.deinit())
return Err;
if (auto Err = HostMemAllocator.deinit())
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index 076dfa080f86e..b7350613f7faa 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -196,7 +196,6 @@ Error L0DeviceTy::initImpl(GenericPluginTy &Plugin) {
if (!QueueGroupInfoOrErr)
return QueueGroupInfoOrErr.takeError();
QueueConfig = *QueueGroupInfoOrErr;
- QueueCache.setCommandMode(getPlugin().getOptions().CommandMode);
if (auto Err = MemAllocator.initDevicePools(*this, Options))
return Err;
@@ -209,8 +208,6 @@ Error L0DeviceTy::deinitImpl() {
for (auto &PGM : Programs)
if (auto Err = PGM.deinit())
return Err;
- if (auto Err = QueueCache.deinit())
- return Err;
return MemAllocator.deinit();
}
@@ -258,11 +255,17 @@ Error L0DeviceTy::unloadBinaryImpl(DeviceImageTy *Image) {
return Plugin::success();
}
+void L0DeviceTy::releaseQueue(L0QueueTy *Queue) {
+ if (!Queue)
+ return;
+ Queue->getUserCtx()->returnCachedQueue(this, Queue);
+}
+
Expected<L0QueueTy *>
L0DeviceTy::getOrCreateQueue(__tgt_async_info *AsyncInfo) {
L0QueueTy *Queue = static_cast<L0QueueTy *>(AsyncInfo->Queue);
if (!Queue) {
- auto NewQueueOrErr = QueueCache.getQueue();
+ auto NewQueueOrErr = L0Context.getDefaultUserCtx().takeCachedQueue(this);
if (!NewQueueOrErr)
return NewQueueOrErr.takeError();
Queue = *NewQueueOrErr;
@@ -398,8 +401,16 @@ Error L0DeviceTy::dataExchangeImpl(const void *SrcPtr, GenericDeviceTy &DstDev,
}
Error L0DeviceTy::initAsyncInfoImpl(AsyncInfoWrapperTy &AsyncInfoWrapper) {
- auto QueueOrErr = getOrCreateQueue(AsyncInfoWrapper);
- return QueueOrErr ? Plugin::success() : QueueOrErr.takeError();
+ __tgt_async_info *AsyncInfo = AsyncInfoWrapper;
+ auto *L0Ctx = AsyncInfoWrapper.getContext()
+ ? static_cast<LevelZeroPluginContextTy *>(
+ AsyncInfoWrapper.getContext())
+ : &L0Context.getDefaultUserCtx();
+ auto NewQueueOrErr = L0Ctx->takeCachedQueue(this);
+ if (!NewQueueOrErr)
+ return NewQueueOrErr.takeError();
+ AsyncInfo->Queue = *NewQueueOrErr;
+ return Plugin::success();
}
const char *L0DeviceTy::getArchCStr() const {
@@ -733,7 +744,8 @@ Error L0DeviceTy::makeMemoryResident(void *Mem, size_t Size) {
/// Create an immediate command list.
Expected<ze_command_list_handle_t>
-L0DeviceTy::createImmCmdList(uint32_t Ordinal, uint32_t Index, bool InOrder) {
+L0DeviceTy::createImmCmdList(uint32_t Ordinal, uint32_t Index, bool InOrder,
+ ze_context_handle_t UserZeCtx) {
ze_command_queue_flags_t Flags = InOrder ? ZE_COMMAND_QUEUE_FLAG_IN_ORDER : 0;
if (getPlugin().getOptions().Flags.UseCopyOffloadHint)
Flags |= ZE_COMMAND_QUEUE_FLAG_COPY_OFFLOAD_HINT;
@@ -746,8 +758,9 @@ L0DeviceTy::createImmCmdList(uint32_t Ordinal, uint32_t Index, bool InOrder) {
ZE_COMMAND_QUEUE_MODE_ASYNCHRONOUS,
ZE_COMMAND_QUEUE_PRIORITY_NORMAL};
ze_command_list_handle_t CmdList = nullptr;
- CALL_ZE_RET_ERROR(zeCommandListCreateImmediate, getZeContext(), getZeDevice(),
- &Desc, &CmdList);
+ ze_context_handle_t ZeCtx = UserZeCtx ? UserZeCtx : getZeContext();
+ CALL_ZE_RET_ERROR(zeCommandListCreateImmediate, ZeCtx, getZeDevice(), &Desc,
+ &CmdList);
ODBG(OLDT_Device) << "Created an immediate command list " << CmdList
<< " (Ordinal: " << Ordinal << ", Index: " << Index
<< ", Flags: " << Flags << ") for device " << getZeIdCStr();
diff --git a/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp b/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp
index 5723644c6763c..77b997d912864 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp
@@ -255,10 +255,25 @@ Error LevelZeroPluginTy::asyncBarrierImpl(omp_interop_val_t *Interop) {
}
LevelZeroPluginContextTy::~LevelZeroPluginContextTy() {
+ // TODO: this should be moved out of the destructor and into a deinit() method
+ if (auto Err = QueueCache.deinit()) {
+ REPORT() << "Error deinitializing LevelZeroPluginContextTy queue cache: "
+ << toString(std::move(Err));
+ }
if (OwnsZeContext && ZeContext)
zeContextDestroy(ZeContext);
}
+Expected<L0QueueTy *>
+LevelZeroPluginContextTy::takeCachedQueue(L0DeviceTy *Device) {
+ return QueueCache.getQueue(*Device);
+}
+
+void LevelZeroPluginContextTy::returnCachedQueue(L0DeviceTy *Device,
+ L0QueueTy *Queue) {
+ QueueCache.releaseQueue(*Device, Queue);
+}
+
Expected<std::unique_ptr<PluginContextTy>>
LevelZeroPluginTy::createPluginContext(
llvm::ArrayRef<GenericDeviceTy *> Devices) {
diff --git a/offload/plugins-nextgen/level_zero/src/L0Queue.cpp b/offload/plugins-nextgen/level_zero/src/L0Queue.cpp
index a27024ad66d19..0a3085642148e 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Queue.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Queue.cpp
@@ -24,8 +24,8 @@ namespace llvm::omp::target::plugin {
/// common methods
-Error L0QueueTy::init() {
- auto CmdListOrErr = Device.getCmdListManager(CreateQueueInOrder);
+Error L0QueueTy::init(ze_context_handle_t UserZeCtx) {
+ auto CmdListOrErr = Device.getCmdListManager(CreateQueueInOrder, UserZeCtx);
if (!CmdListOrErr)
return CmdListOrErr.takeError();
CmdList = *CmdListOrErr;
@@ -458,17 +458,18 @@ Error L0SyncQueueTy::hostCallImpl(void (*Callback)(void *), void *UserData) {
}
// L0QueueCache implementation.
-Expected<L0QueueTy *> L0QueueCacheTy::getQueue() {
+Expected<L0QueueTy *> L0QueueCacheTy::getQueue(L0DeviceTy &Device) {
{
std::lock_guard<std::mutex> Lock(Mtx);
- if (!Queues.empty()) {
- L0QueueTy *Queue = Queues.back();
- Queues.pop_back();
+ auto Itr = Queues.find(&Device);
+ if (Itr != Queues.end() && !Itr->second.empty()) {
+ L0QueueTy *Queue = Itr->second.back();
+ Itr->second.pop_back();
return Queue;
}
}
L0QueueTy *Queue = nullptr;
- switch (CachedCmdMode) {
+ switch (Device.getPlugin().getOptions().CommandMode) {
case CommandModeTy::Async:
Queue = new L0AsyncQueueTy(Device);
break;
@@ -482,28 +483,31 @@ Expected<L0QueueTy *> L0QueueCacheTy::getQueue() {
Queue = new L0InorderQueueTy(Device);
break;
}
- if (auto Err = Queue->init()) {
+ Queue->setUserCtx(&UserCtx);
+ if (auto Err = Queue->init(UserCtx.getZeContext())) {
delete Queue;
return std::move(Err);
}
return Queue;
}
-void L0QueueCacheTy::releaseQueue(L0QueueTy *Queue) {
+void L0QueueCacheTy::releaseQueue(L0DeviceTy &Device, L0QueueTy *Queue) {
if (!Queue)
return;
Queue->reset();
std::lock_guard<std::mutex> Lock(Mtx);
- Queues.push_back(Queue);
+ Queues[&Device].push_back(Queue);
}
Error L0QueueCacheTy::deinit() {
Error AllErrors = Error::success();
std::lock_guard<std::mutex> Lock(Mtx);
- for (auto *Queue : Queues) {
- if (auto Err = Queue->deinit())
- AllErrors = joinErrors(std::move(AllErrors), std::move(Err));
- delete Queue;
+ for (auto &Bucket : Queues) {
+ for (auto *Queue : Bucket.second) {
+ if (auto Err = Queue->deinit())
+ AllErrors = joinErrors(std::move(AllErrors), std::move(Err));
+ delete Queue;
+ }
}
Queues.clear();
return AllErrors;
diff --git a/offload/unittests/Conformance/include/mathtest/DeviceContext.hpp b/offload/unittests/Conformance/include/mathtest/DeviceContext.hpp
index 17ec7e95fb2be..2e23cd3f4b19a 100644
--- a/offload/unittests/Conformance/include/mathtest/DeviceContext.hpp
+++ b/offload/unittests/Conformance/include/mathtest/DeviceContext.hpp
@@ -56,6 +56,8 @@ class DeviceContext {
explicit DeviceContext(llvm::StringRef Platform, std::size_t DeviceId = 0);
+ ~DeviceContext();
+
template <typename T>
ManagedBuffer<T> createManagedBuffer(std::size_t Size) const noexcept {
void *UntypedAddress = nullptr;
@@ -137,6 +139,7 @@ class DeviceContext {
std::size_t GlobalDeviceId;
ol_device_handle_t DeviceHandle;
+ ol_context_handle_t Context = nullptr;
};
} // namespace mathtest
diff --git a/offload/unittests/Conformance/include/mathtest/OffloadForward.hpp b/offload/unittests/Conformance/include/mathtest/OffloadForward.hpp
index 788989a0d4211..f8a17cf05e29c 100644
--- a/offload/unittests/Conformance/include/mathtest/OffloadForward.hpp
+++ b/offload/unittests/Conformance/include/mathtest/OffloadForward.hpp
@@ -26,6 +26,9 @@ typedef const ol_error_struct_t *ol_result_t;
struct ol_device_impl_t;
typedef struct ol_device_impl_t *ol_device_handle_t;
+struct ol_context_impl_t;
+typedef struct ol_context_impl_t *ol_context_handle_t;
+
struct ol_program_impl_t;
typedef struct ol_program_impl_t *ol_program_handle_t;
diff --git a/offload/unittests/Conformance/lib/DeviceContext.cpp b/offload/unittests/Conformance/lib/DeviceContext.cpp
index 638831e405424..f3f0f8f394323 100644
--- a/offload/unittests/Conformance/lib/DeviceContext.cpp
+++ b/offload/unittests/Conformance/lib/DeviceContext.cpp
@@ -175,6 +175,7 @@ DeviceContext::DeviceContext(std::size_t GlobalDeviceId)
llvm::Twine(Devices.size()));
DeviceHandle = Devices[GlobalDeviceId].Handle;
+ OL_CHECK(olCreateContext(1, &DeviceHandle, &Context));
}
DeviceContext::DeviceContext(llvm::StringRef Platform, std::size_t DeviceId)
@@ -210,6 +211,12 @@ DeviceContext::DeviceContext(llvm::StringRef Platform, std::size_t DeviceId)
GlobalDeviceId = *FoundGlobalDeviceId;
DeviceHandle = Devices[GlobalDeviceId].Handle;
+ OL_CHECK(olCreateContext(1, &DeviceHandle, &Context));
+}
+
+DeviceContext::~DeviceContext() {
+ if (Context)
+ olDestroyContext(Context);
}
[[nodiscard]] llvm::Expected<std::shared_ptr<DeviceImage>>
diff --git a/offload/unittests/OffloadAPI/common/Fixtures.hpp b/offload/unittests/OffloadAPI/common/Fixtures.hpp
index f6b7502c41882..0d667db00a152 100644
--- a/offload/unittests/OffloadAPI/common/Fixtures.hpp
+++ b/offload/unittests/OffloadAPI/common/Fixtures.hpp
@@ -190,6 +190,14 @@ struct OffloadDeviceTest
Device = DeviceParam.Handle;
if (Device == nullptr)
GTEST_SKIP() << "No available devices.";
+
+ ASSERT_SUCCESS(olCreateContext(1, &Device, &Context));
+ }
+
+ void TearDown() override {
+ if (Context)
+ olDestroyContext(Context);
+ RETURN_ON_FATAL_FAILURE(OffloadTest::TearDown());
}
ol_platform_backend_t getPlatformBackend() const {
@@ -205,6 +213,7 @@ struct OffloadDeviceTest
}
ol_device_handle_t Device = nullptr;
+ ol_context_handle_t Context = nullptr;
};
struct OffloadPlatformTest : OffloadDeviceTest {
@@ -274,7 +283,7 @@ struct OffloadGlobalTest : OffloadProgramTest {
struct OffloadQueueTest : OffloadDeviceTest {
void SetUp() override {
RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::SetUp());
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue));
}
void TearDown() override {
diff --git a/offload/unittests/OffloadAPI/context/olCreateContext.cpp b/offload/unittests/OffloadAPI/context/olCreateContext.cpp
index 81777eb21e8ed..eb7dba1fd6196 100644
--- a/offload/unittests/OffloadAPI/context/olCreateContext.cpp
+++ b/offload/unittests/OffloadAPI/context/olCreateContext.cpp
@@ -10,7 +10,21 @@
#include <OffloadAPI.h>
#include <gtest/gtest.h>
-using olCreateContextTest = OffloadDeviceTest;
+// OffloadDeviceTest creates an ol_context_handle_t in SetUp; this fixture
+// stops at the device so the tests below can exercise olCreateContext.
+struct olCreateContextTest
+ : OffloadTest,
+ ::testing::WithParamInterface<TestEnvironment::Device> {
+ void SetUp() override {
+ RETURN_ON_FATAL_FAILURE(OffloadTest::SetUp());
+ auto DeviceParam = GetParam();
+ Device = DeviceParam.Handle;
+ if (Device == nullptr)
+ GTEST_SKIP() << "No available devices.";
+ }
+
+ ol_device_handle_t Device = nullptr;
+};
OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olCreateContextTest);
TEST_P(olCreateContextTest, Success) {
diff --git a/offload/unittests/OffloadAPI/context/olGetContextInfo.cpp b/offload/unittests/OffloadAPI/context/olGetContextInfo.cpp
index 14d911f786848..c41d23ce6c49f 100644
--- a/offload/unittests/OffloadAPI/context/olGetContextInfo.cpp
+++ b/offload/unittests/OffloadAPI/context/olGetContextInfo.cpp
@@ -10,20 +10,7 @@
#include <OffloadAPI.h>
#include <gtest/gtest.h>
-struct olGetContextInfoTest : OffloadDeviceTest {
- void SetUp() override {
- RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::SetUp());
- ASSERT_SUCCESS(olCreateContext(1, &Device, &Context));
- }
-
- void TearDown() override {
- if (Context)
- olDestroyContext(Context);
- RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::TearDown());
- }
-
- ol_context_handle_t Context = nullptr;
-};
+using olGetContextInfoTest = OffloadDeviceTest;
OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olGetContextInfoTest);
TEST_P(olGetContextInfoTest, SuccessNumDevices) {
diff --git a/offload/unittests/OffloadAPI/context/olGetContextInfoSize.cpp b/offload/unittests/OffloadAPI/context/olGetContextInfoSize.cpp
index 1af9298717eb1..2c7ad71859793 100644
--- a/offload/unittests/OffloadAPI/context/olGetContextInfoSize.cpp
+++ b/offload/unittests/OffloadAPI/context/olGetContextInfoSize.cpp
@@ -10,20 +10,7 @@
#include <OffloadAPI.h>
#include <gtest/gtest.h>
-struct olGetContextInfoSizeTest : OffloadDeviceTest {
- void SetUp() override {
- RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::SetUp());
- ASSERT_SUCCESS(olCreateContext(1, &Device, &Context));
- }
-
- void TearDown() override {
- if (Context)
- olDestroyContext(Context);
- RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::TearDown());
- }
-
- ol_context_handle_t Context = nullptr;
-};
+using olGetContextInfoSizeTest = OffloadDeviceTest;
OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olGetContextInfoSizeTest);
TEST_P(olGetContextInfoSizeTest, SuccessNumDevices) {
diff --git a/offload/unittests/OffloadAPI/kernel/olLaunchKernel.cpp b/offload/unittests/OffloadAPI/kernel/olLaunchKernel.cpp
index c159829e7e40e..a8840f713ca84 100644
--- a/offload/unittests/OffloadAPI/kernel/olLaunchKernel.cpp
+++ b/offload/unittests/OffloadAPI/kernel/olLaunchKernel.cpp
@@ -355,7 +355,7 @@ TEST_P(olLaunchKernelSingleCounterSyncEventTest, SuccessTwoQueues) {
ASSERT_SUCCESS(olSyncQueue(Queue));
ol_queue_handle_t Queue2 = nullptr;
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue2));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue2));
// For the explanation of the reasoning behind particular values assigned to
// parameters, see the comment in the Success test from the same test suite
diff --git a/offload/unittests/OffloadAPI/memory/olMemcpy.cpp b/offload/unittests/OffloadAPI/memory/olMemcpy.cpp
index 3d210e3d6d015..9ecc8b700b7f5 100644
--- a/offload/unittests/OffloadAPI/memory/olMemcpy.cpp
+++ b/offload/unittests/OffloadAPI/memory/olMemcpy.cpp
@@ -20,7 +20,7 @@ struct olMemcpyGlobalTest : OffloadGlobalTest {
olGetSymbol(Program, "read", OL_SYMBOL_KIND_KERNEL, &ReadKernel));
ASSERT_SUCCESS(
olGetSymbol(Program, "write", OL_SYMBOL_KIND_KERNEL, &WriteKernel));
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue));
ASSERT_SUCCESS(olGetSymbolInfo(
Global, OL_SYMBOL_INFO_GLOBAL_VARIABLE_ADDRESS, sizeof(Addr), &Addr));
diff --git a/offload/unittests/OffloadAPI/queue/olCreateQueue.cpp b/offload/unittests/OffloadAPI/queue/olCreateQueue.cpp
index 8a2b964c6ed42..986b84702d866 100644
--- a/offload/unittests/OffloadAPI/queue/olCreateQueue.cpp
+++ b/offload/unittests/OffloadAPI/queue/olCreateQueue.cpp
@@ -15,15 +15,31 @@ OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olCreateQueueTest);
TEST_P(olCreateQueueTest, Success) {
ol_queue_handle_t Queue = nullptr;
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue));
ASSERT_NE(Queue, nullptr);
+ ASSERT_SUCCESS(olDestroyQueue(Queue));
+}
+
+TEST_P(olCreateQueueTest, InvalidNullHandleContext) {
+ ol_queue_handle_t Queue = nullptr;
+ ASSERT_ERROR(OL_ERRC_INVALID_NULL_HANDLE,
+ olCreateQueue(nullptr, Device, &Queue));
}
TEST_P(olCreateQueueTest, InvalidNullHandleDevice) {
ol_queue_handle_t Queue = nullptr;
- ASSERT_ERROR(OL_ERRC_INVALID_NULL_HANDLE, olCreateQueue(nullptr, &Queue));
+ ASSERT_ERROR(OL_ERRC_INVALID_NULL_HANDLE,
+ olCreateQueue(Context, nullptr, &Queue));
}
TEST_P(olCreateQueueTest, InvalidNullPointerQueue) {
- ASSERT_ERROR(OL_ERRC_INVALID_NULL_POINTER, olCreateQueue(Device, nullptr));
+ ASSERT_ERROR(OL_ERRC_INVALID_NULL_POINTER,
+ olCreateQueue(Context, Device, nullptr));
+}
+
+TEST_P(olCreateQueueTest, InvalidDeviceNotInContext) {
+ if (Host == Device)
+ GTEST_SKIP() << "Host device is the fixture device; cannot test.";
+ ol_queue_handle_t Queue = nullptr;
+ ASSERT_ERROR(OL_ERRC_INVALID_DEVICE, olCreateQueue(Context, Host, &Queue));
}
diff --git a/offload/unittests/OffloadAPI/queue/olGetQueueInfo.cpp b/offload/unittests/OffloadAPI/queue/olGetQueueInfo.cpp
index 2dccd33005563..f40319a04a2de 100644
--- a/offload/unittests/OffloadAPI/queue/olGetQueueInfo.cpp
+++ b/offload/unittests/OffloadAPI/queue/olGetQueueInfo.cpp
@@ -20,6 +20,14 @@ TEST_P(olGetQueueInfoTest, SuccessDevice) {
ASSERT_EQ(Device, RetrievedDevice);
}
+TEST_P(olGetQueueInfoTest, SuccessContext) {
+ ol_context_handle_t RetrievedContext;
+ ASSERT_SUCCESS(olGetQueueInfo(Queue, OL_QUEUE_INFO_CONTEXT,
+ sizeof(ol_context_handle_t),
+ &RetrievedContext));
+ ASSERT_EQ(Context, RetrievedContext);
+}
+
TEST_P(olGetQueueInfoTest, SuccessEmpty) {
bool Empty;
ASSERT_SUCCESS(
diff --git a/offload/unittests/OffloadAPI/queue/olGetQueueInfoSize.cpp b/offload/unittests/OffloadAPI/queue/olGetQueueInfoSize.cpp
index 735dad6a29384..3163f74d71d96 100644
--- a/offload/unittests/OffloadAPI/queue/olGetQueueInfoSize.cpp
+++ b/offload/unittests/OffloadAPI/queue/olGetQueueInfoSize.cpp
@@ -19,6 +19,12 @@ TEST_P(olGetQueueInfoSizeTest, SuccessDevice) {
ASSERT_EQ(Size, sizeof(ol_device_handle_t));
}
+TEST_P(olGetQueueInfoSizeTest, SuccessContext) {
+ size_t Size = 0;
+ ASSERT_SUCCESS(olGetQueueInfoSize(Queue, OL_QUEUE_INFO_CONTEXT, &Size));
+ ASSERT_EQ(Size, sizeof(ol_context_handle_t));
+}
+
TEST_P(olGetQueueInfoSizeTest, SuccessEmpty) {
size_t Size = 0;
ASSERT_SUCCESS(olGetQueueInfoSize(Queue, OL_QUEUE_INFO_EMPTY, &Size));
diff --git a/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp b/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp
index 28d9b78c35f76..1dedf7ecaaefd 100644
--- a/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp
+++ b/offload/unittests/OffloadAPI/queue/olLaunchHostFunction.cpp
@@ -57,7 +57,7 @@ TEST_P(olLaunchHostFunctionKernelTest, SuccessBlocking) {
LaunchArgs.DynSharedMemory = 0;
ol_queue_handle_t Queue;
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue));
void *Mem;
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
diff --git a/offload/unittests/OffloadAPI/queue/olWaitEvents.cpp b/offload/unittests/OffloadAPI/queue/olWaitEvents.cpp
index 6396b7cd0a748..112785c1a066f 100644
--- a/offload/unittests/OffloadAPI/queue/olWaitEvents.cpp
+++ b/offload/unittests/OffloadAPI/queue/olWaitEvents.cpp
@@ -45,7 +45,7 @@ TEST_P(olWaitEventsTest, Success) {
for (size_t I = 0; I < NUM_KERNELS; I++) {
Idx = I;
- ASSERT_SUCCESS(olCreateQueue(Device, &Queues[I]));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queues[I]));
if (I > 0)
ASSERT_SUCCESS(olWaitEvents(Queues[I], &Events[I - 1], 1));
@@ -68,7 +68,7 @@ TEST_P(olWaitEventsTest, SuccessSingleQueue) {
ol_queue_handle_t Queue;
ol_event_handle_t Events[NUM_KERNELS];
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue));
void *Mem;
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
@@ -111,7 +111,7 @@ TEST_P(olWaitEventsTest, SuccessMultipleEvents) {
for (size_t I = 0; I < NUM_KERNELS; I++) {
Idx = I;
- ASSERT_SUCCESS(olCreateQueue(Device, &Queues[I]));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queues[I]));
if (I > 0)
ASSERT_SUCCESS(olWaitEvents(Queues[I], Events, I));
@@ -136,13 +136,13 @@ TEST_P(olWaitEventsTest, InvalidNullQueue) {
TEST_P(olWaitEventsTest, InvalidNullEvent) {
ol_queue_handle_t Queue;
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue));
ASSERT_ERROR(OL_ERRC_INVALID_NULL_POINTER, olWaitEvents(Queue, nullptr, 1));
}
TEST_P(olWaitEventsTest, InvalidNullInnerEvent) {
ol_queue_handle_t Queue;
- ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
+ ASSERT_SUCCESS(olCreateQueue(Context, Device, &Queue));
ol_event_handle_t Event = nullptr;
ASSERT_ERROR(OL_ERRC_INVALID_NULL_HANDLE, olWaitEvents(Queue, &Event, 1));
}
>From 123808069827d7cec9f286fa06de2e35446eaa83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Plewa?= <lukasz.plewa at intel.com>
Date: Fri, 31 Jul 2026 16:16:16 +0200
Subject: [PATCH 2/2] review fixes
---
offload/liboffload/src/OffloadImpl.cpp | 3 +++
.../common/include/PluginInterface.h | 5 ++++
.../level_zero/include/L0Device.h | 7 ++++--
.../level_zero/include/L0Plugin.h | 12 ++++++---
.../level_zero/src/L0Context.cpp | 6 ++++-
.../level_zero/src/L0Device.cpp | 20 ++++++---------
.../level_zero/src/L0Plugin.cpp | 25 ++++++-------------
7 files changed, 43 insertions(+), 35 deletions(-)
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index d6a2b466cb92d..40f5ef6ce8b27 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -641,6 +641,9 @@ Error olCreateContext_impl(size_t DevicesCount, ol_device_handle_t *Devices,
Error olDestroyContext_impl(ol_context_handle_t Context) {
if (auto Err = Context->drainOutstandingQueues())
return Err;
+ if (Context->PluginCtx)
+ if (auto Err = Context->PluginCtx->deinit())
+ return Err;
return olDestroy(Context);
}
diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index 250f9d66a1afd..ae62b7f12e631 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -880,6 +880,11 @@ struct PluginContextTy {
virtual ~PluginContextTy() = default;
+ /// Release resources owned by this context. Called from olDestroyContext
+ /// before the object is destroyed so that errors are propagated instead of
+ /// being swallowed in the destructor.
+ virtual llvm::Error deinit() { return llvm::Error::success(); }
+
llvm::ArrayRef<GenericDeviceTy *> getDevices() const { return Devices; }
GenericPluginTy &getPlugin() const { return Plugin; }
diff --git a/offload/plugins-nextgen/level_zero/include/L0Device.h b/offload/plugins-nextgen/level_zero/include/L0Device.h
index 314b2df3e9ddd..71e545ad89231 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Device.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Device.h
@@ -471,8 +471,11 @@ class L0DeviceTy final : public GenericDeviceTy {
bool supportsLargeMem() const { return L0Context.supportsLargeMem(); }
/// Returns the Queue from an async info object, or creates a new one if
- /// the async info does not have a queue yet.
- Expected<L0QueueTy *> getOrCreateQueue(__tgt_async_info *AsyncInfo);
+ /// the async info does not have a queue yet. When \p UserCtx is null the
+ /// driver's default plugin-side context is used.
+ Expected<L0QueueTy *>
+ getOrCreateQueue(__tgt_async_info *AsyncInfo,
+ LevelZeroPluginContextTy *UserCtx = nullptr);
void releaseQueue(L0QueueTy *Queue);
// Allocation related routines.
diff --git a/offload/plugins-nextgen/level_zero/include/L0Plugin.h b/offload/plugins-nextgen/level_zero/include/L0Plugin.h
index f84e7cbeca0d2..3909f1a9e48e4 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Plugin.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Plugin.h
@@ -32,16 +32,22 @@ class LevelZeroPluginContextTy final : public PluginContextTy {
: PluginContextTy(Plugin, Devices), Driver(Driver), ZeContext(ZeContext),
OwnsZeContext(OwnsZeContext), QueueCache(*this) {}
- ~LevelZeroPluginContextTy() override;
+ ~LevelZeroPluginContextTy() override = default;
+
+ Error deinit() override;
ze_driver_handle_t getZeDriver() const { return Driver; }
ze_context_handle_t getZeContext() const { return ZeContext; }
/// Pop an idle queue for \p Device from the cache, or create a new one.
- Expected<L0QueueTy *> takeCachedQueue(L0DeviceTy *Device);
+ Expected<L0QueueTy *> takeCachedQueue(L0DeviceTy *Device) {
+ return QueueCache.getQueue(*Device);
+ }
/// Return an idle queue to the cache.
- void returnCachedQueue(L0DeviceTy *Device, L0QueueTy *Queue);
+ void returnCachedQueue(L0DeviceTy *Device, L0QueueTy *Queue) {
+ QueueCache.releaseQueue(*Device, Queue);
+ }
private:
ze_driver_handle_t Driver;
diff --git a/offload/plugins-nextgen/level_zero/src/L0Context.cpp b/offload/plugins-nextgen/level_zero/src/L0Context.cpp
index 4cab00ff0b5e1..cdcd1210cbcf1 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Context.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Context.cpp
@@ -83,7 +83,11 @@ Error L0ContextTy::init() {
Error L0ContextTy::deinit() {
// Release the default context (drains its queue cache) before zeContext.
- DefaultUserCtx.reset();
+ if (DefaultUserCtx) {
+ if (auto Err = DefaultUserCtx->deinit())
+ return Err;
+ DefaultUserCtx.reset();
+ }
if (auto Err = EventPool.deinit())
return Err;
if (auto Err = HostMemAllocator.deinit())
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index b7350613f7faa..e3460891f3f52 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -262,10 +262,12 @@ void L0DeviceTy::releaseQueue(L0QueueTy *Queue) {
}
Expected<L0QueueTy *>
-L0DeviceTy::getOrCreateQueue(__tgt_async_info *AsyncInfo) {
+L0DeviceTy::getOrCreateQueue(__tgt_async_info *AsyncInfo,
+ LevelZeroPluginContextTy *UserCtx) {
L0QueueTy *Queue = static_cast<L0QueueTy *>(AsyncInfo->Queue);
if (!Queue) {
- auto NewQueueOrErr = L0Context.getDefaultUserCtx().takeCachedQueue(this);
+ auto &Ctx = UserCtx ? *UserCtx : L0Context.getDefaultUserCtx();
+ auto NewQueueOrErr = Ctx.takeCachedQueue(this);
if (!NewQueueOrErr)
return NewQueueOrErr.takeError();
Queue = *NewQueueOrErr;
@@ -401,16 +403,10 @@ Error L0DeviceTy::dataExchangeImpl(const void *SrcPtr, GenericDeviceTy &DstDev,
}
Error L0DeviceTy::initAsyncInfoImpl(AsyncInfoWrapperTy &AsyncInfoWrapper) {
- __tgt_async_info *AsyncInfo = AsyncInfoWrapper;
- auto *L0Ctx = AsyncInfoWrapper.getContext()
- ? static_cast<LevelZeroPluginContextTy *>(
- AsyncInfoWrapper.getContext())
- : &L0Context.getDefaultUserCtx();
- auto NewQueueOrErr = L0Ctx->takeCachedQueue(this);
- if (!NewQueueOrErr)
- return NewQueueOrErr.takeError();
- AsyncInfo->Queue = *NewQueueOrErr;
- return Plugin::success();
+ auto *UserCtx =
+ static_cast<LevelZeroPluginContextTy *>(AsyncInfoWrapper.getContext());
+ auto QueueOrErr = getOrCreateQueue(AsyncInfoWrapper, UserCtx);
+ return QueueOrErr ? Plugin::success() : QueueOrErr.takeError();
}
const char *L0DeviceTy::getArchCStr() const {
diff --git a/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp b/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp
index 77b997d912864..be6b31eeb1167 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Plugin.cpp
@@ -254,24 +254,15 @@ Error LevelZeroPluginTy::asyncBarrierImpl(omp_interop_val_t *Interop) {
return Plugin::success();
}
-LevelZeroPluginContextTy::~LevelZeroPluginContextTy() {
- // TODO: this should be moved out of the destructor and into a deinit() method
- if (auto Err = QueueCache.deinit()) {
- REPORT() << "Error deinitializing LevelZeroPluginContextTy queue cache: "
- << toString(std::move(Err));
+Error LevelZeroPluginContextTy::deinit() {
+ if (auto Err = QueueCache.deinit())
+ return Err;
+ if (OwnsZeContext && ZeContext) {
+ CALL_ZE_RET_ERROR(zeContextDestroy, ZeContext);
+ ZeContext = nullptr;
+ OwnsZeContext = false;
}
- if (OwnsZeContext && ZeContext)
- zeContextDestroy(ZeContext);
-}
-
-Expected<L0QueueTy *>
-LevelZeroPluginContextTy::takeCachedQueue(L0DeviceTy *Device) {
- return QueueCache.getQueue(*Device);
-}
-
-void LevelZeroPluginContextTy::returnCachedQueue(L0DeviceTy *Device,
- L0QueueTy *Queue) {
- QueueCache.releaseQueue(*Device, Queue);
+ return Plugin::success();
}
Expected<std::unique_ptr<PluginContextTy>>
More information about the llvm-commits
mailing list