[llvm] [OFFLOAD][L0] Implement Event APIs (PR #201306)
Alex Duran via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 3 23:50:24 PDT 2026
https://github.com/adurang updated https://github.com/llvm/llvm-project/pull/201306
>From 0b381b100489581626288303ea3c00196569895f Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Wed, 3 Jun 2026 03:12:52 -0700
Subject: [PATCH 1/7] [OFFLOAD][L0] Implement Event APIs
---
.../plugins-nextgen/level_zero/CMakeLists.txt | 1 +
.../level_zero/dynamic_l0/L0DynWrapper.cpp | 3 +
.../level_zero/dynamic_l0/level_zero/ze_api.h | 9 ++
.../level_zero/include/L0CmdListManager.h | 18 +++
.../level_zero/include/L0Context.h | 1 +
.../level_zero/include/L0Device.h | 49 ++-----
.../level_zero/include/L0Event.h | 124 ++++++++++++++++++
.../level_zero/include/L0Memory.h | 52 --------
.../level_zero/include/L0Queue.h | 37 ++++++
.../level_zero/src/L0Device.cpp | 61 +++++++++
.../level_zero/src/L0Event.cpp | 93 +++++++++++++
.../level_zero/src/L0Memory.cpp | 50 -------
12 files changed, 361 insertions(+), 137 deletions(-)
create mode 100644 offload/plugins-nextgen/level_zero/include/L0Event.h
create mode 100644 offload/plugins-nextgen/level_zero/src/L0Event.cpp
diff --git a/offload/plugins-nextgen/level_zero/CMakeLists.txt b/offload/plugins-nextgen/level_zero/CMakeLists.txt
index c11f436861284..c40a375166f8b 100644
--- a/offload/plugins-nextgen/level_zero/CMakeLists.txt
+++ b/offload/plugins-nextgen/level_zero/CMakeLists.txt
@@ -11,6 +11,7 @@ add_target_library(omptarget.rtl.level_zero LEVEL_ZERO)
set(LEVEL_ZERO_SRC_FILES
src/L0Context.cpp
src/L0Device.cpp
+ src/L0Event.cpp
src/L0Kernel.cpp
src/L0Memory.cpp
src/L0Program.cpp
diff --git a/offload/plugins-nextgen/level_zero/dynamic_l0/L0DynWrapper.cpp b/offload/plugins-nextgen/level_zero/dynamic_l0/L0DynWrapper.cpp
index a338e1f024d2c..0e19c6373340a 100644
--- a/offload/plugins-nextgen/level_zero/dynamic_l0/L0DynWrapper.cpp
+++ b/offload/plugins-nextgen/level_zero/dynamic_l0/L0DynWrapper.cpp
@@ -91,6 +91,9 @@ DLWRAP(zeModuleGetFunctionPointer, 3)
DLWRAP(zesDeviceEnumMemoryModules, 3)
DLWRAP(zesMemoryGetState, 2)
DLWRAP(zeCommandListHostSynchronize, 2)
+DLWRAP(zeCommandListAppendSignalEvent, 2)
+DLWRAP(zeCommandListAppendWaitOnEvents, 3)
+DLWRAP(zeEventQueryStatus, 1)
DLWRAP_FINALIZE()
diff --git a/offload/plugins-nextgen/level_zero/dynamic_l0/level_zero/ze_api.h b/offload/plugins-nextgen/level_zero/dynamic_l0/level_zero/ze_api.h
index 1e011c2a933a5..b3214378e5da1 100644
--- a/offload/plugins-nextgen/level_zero/dynamic_l0/level_zero/ze_api.h
+++ b/offload/plugins-nextgen/level_zero/dynamic_l0/level_zero/ze_api.h
@@ -862,6 +862,15 @@ ZE_APIEXPORT ze_result_t ZE_APICALL
zeEventHostSynchronize(ze_event_handle_t hEvent, uint64_t timeout);
ZE_APIEXPORT ze_result_t ZE_APICALL zeEventQueryKernelTimestamp(
ze_event_handle_t hEvent, ze_kernel_timestamp_result_t *dstptr);
+ZE_APIEXPORT ze_result_t ZE_APICALL
+zeEventQueryStatus(ze_event_handle_t hEvent);
+
+/* Event append functions on command lists */
+ZE_APIEXPORT ze_result_t ZE_APICALL zeCommandListAppendSignalEvent(
+ ze_command_list_handle_t hCommandList, ze_event_handle_t hEvent);
+ZE_APIEXPORT ze_result_t ZE_APICALL zeCommandListAppendWaitOnEvents(
+ ze_command_list_handle_t hCommandList, uint32_t numEvents,
+ ze_event_handle_t *phEvents);
/* Fence functions */
ZE_APIEXPORT ze_result_t ZE_APICALL
diff --git a/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h b/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
index ec4906a1636e9..f17c1149d88cb 100644
--- a/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
+++ b/offload/plugins-nextgen/level_zero/include/L0CmdListManager.h
@@ -127,6 +127,24 @@ class L0CmdListManagerTy {
return Plugin::success();
}
+ Error appendSignalEvent(ze_event_handle_t Event) {
+ std::lock_guard<std::mutex> Lock(Mtx);
+ CALL_ZE_RET_ERROR(zeCommandListAppendSignalEvent, CmdList, Event);
+ return Plugin::success();
+ }
+
+ Error appendWaitOnEvents(size_t NumWaitEvents,
+ ze_event_handle_t *WaitEvents) {
+ std::lock_guard<std::mutex> Lock(Mtx);
+ CALL_ZE_RET_ERROR(zeCommandListAppendWaitOnEvents, CmdList, NumWaitEvents,
+ WaitEvents);
+ return Plugin::success();
+ }
+
+ Error appendWaitOnEvent(ze_event_handle_t Event) {
+ return appendWaitOnEvents(1, &Event);
+ }
+
Error appendBarrier(ze_event_handle_t SignalEvent, uint32_t NumWaitEvents,
ze_event_handle_t *WaitEvents) {
std::lock_guard<std::mutex> Lock(Mtx);
diff --git a/offload/plugins-nextgen/level_zero/include/L0Context.h b/offload/plugins-nextgen/level_zero/include/L0Context.h
index 14cb6da9c8da6..3ea68d8dd07a1 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Context.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Context.h
@@ -13,6 +13,7 @@
#ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0CONTEXT_H
#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0CONTEXT_H
+#include "L0Event.h"
#include "L0Memory.h"
#include "PerThreadTable.h"
diff --git a/offload/plugins-nextgen/level_zero/include/L0Device.h b/offload/plugins-nextgen/level_zero/include/L0Device.h
index f2f75a9d904bf..eb0cfba504188 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Device.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Device.h
@@ -423,10 +423,16 @@ class L0DeviceTy final : public GenericDeviceTy {
Expected<ze_event_handle_t> getEvent() {
return l0Context.getEventPool().getEvent();
}
+ Expected<L0EventTy *> getEventObject() {
+ return l0Context.getEventPool().getEventObject();
+ }
/// Release event to the pool associated to this device.
Error releaseEvent(ze_event_handle_t Event) {
- return l0Context.getEventPool().releaseEvent(Event, *this);
+ return l0Context.getEventPool().releaseEvent(Event);
+ }
+ Error releaseEventObject(L0EventTy *EventObj) {
+ return l0Context.getEventPool().releaseEventObject(EventObj);
}
StagingBufferTy &getStagingBuffer() { return l0Context.getStagingBuffer(); }
@@ -518,44 +524,17 @@ class L0DeviceTy final : public GenericDeviceTy {
"enqueueHostCallImpl not implemented yet");
}
- // Event routines are used to ensure ordering between dataTransfers. Instead
- // of adding extra events in the queues, we make sure they're ordered by
- // using the events from the data submission APIs so we don't need to support
- // these routines.
- // They still need to report succes to indicate the event are handled
- // somewhere waitEvent and syncEvent should remain unimplemented.
Expected<bool> isEventCompleteImpl(void *EventPtr,
- AsyncInfoWrapperTy &) override {
- return true;
- }
-
- Error createEventImpl(void **EventPtrStorage, bool EnableProfiling) override {
- return Plugin::success();
- }
- Error destroyEventImpl(void *EventPtr, bool EnableProfiling) override {
- return Plugin::success();
- }
+ AsyncInfoWrapperTy &) override;
+ Error createEventImpl(void **EventPtrStorage, bool EnableProfiling) override;
+ Error destroyEventImpl(void *EventPtr, bool EnableProfiling) override;
Error recordEventImpl(void *EventPtr, AsyncInfoWrapperTy &AsyncInfoWrapper,
- bool EnableProfiling) override {
- return Plugin::success();
- }
-
+ bool EnableProfiling) override;
Error waitEventImpl(void *EventPtr,
- AsyncInfoWrapperTy &AsyncInfoWrapper) override {
- return Plugin::error(error::ErrorCode::UNKNOWN, "%s not implemented yet\n",
- __func__);
- }
-
- Error syncEventImpl(void *EventPtr) override {
- return Plugin::error(error::ErrorCode::UNKNOWN, "%s not implemented yet\n",
- __func__);
- }
-
+ AsyncInfoWrapperTy &AsyncInfoWrapper) override;
+ Error syncEventImpl(void *EventPtr) override;
Expected<float> getEventElapsedTimeImpl(void *StartEventPtr,
- void *EndEventPtr) override {
- return Plugin::error(error::ErrorCode::UNKNOWN, "%s not implemented yet\n",
- __func__);
- }
+ void *EndEventPtr) override;
Expected<InfoTreeNode> obtainInfoImpl() override;
uint64_t getClockFrequency() const override { return getClockRate(); }
diff --git a/offload/plugins-nextgen/level_zero/include/L0Event.h b/offload/plugins-nextgen/level_zero/include/L0Event.h
new file mode 100644
index 0000000000000..0400fa33c29d5
--- /dev/null
+++ b/offload/plugins-nextgen/level_zero/include/L0Event.h
@@ -0,0 +1,124 @@
+//===--- Level Zero Target RTL Implementation -----------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Level Zero Event and Event Pool abstractions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0EVENT_H
+#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0EVENT_H
+
+#include <level_zero/ze_api.h>
+#include <memory>
+#include <mutex>
+
+#include "L0Defs.h"
+#include "L0Trace.h"
+
+namespace llvm::omp::target::plugin {
+
+class L0QueueTy;
+
+
+class L0EventTy {
+ ze_event_handle_t ZeEvent;
+ L0QueueTy *Queue = nullptr;
+
+public:
+ L0EventTy(ze_event_handle_t ZeEvent)
+ : ZeEvent(ZeEvent) {}
+ ze_event_handle_t getZeEvent() const { return ZeEvent; }
+ L0QueueTy *getQueue() const { return Queue; }
+
+ Error reset () {
+ Queue = nullptr;
+ CALL_ZE_RET_ERROR(zeEventHostReset, ZeEvent);
+ return Plugin::success();
+ }
+
+ void recordQueue(L0QueueTy &Q) { Queue = &Q; }
+
+ Error synchronize() {
+ CALL_ZE_RET_ERROR(zeEventHostSynchronize, ZeEvent, L0DefaultTimeout);
+ return Plugin::success();
+ }
+
+ Expected<bool> isComplete() {
+ ze_result_t Result;
+
+ CALL_ZE(Result, zeEventQueryStatus, ZeEvent);
+ if (Result == ZE_RESULT_SUCCESS)
+ return true;
+ if (Result == ZE_RESULT_NOT_READY)
+ return false;
+ return Plugin::error(ErrorCode::UNKNOWN, "failed to query event status: %s",
+ getZeErrorName(Result));
+ }
+};
+
+/// Common event pool used in the plugin. This event pool assumes all events
+/// from the pool are host-visible and use the same event pool flag.
+class EventPoolTy {
+ /// Size of L0 event pool created on demand.
+ size_t PoolSize = 64;
+
+ /// Context of the events.
+ ze_context_handle_t Context = nullptr;
+
+ /// Additional event pool flags common to this pool.
+ uint32_t Flags = 0;
+
+ /// Protection.
+ std::unique_ptr<std::mutex> Mtx;
+
+ /// Created L0 event pools.
+ llvm::SmallVector<ze_event_pool_handle_t> Pools;
+
+ /// L0 events cache.
+ llvm::SmallVector<ze_event_handle_t> Events;
+
+ /// L0 event objects cache.
+ llvm::SmallVector<L0EventTy *> EventObjects;
+
+ // Internal method to get an event from the pool. The caller must hold the lock.
+ Expected<ze_event_handle_t> getEventLocked();
+public:
+ /// Initialize context, flags, and mutex.
+ Error init(ze_context_handle_t ContextIn, uint32_t FlagsIn) {
+ Context = ContextIn;
+ Flags = FlagsIn;
+ Mtx.reset(new std::mutex);
+ return Plugin::success();
+ }
+
+ /// Destroys L0 resources.
+ Error deinit() {
+ for (auto *EventObj : EventObjects)
+ delete EventObj;
+ for (auto E : Events)
+ CALL_ZE_RET_ERROR(zeEventDestroy, E);
+ for (auto P : Pools)
+ CALL_ZE_RET_ERROR(zeEventPoolDestroy, P);
+ return Plugin::success();
+ }
+
+ /// Get a free event from the pool.
+ Expected<ze_event_handle_t> getEvent() {
+ std::lock_guard<std::mutex> Lock(*Mtx);
+ return getEventLocked();
+ }
+ Expected<L0EventTy *> getEventObject();
+
+ /// Return an event to the pool.
+ Error releaseEvent(ze_event_handle_t Event);
+ Error releaseEventObject(L0EventTy *EventObj);
+};
+
+} // namespace llvm::omp::target::plugin
+
+#endif // OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_L0EVENT_H
diff --git a/offload/plugins-nextgen/level_zero/include/L0Memory.h b/offload/plugins-nextgen/level_zero/include/L0Memory.h
index 2e0f43497eb2f..e666062d005eb 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Memory.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Memory.h
@@ -422,58 +422,6 @@ class MemAllocatorTy {
}
}; /// MemAllocatorTy
-/// Common event pool used in the plugin. This event pool assumes all events
-/// from the pool are host-visible and use the same event pool flag.
-class EventPoolTy {
- /// Size of L0 event pool created on demand.
- size_t PoolSize = 64;
-
- /// Context of the events.
- ze_context_handle_t Context = nullptr;
-
- /// Additional event pool flags common to this pull.
- uint32_t Flags = 0;
-
- /// Protection.
- std::unique_ptr<std::mutex> Mtx;
-
- /// List of created L0 event pools.
- std::list<ze_event_pool_handle_t> Pools;
-
- /// List of free L0 events.
- std::list<ze_event_handle_t> Events;
-
-#ifdef OMPT_SUPPORT
- /// Event to OMPT record map. The timestamp information is recorded to the
- /// OMPT record before the event is recycled.
- std::unordered_map<ze_event_handle_t, ompt_record_ompt_t *> EventToRecord;
-#endif // OMPT_SUPPORT
-
-public:
- /// Initialize context, flags, and mutex.
- Error init(ze_context_handle_t ContextIn, uint32_t FlagsIn) {
- Context = ContextIn;
- Flags = FlagsIn;
- Mtx.reset(new std::mutex);
- return Plugin::success();
- }
-
- /// Destroys L0 resources.
- Error deinit() {
- for (auto E : Events)
- CALL_ZE_RET_ERROR(zeEventDestroy, E);
- for (auto P : Pools)
- CALL_ZE_RET_ERROR(zeEventPoolDestroy, P);
- return Plugin::success();
- }
-
- /// Get a free event from the pool.
- Expected<ze_event_handle_t> getEvent();
-
- /// Return an event to the pool.
- Error releaseEvent(ze_event_handle_t Event, L0DeviceTy &Device);
-};
-
/// Staging buffer.
/// A single staging buffer is not enough when batching is enabled since there
/// can be multiple pending copy operations.
diff --git a/offload/plugins-nextgen/level_zero/include/L0Queue.h b/offload/plugins-nextgen/level_zero/include/L0Queue.h
index 4f888b997e120..ee5b9491ca2ec 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Queue.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Queue.h
@@ -14,6 +14,7 @@
#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_LEVEL_ZERO_ASYNCQUEUE_H
#include "L0Defs.h"
+#include "L0Event.h"
#include "L0Trace.h"
#include "PluginInterface.h"
@@ -83,12 +84,38 @@ class L0QueueTy {
Error dataFence() { return dataFenceImpl(); }
+ Error appendSignalEvent(L0EventTy *Event) {
+ return appendSignalEventImpl(Event->getZeEvent());
+ }
+ Error appendWaitOnEvent(L0EventTy *Event) {
+ if (Event->getQueue() == this)
+ return Plugin::success();
+ return appendWaitOnEventImpl(Event->getZeEvent());
+ }
+ Error synchronizeEvent(L0EventTy *Event) {
+ if (hasPendingMemoryCopies())
+ if (auto Err = synchronize())
+ return Err;
+ return Event->synchronize();
+ }
+ Expected<bool> isEventComplete(L0EventTy *Event) {
+ if (hasPendingMemoryCopies()) {
+ auto PendingWorkOrErr = hasPendingWork();
+ if (!PendingWorkOrErr)
+ return PendingWorkOrErr.takeError();
+ if (*PendingWorkOrErr)
+ return false;
+ }
+ return Event->isComplete();
+ }
+
virtual Error initImpl() { return Plugin::success(); }
virtual Error deinitImpl() { return Plugin::success(); }
virtual void resetImpl() {}
virtual Error synchronizeImpl() = 0;
virtual Expected<bool> hasPendingWorkImpl() = 0;
+ virtual bool hasPendingMemoryCopies() { return false; }
virtual Error memoryCopyImpl(void *Dst, const void *Src, size_t Size) = 0;
virtual Error dataRetrieveImpl(void *HstPtr, const void *TgtPtr,
int64_t Size) {
@@ -105,6 +132,13 @@ class L0QueueTy {
return CmdList->appendMemoryFill(Ptr, Pattern, PatternSize, Size);
}
virtual Error dataFenceImpl() = 0;
+
+ virtual Error appendSignalEventImpl(ze_event_handle_t Event) {
+ return CmdList->appendSignalEvent(Event);
+ }
+ virtual Error appendWaitOnEventImpl(ze_event_handle_t Event) {
+ return CmdList->appendWaitOnEvent(Event);
+ }
};
class L0AsyncQueueTy : public L0QueueTy {
@@ -143,6 +177,9 @@ class L0AsyncQueueTy : public L0QueueTy {
void resetImpl() override;
Error synchronizeImpl() override;
Expected<bool> hasPendingWorkImpl() override;
+ bool hasPendingMemoryCopies() override {
+ return !H2MList.empty() || !USM2MList.empty();
+ }
Error memoryCopyImpl(void *Dst, const void *Src, size_t Size) override;
Error dataRetrieveImpl(void *HstPtr, const void *TgtPtr,
int64_t Size) override;
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index 1afed11b965f0..389005ce9e99a 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -12,6 +12,7 @@
#include "L0Device.h"
#include "L0Defs.h"
+#include "L0Event.h"
#include "L0Interop.h"
#include "L0Plugin.h"
#include "L0Program.h"
@@ -745,6 +746,66 @@ Expected<bool> L0DeviceTy::isAccessiblePtrImpl(const void *Ptr, size_t Size) {
return getMemAllocator(Ptr).contains(Ptr, Size);
}
+Error L0DeviceTy::createEventImpl(void **EventPtrStorage,
+ bool EnableProfiling) {
+ auto EventOrErr = getEventObject();
+ if (!EventOrErr)
+ return EventOrErr.takeError();
+ *EventPtrStorage = *EventOrErr;
+ ;
+ return Plugin::success();
+}
+
+Error L0DeviceTy::destroyEventImpl(void *EventPtr, bool EnableProfiling) {
+ L0EventTy *Event = static_cast<L0EventTy *>(EventPtr);
+ return releaseEventObject(Event);
+}
+
+Error L0DeviceTy::recordEventImpl(void *EventPtr,
+ AsyncInfoWrapperTy &AsyncInfoWrapper,
+ bool EnableProfiling) {
+ auto QueueOrErr = getOrCreateQueue(AsyncInfoWrapper);
+ if (!QueueOrErr)
+ return QueueOrErr.takeError();
+ L0QueueTy *Queue = *QueueOrErr;
+ L0EventTy *Event = static_cast<L0EventTy *>(EventPtr);
+ Event->recordQueue(*Queue);
+ return Queue->appendSignalEvent(Event);
+}
+
+Error L0DeviceTy::waitEventImpl(void *EventPtr,
+ AsyncInfoWrapperTy &AsyncInfoWrapper) {
+ auto QueueOrErr = getOrCreateQueue(AsyncInfoWrapper);
+ if (!QueueOrErr)
+ return QueueOrErr.takeError();
+ L0QueueTy *Queue = *QueueOrErr;
+ L0EventTy *Event = static_cast<L0EventTy *>(EventPtr);
+ return Queue->appendWaitOnEvent(Event);
+}
+
+Error L0DeviceTy::syncEventImpl(void *EventPtr) {
+ L0EventTy *Event = static_cast<L0EventTy *>(EventPtr);
+ if (!Event->getQueue())
+ return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+ "event does not have any associated queue");
+ return Event->getQueue()->synchronizeEvent(Event);
+}
+
+Expected<bool> L0DeviceTy::isEventCompleteImpl(void *EventPtr,
+ AsyncInfoWrapperTy &) {
+ L0EventTy *Event = static_cast<L0EventTy *>(EventPtr);
+ if (!Event->getQueue())
+ return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+ "event does not have any associated queue");
+ return Event->getQueue()->isEventComplete(Event);
+}
+
+Expected<float> L0DeviceTy::getEventElapsedTimeImpl(void *StartEventPtr,
+ void *EndEventPtr) {
+ return Plugin::error(error::ErrorCode::UNKNOWN, "%s not implemented yet\n",
+ __func__);
+}
+
Error L0DeviceTy::callGlobalConstructors(GenericPluginTy &Plugin,
DeviceImageTy &Image) {
return callGlobalCtorDtorCommon(Plugin, Image, /*IsCtor=*/true);
diff --git a/offload/plugins-nextgen/level_zero/src/L0Event.cpp b/offload/plugins-nextgen/level_zero/src/L0Event.cpp
new file mode 100644
index 0000000000000..7dd60acbe2a51
--- /dev/null
+++ b/offload/plugins-nextgen/level_zero/src/L0Event.cpp
@@ -0,0 +1,93 @@
+//===--- Level Zero Target RTL Implementation -----------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Level Zero Event and Event Pool implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "L0Event.h"
+#include "L0Device.h"
+#include "L0Trace.h"
+
+namespace llvm::omp::target::plugin {
+
+Expected<ze_event_handle_t> EventPoolTy::getEventLocked() {
+ if (Events.empty()) {
+ // Need to create a new L0 pool.
+ ze_event_pool_desc_t Desc{ZE_STRUCTURE_TYPE_EVENT_POOL_DESC, nullptr, 0, 0};
+ Desc.flags = ZE_EVENT_POOL_FLAG_HOST_VISIBLE | Flags;
+ Desc.count = PoolSize;
+ ze_event_pool_handle_t Pool;
+ CALL_ZE_RET_ERROR(zeEventPoolCreate, Context, &Desc, 0, nullptr, &Pool);
+ Pools.push_back(Pool);
+
+ // Create events.
+ ze_event_desc_t EventDesc{ZE_STRUCTURE_TYPE_EVENT_DESC, nullptr, 0, 0, 0};
+ EventDesc.wait = 0;
+ EventDesc.signal = ZE_EVENT_SCOPE_FLAG_HOST;
+ uint32_t CreatedEvents = 0;
+ for (uint32_t I = 0; I < PoolSize; I++) {
+ EventDesc.index = I;
+ ze_event_handle_t Event;
+ ze_result_t RC;
+ CALL_ZE(RC, zeEventCreate, Pool, &EventDesc, &Event);
+ if (RC != ZE_RESULT_SUCCESS) {
+ // Log the error and skip this event.
+ ODBG(OLDT_Init) << "Warning: zeEventCreate failed at index " << I
+ << " with code " << RC << ". Skipping this event.";
+ continue;
+ }
+ Events.push_back(Event);
+ CreatedEvents++;
+ }
+ PoolSize = CreatedEvents;
+ ODBG(OLDT_Init) << "Created a new event pool " << Pool << " with "
+ << PoolSize << " events";
+ }
+
+ auto Ret = Events.back();
+ Events.pop_back();
+
+ return Ret;
+}
+
+/// Return an event to the pool.
+Error EventPoolTy::releaseEvent(ze_event_handle_t Event) {
+ std::lock_guard<std::mutex> Lock(*Mtx);
+ CALL_ZE_RET_ERROR(zeEventHostReset, Event);
+ Events.push_back(Event);
+ return Plugin::success();
+}
+
+Expected<L0EventTy *> EventPoolTy::getEventObject() {
+ std::lock_guard<std::mutex> Lock(*Mtx);
+
+ if (EventObjects.empty()) {
+ auto EventOrErr = getEventLocked();
+ if (!EventOrErr)
+ return EventOrErr.takeError();
+ auto Event = *EventOrErr;
+ auto *EventObj = new L0EventTy(Event);
+ return EventObj;
+ }
+
+ auto *Ret = EventObjects.back();
+ if (auto Err = Ret->reset())
+ return std::move(Err);
+
+ EventObjects.pop_back();
+ return Ret;
+}
+
+Error EventPoolTy::releaseEventObject(L0EventTy *EventObj) {
+ std::lock_guard<std::mutex> Lock(*Mtx);
+ EventObjects.push_back(EventObj);
+ return Plugin::success();
+}
+
+} // namespace llvm::omp::target::plugin
diff --git a/offload/plugins-nextgen/level_zero/src/L0Memory.cpp b/offload/plugins-nextgen/level_zero/src/L0Memory.cpp
index 828ea426c5a7b..7aa25ea529d08 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Memory.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Memory.cpp
@@ -696,54 +696,4 @@ Error MemAllocatorTy::deallocFromL0(void *Ptr) {
return Plugin::success();
}
-Expected<ze_event_handle_t> EventPoolTy::getEvent() {
- std::lock_guard<std::mutex> Lock(*Mtx);
-
- if (Events.empty()) {
- // Need to create a new L0 pool.
- ze_event_pool_desc_t Desc{ZE_STRUCTURE_TYPE_EVENT_POOL_DESC, nullptr, 0, 0};
- Desc.flags = ZE_EVENT_POOL_FLAG_HOST_VISIBLE | Flags;
- Desc.count = PoolSize;
- ze_event_pool_handle_t Pool;
- CALL_ZE_RET_ERROR(zeEventPoolCreate, Context, &Desc, 0, nullptr, &Pool);
- Pools.push_back(Pool);
-
- // Create events.
- ze_event_desc_t EventDesc{ZE_STRUCTURE_TYPE_EVENT_DESC, nullptr, 0, 0, 0};
- EventDesc.wait = 0;
- EventDesc.signal = ZE_EVENT_SCOPE_FLAG_HOST;
- uint32_t CreatedEvents = 0;
- for (uint32_t I = 0; I < PoolSize; I++) {
- EventDesc.index = I;
- ze_event_handle_t Event;
- ze_result_t RC;
- CALL_ZE(RC, zeEventCreate, Pool, &EventDesc, &Event);
- if (RC != ZE_RESULT_SUCCESS) {
- // Log the error and skip this event.
- ODBG(OLDT_Init) << "Warning: zeEventCreate failed at index " << I
- << " with code " << RC << ". Skipping this event.";
- continue;
- }
- Events.push_back(Event);
- CreatedEvents++;
- }
- PoolSize = CreatedEvents;
- ODBG(OLDT_Init) << "Created a new event pool " << Pool << " with "
- << PoolSize << " events";
- }
-
- auto Ret = Events.back();
- Events.pop_back();
-
- return Ret;
-}
-
-/// Return an event to the pool.
-Error EventPoolTy::releaseEvent(ze_event_handle_t Event, L0DeviceTy &Device) {
- std::lock_guard<std::mutex> Lock(*Mtx);
- CALL_ZE_RET_ERROR(zeEventHostReset, Event);
- Events.push_back(Event);
- return Plugin::success();
-}
-
} // namespace llvm::omp::target::plugin
>From df219b1fc4e14ec868e423baf16dacf1cc7d7ce6 Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Wed, 3 Jun 2026 03:20:21 -0700
Subject: [PATCH 2/7] format
---
offload/plugins-nextgen/level_zero/include/L0Event.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/offload/plugins-nextgen/level_zero/include/L0Event.h b/offload/plugins-nextgen/level_zero/include/L0Event.h
index 0400fa33c29d5..50c8badf37f43 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Event.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Event.h
@@ -24,18 +24,16 @@ namespace llvm::omp::target::plugin {
class L0QueueTy;
-
class L0EventTy {
ze_event_handle_t ZeEvent;
L0QueueTy *Queue = nullptr;
public:
- L0EventTy(ze_event_handle_t ZeEvent)
- : ZeEvent(ZeEvent) {}
+ L0EventTy(ze_event_handle_t ZeEvent) : ZeEvent(ZeEvent) {}
ze_event_handle_t getZeEvent() const { return ZeEvent; }
L0QueueTy *getQueue() const { return Queue; }
- Error reset () {
+ Error reset() {
Queue = nullptr;
CALL_ZE_RET_ERROR(zeEventHostReset, ZeEvent);
return Plugin::success();
@@ -85,8 +83,10 @@ class EventPoolTy {
/// L0 event objects cache.
llvm::SmallVector<L0EventTy *> EventObjects;
- // Internal method to get an event from the pool. The caller must hold the lock.
+ // Internal method to get an event from the pool. The caller must hold the
+ // lock.
Expected<ze_event_handle_t> getEventLocked();
+
public:
/// Initialize context, flags, and mutex.
Error init(ze_context_handle_t ContextIn, uint32_t FlagsIn) {
>From 3aac9e97e28a01b57badee6192031a14acb4ceef Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Wed, 3 Jun 2026 12:45:18 -0700
Subject: [PATCH 3/7] Address comments
---
.../plugins-nextgen/level_zero/include/L0Event.h | 4 ++--
offload/plugins-nextgen/level_zero/src/L0Device.cpp | 2 +-
offload/plugins-nextgen/level_zero/src/L0Event.cpp | 13 ++++++++-----
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/offload/plugins-nextgen/level_zero/include/L0Event.h b/offload/plugins-nextgen/level_zero/include/L0Event.h
index 50c8badf37f43..fc01bdcca7ace 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Event.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Event.h
@@ -25,7 +25,7 @@ namespace llvm::omp::target::plugin {
class L0QueueTy;
class L0EventTy {
- ze_event_handle_t ZeEvent;
+ ze_event_handle_t ZeEvent = nullptr;
L0QueueTy *Queue = nullptr;
public:
@@ -39,7 +39,7 @@ class L0EventTy {
return Plugin::success();
}
- void recordQueue(L0QueueTy &Q) { Queue = &Q; }
+ void setQueue(L0QueueTy &Q) { Queue = &Q; }
Error synchronize() {
CALL_ZE_RET_ERROR(zeEventHostSynchronize, ZeEvent, L0DefaultTimeout);
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index 389005ce9e99a..bd2d39f9b3a5e 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -769,7 +769,7 @@ Error L0DeviceTy::recordEventImpl(void *EventPtr,
return QueueOrErr.takeError();
L0QueueTy *Queue = *QueueOrErr;
L0EventTy *Event = static_cast<L0EventTy *>(EventPtr);
- Event->recordQueue(*Queue);
+ Event->setQueue(*Queue);
return Queue->appendSignalEvent(Event);
}
diff --git a/offload/plugins-nextgen/level_zero/src/L0Event.cpp b/offload/plugins-nextgen/level_zero/src/L0Event.cpp
index 7dd60acbe2a51..cb70df71da74d 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Event.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Event.cpp
@@ -19,9 +19,12 @@ namespace llvm::omp::target::plugin {
Expected<ze_event_handle_t> EventPoolTy::getEventLocked() {
if (Events.empty()) {
// Need to create a new L0 pool.
- ze_event_pool_desc_t Desc{ZE_STRUCTURE_TYPE_EVENT_POOL_DESC, nullptr, 0, 0};
+ ze_event_pool_desc_t Desc{/* stype */ ZE_STRUCTURE_TYPE_EVENT_POOL_DESC,
+ /* pNext */ nullptr,
+ /* flags */ 0,
+ /* count */ 0};
Desc.flags = ZE_EVENT_POOL_FLAG_HOST_VISIBLE | Flags;
- Desc.count = PoolSize;
+ Desc.count = static_cast<uint32_t>(PoolSize);
ze_event_pool_handle_t Pool;
CALL_ZE_RET_ERROR(zeEventPoolCreate, Context, &Desc, 0, nullptr, &Pool);
Pools.push_back(Pool);
@@ -31,14 +34,14 @@ Expected<ze_event_handle_t> EventPoolTy::getEventLocked() {
EventDesc.wait = 0;
EventDesc.signal = ZE_EVENT_SCOPE_FLAG_HOST;
uint32_t CreatedEvents = 0;
- for (uint32_t I = 0; I < PoolSize; I++) {
- EventDesc.index = I;
+ for (uint32_t EventIdx = 0; EventIdx < PoolSize; EventIdx++) {
+ EventDesc.index = EventIdx;
ze_event_handle_t Event;
ze_result_t RC;
CALL_ZE(RC, zeEventCreate, Pool, &EventDesc, &Event);
if (RC != ZE_RESULT_SUCCESS) {
// Log the error and skip this event.
- ODBG(OLDT_Init) << "Warning: zeEventCreate failed at index " << I
+ ODBG(OLDT_Init) << "Warning: zeEventCreate failed at index " << EventIdx
<< " with code " << RC << ". Skipping this event.";
continue;
}
>From 1b16059be63f5b562746d1db1af7d6a87fee0344 Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Wed, 3 Jun 2026 13:07:44 -0700
Subject: [PATCH 4/7] rm ;
---
offload/plugins-nextgen/level_zero/src/L0Device.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index bd2d39f9b3a5e..b6994fa98d9fd 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -752,7 +752,6 @@ Error L0DeviceTy::createEventImpl(void **EventPtrStorage,
if (!EventOrErr)
return EventOrErr.takeError();
*EventPtrStorage = *EventOrErr;
- ;
return Plugin::success();
}
>From 9a1cfd55aea087fc410a3e2a8829860c079fa4f7 Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Wed, 3 Jun 2026 23:25:54 -0700
Subject: [PATCH 5/7] Document new routines
---
offload/plugins-nextgen/level_zero/include/L0Device.h | 7 +++++--
offload/plugins-nextgen/level_zero/include/L0Event.h | 9 +++++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/offload/plugins-nextgen/level_zero/include/L0Device.h b/offload/plugins-nextgen/level_zero/include/L0Device.h
index eb0cfba504188..275182faebfd6 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Device.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Device.h
@@ -419,18 +419,21 @@ class L0DeviceTy final : public GenericDeviceTy {
return l0Context.getDriverAPIVersion();
}
- /// Return an event from the driver associated to this device.
+ /// Get a low-level L0 event from the driver associated to this device.
Expected<ze_event_handle_t> getEvent() {
return l0Context.getEventPool().getEvent();
}
+ /// Get a high-level L0EventTy object from the driver associated to this
+ /// device.
Expected<L0EventTy *> getEventObject() {
return l0Context.getEventPool().getEventObject();
}
- /// Release event to the pool associated to this device.
+ /// Release a L0 event to the pool associated to this device.
Error releaseEvent(ze_event_handle_t Event) {
return l0Context.getEventPool().releaseEvent(Event);
}
+ /// Release an L0EventTy object to the pool associated to this device.
Error releaseEventObject(L0EventTy *EventObj) {
return l0Context.getEventPool().releaseEventObject(EventObj);
}
diff --git a/offload/plugins-nextgen/level_zero/include/L0Event.h b/offload/plugins-nextgen/level_zero/include/L0Event.h
index fc01bdcca7ace..82361e4c74200 100644
--- a/offload/plugins-nextgen/level_zero/include/L0Event.h
+++ b/offload/plugins-nextgen/level_zero/include/L0Event.h
@@ -107,15 +107,20 @@ class EventPoolTy {
return Plugin::success();
}
- /// Get a free event from the pool.
+ /// Get a L0 Event (ze_event_handle_t) from the pool.
Expected<ze_event_handle_t> getEvent() {
std::lock_guard<std::mutex> Lock(*Mtx);
return getEventLocked();
}
+ /// Get an L0EventTy object that wraps a ze_event_handle_t from the pool.
+ /// This is the preferred way to get an event unless a raw event is really
+ /// needed.
Expected<L0EventTy *> getEventObject();
- /// Return an event to the pool.
+ /// Return a ze_event_handle_t to the pool.
Error releaseEvent(ze_event_handle_t Event);
+ /// Returns an L0EventTy object to the pool so it can be reused. This does not
+ /// return the underlying ze_event_handle_t to the handle pool.
Error releaseEventObject(L0EventTy *EventObj);
};
>From a15bae84a55d7be1cc8639f00c7a913f91b32ae7 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Thu, 4 Jun 2026 08:33:07 +0200
Subject: [PATCH 6/7] Update
offload/plugins-nextgen/level_zero/src/L0Device.cpp
Co-authored-by: Kevin Sala Penades <kevinsala.ks at gmail.com>
---
offload/plugins-nextgen/level_zero/src/L0Device.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index b6994fa98d9fd..bf8394939d8d3 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -801,7 +801,7 @@ Expected<bool> L0DeviceTy::isEventCompleteImpl(void *EventPtr,
Expected<float> L0DeviceTy::getEventElapsedTimeImpl(void *StartEventPtr,
void *EndEventPtr) {
- return Plugin::error(error::ErrorCode::UNKNOWN, "%s not implemented yet\n",
+ return Plugin::error(error::ErrorCode::UNSUPPORTED, "%s not implemented yet\n",
__func__);
}
>From 0d4212dd2b131dcc1f3cf2fdb53c4d6287016d15 Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Wed, 3 Jun 2026 23:50:09 -0700
Subject: [PATCH 7/7] format
---
offload/plugins-nextgen/level_zero/src/L0Device.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/offload/plugins-nextgen/level_zero/src/L0Device.cpp b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
index bf8394939d8d3..3f3922036c8c3 100644
--- a/offload/plugins-nextgen/level_zero/src/L0Device.cpp
+++ b/offload/plugins-nextgen/level_zero/src/L0Device.cpp
@@ -801,8 +801,8 @@ Expected<bool> L0DeviceTy::isEventCompleteImpl(void *EventPtr,
Expected<float> L0DeviceTy::getEventElapsedTimeImpl(void *StartEventPtr,
void *EndEventPtr) {
- return Plugin::error(error::ErrorCode::UNSUPPORTED, "%s not implemented yet\n",
- __func__);
+ return Plugin::error(error::ErrorCode::UNSUPPORTED,
+ "%s not implemented yet\n", __func__);
}
Error L0DeviceTy::callGlobalConstructors(GenericPluginTy &Plugin,
More information about the llvm-commits
mailing list