Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[OFFLOAD][L0] Implement Event APIs#201306

Merged
adurang merged 7 commits into
llvm:mainfrom
adurang:event_apis
Jun 4, 2026
Merged

[OFFLOAD][L0] Implement Event APIs#201306
adurang merged 7 commits into
llvm:mainfrom
adurang:event_apis

Conversation

@adurang
Copy link
Copy Markdown
Contributor

@adurang adurang commented Jun 3, 2026

Introduce a new L0EventTy type used to implement most of the Event APIs of PluginInterface (all but getEventElapsedTimeImpl).

@llvmorg-github-actions
Copy link
Copy Markdown

@llvm/pr-subscribers-offload

Author: Alex Duran (adurang)

Changes

Introduce a new L0EventTy type used to implement most of the Event APIs of PluginInterface (all but getEventElapsedTimeImpl).


Patch is 23.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/201306.diff

12 Files Affected:

  • (modified) offload/plugins-nextgen/level_zero/CMakeLists.txt (+1)
  • (modified) offload/plugins-nextgen/level_zero/dynamic_l0/L0DynWrapper.cpp (+3)
  • (modified) offload/plugins-nextgen/level_zero/dynamic_l0/level_zero/ze_api.h (+9)
  • (modified) offload/plugins-nextgen/level_zero/include/L0CmdListManager.h (+18)
  • (modified) offload/plugins-nextgen/level_zero/include/L0Context.h (+1)
  • (modified) offload/plugins-nextgen/level_zero/include/L0Device.h (+14-35)
  • (added) offload/plugins-nextgen/level_zero/include/L0Event.h (+124)
  • (modified) offload/plugins-nextgen/level_zero/include/L0Memory.h (-52)
  • (modified) offload/plugins-nextgen/level_zero/include/L0Queue.h (+37)
  • (modified) offload/plugins-nextgen/level_zero/src/L0Device.cpp (+61)
  • (added) offload/plugins-nextgen/level_zero/src/L0Event.cpp (+93)
  • (modified) offload/plugins-nextgen/level_zero/src/L0Memory.cpp (-50)
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...
[truncated]

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.


/// 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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using GenericDeviceResourceManagerTy for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the structure and internal behavior are really different.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to modify the generic manager to cover this use case as well. I will try it when I have some free time.

Comment thread offload/plugins-nextgen/level_zero/include/L0Queue.h
Comment thread offload/plugins-nextgen/level_zero/src/L0Device.cpp Outdated
Copy link
Copy Markdown
Member

@sarnex sarnex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as usual not qualified to review algorithm

Comment thread offload/plugins-nextgen/level_zero/include/L0Event.h Outdated
Comment thread offload/plugins-nextgen/level_zero/include/L0Event.h Outdated
Comment thread offload/plugins-nextgen/level_zero/src/L0Event.cpp Outdated
Comment thread offload/plugins-nextgen/level_zero/src/L0Event.cpp Outdated
Copy link
Copy Markdown
Member

@sarnex sarnex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm but should wait for an approval from someone on the logic

Comment thread offload/plugins-nextgen/level_zero/src/L0Device.cpp Outdated
Comment thread offload/plugins-nextgen/level_zero/include/L0Event.h
Comment thread offload/plugins-nextgen/level_zero/include/L0Event.h
Comment thread offload/plugins-nextgen/level_zero/include/L0Device.h

/// 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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to modify the generic manager to cover this use case as well. I will try it when I have some free time.

@adurang
Copy link
Copy Markdown
Contributor Author

adurang commented Jun 4, 2026

@kevinsala I added a bit more documentation to the routines. Let me know if you think if it needs further clarifications.

Comment thread offload/plugins-nextgen/level_zero/src/L0Device.cpp Outdated
Copy link
Copy Markdown
Contributor

@kevinsala kevinsala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks

@adurang adurang merged commit 7b4d5d0 into llvm:main Jun 4, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants