[llvm] [offload] Allow replay repetitions and report basic timing (PR #193388)

Kevin Sala Penades via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 21 18:56:06 PDT 2026


https://github.com/kevinsala updated https://github.com/llvm/llvm-project/pull/193388

>From 639fdce40904eacaf07409967c039ffd493688bb Mon Sep 17 00:00:00 2001
From: Kevin Sala <salapenades1 at llnl.gov>
Date: Tue, 21 Apr 2026 18:35:01 -0700
Subject: [PATCH 1/3] [offload] Allow replay repetitions and report basic
 timing

---
 offload/include/Shared/APITypes.h             |  6 ++
 offload/include/omptarget.h                   |  2 +-
 offload/libomptarget/interface.cpp            |  7 +-
 offload/libomptarget/omptarget.cpp            | 11 ++-
 offload/libomptarget/private.h                |  2 +-
 .../common/include/RecordReplay.h             | 22 ++++++
 .../common/src/RecordReplay.cpp               | 69 ++++++++++++++-----
 .../kernelreplay/llvm-omp-kernel-replay.cpp   | 50 +++++++++-----
 8 files changed, 127 insertions(+), 42 deletions(-)

diff --git a/offload/include/Shared/APITypes.h b/offload/include/Shared/APITypes.h
index 40824596c3b9b..488ae68106d8f 100644
--- a/offload/include/Shared/APITypes.h
+++ b/offload/include/Shared/APITypes.h
@@ -134,6 +134,12 @@ struct KernelReplayOutcomeTy {
   /// The path to the file that stores the output memory snapshot after the
   /// kernel has been replayed.
   llvm::SmallString<128> OutputFilepath;
+  /// The execution time of the kernel replay in nanoseconds. This time includes
+  /// the the kernel launch and synchronization time. Replay I/O is excluded.
+  uint64_t KernelReplayTimeNano = 0;
+  /// The pointer to the device memory allocation used to replay. This can be
+  /// reused for future replays of the same kernel.
+  void *ReplayDeviceAlloc = nullptr;
 };
 
 /// Extra kernel arguments managed by the runtime components. Notice these
diff --git a/offload/include/omptarget.h b/offload/include/omptarget.h
index 0234e8fc55245..7cb306dcf6b2e 100644
--- a/offload/include/omptarget.h
+++ b/offload/include/omptarget.h
@@ -427,7 +427,7 @@ void __tgt_target_nowait_query(void **AsyncHandle);
 /// Executes a target kernel by replaying recorded kernel arguments and
 /// device memory.
 int __tgt_target_kernel_replay(
-    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory,
+    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory, void *ReusableDeviceAlloc,
     int64_t DeviceMemorySize, const llvm::offloading::EntryTy *Globals,
     int32_t NumGlobals, void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs,
     int32_t NumTeams, int32_t ThreadLimit, uint32_t SharedMemorySize,
diff --git a/offload/libomptarget/interface.cpp b/offload/libomptarget/interface.cpp
index 9dd206d140c18..576d7c52ba62a 100644
--- a/offload/libomptarget/interface.cpp
+++ b/offload/libomptarget/interface.cpp
@@ -509,6 +509,9 @@ EXTERN int __tgt_activate_record_replay(int64_t DeviceId, uint64_t MemorySize,
 /// \param DeviceMemory A pointer to an array storing device memory data to move
 ///                     prior to kernel execution.
 /// \param DeviceMemorySize The size of the above device memory data in bytes.
+/// \param ReusableDeviceAlloc Pointer to a device memory allocation that should
+///                            be reused for the replay. If null, the replay will
+///                            allocate the necessary device buffer.
 /// \param TgtArgs An array of pointers of the pre-recorded target kernel
 ///                arguments.
 /// \param TgtOffsets An array of pointers of the pre-recorded target kernel
@@ -520,7 +523,7 @@ EXTERN int __tgt_activate_record_replay(int64_t DeviceId, uint64_t MemorySize,
 /// \param LoopTripCount The pre-recorded value of the loop tripcount, if any.
 /// \return OMP_TGT_SUCCESS on success, OMP_TGT_FAIL on failure.
 EXTERN int __tgt_target_kernel_replay(
-    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory,
+    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory, void *ReusableDeviceAlloc,
     int64_t DeviceMemorySize, const llvm::offloading::EntryTy *Globals,
     int32_t NumGlobals, void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs,
     int32_t NumTeams, int32_t ThreadLimit, uint32_t SharedMemorySize,
@@ -542,7 +545,7 @@ EXTERN int __tgt_target_kernel_replay(
 
   AsyncInfoTy AsyncInfo(*DeviceOrErr);
   int Rc = target_replay(
-      Loc, *DeviceOrErr, HostPtr, DeviceMemory, DeviceMemorySize, Globals,
+      Loc, *DeviceOrErr, HostPtr, DeviceMemory, DeviceMemorySize, ReusableDeviceAlloc, Globals,
       NumGlobals, TgtArgs, TgtOffsets, NumArgs, NumTeams, ThreadLimit,
       SharedMemorySize, LoopTripCount, AsyncInfo, ReplayOutcome);
 
diff --git a/offload/libomptarget/omptarget.cpp b/offload/libomptarget/omptarget.cpp
index f06654c639a8e..42a44178b3249 100644
--- a/offload/libomptarget/omptarget.cpp
+++ b/offload/libomptarget/omptarget.cpp
@@ -2390,7 +2390,7 @@ int target_activate_rr(DeviceTy &Device, uint64_t MemorySize, void *VAddr,
 /// device memory to launch the target kernel with the pre-recorded
 /// configuration.
 int target_replay(ident_t *Loc, DeviceTy &Device, void *HostPtr,
-                  void *DeviceMemory, int64_t DeviceMemorySize,
+                  void *DeviceMemory, int64_t DeviceMemorySize, void *ReusableDeviceAlloc,
                   const llvm::offloading::EntryTy *Globals, int32_t NumGlobals,
                   void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs,
                   int32_t NumTeams, int32_t ThreadLimit,
@@ -2448,13 +2448,20 @@ int target_replay(ident_t *Loc, DeviceTy &Device, void *HostPtr,
     }
   }
 
-  void *TgtPtr = Device.allocData(DeviceMemorySize, /*HstPtr=*/nullptr,
+  // Reuse a previous device allocation or allocate a new device buffer.
+  void *&TgtPtr = ReusableDeviceAlloc;
+  if (!TgtPtr)
+    TgtPtr = Device.allocData(DeviceMemorySize, /*HstPtr=*/nullptr,
                                   TARGET_ALLOC_DEFAULT);
   if (!TgtPtr) {
     REPORT() << "Failed to allocate device memory.";
     return OFFLOAD_FAIL;
   }
 
+  // Save the device allocation for future replays of the same kernel.
+  if (ReplayOutcome)
+    ReplayOutcome->ReplayDeviceAlloc = TgtPtr;
+
   int Ret =
       Device.submitData(TgtPtr, DeviceMemory, DeviceMemorySize, AsyncInfo);
   if (Ret != OFFLOAD_SUCCESS) {
diff --git a/offload/libomptarget/private.h b/offload/libomptarget/private.h
index 31b295bda613e..9e670ee902ab0 100644
--- a/offload/libomptarget/private.h
+++ b/offload/libomptarget/private.h
@@ -31,7 +31,7 @@ extern int target_activate_rr(DeviceTy &Device, uint64_t MemorySize,
                               bool EmitReport, const char *OutputDirPath);
 
 extern int target_replay(ident_t *Loc, DeviceTy &Device, void *HostPtr,
-                         void *DeviceMemory, int64_t DeviceMemorySize,
+                         void *DeviceMemory, int64_t DeviceMemorySize, void *ReusableDeviceAlloc,
                          const llvm::offloading::EntryTy *Globals,
                          int32_t NumGlobals, void **TgtArgs,
                          ptrdiff_t *TgtOffsets, int32_t NumArgs,
diff --git a/offload/plugins-nextgen/common/include/RecordReplay.h b/offload/plugins-nextgen/common/include/RecordReplay.h
index 0929a533effa4..76d722bc169b8 100644
--- a/offload/plugins-nextgen/common/include/RecordReplay.h
+++ b/offload/plugins-nextgen/common/include/RecordReplay.h
@@ -13,6 +13,7 @@
 
 #include <cstddef>
 #include <cstdint>
+#include <chrono>
 #include <filesystem>
 #include <mutex>
 #include <unordered_set>
@@ -116,6 +117,10 @@ struct RecordReplayTy {
     /// information about the the kernel's replay, such as the snapshot file.
     KernelReplayOutcomeTy *ReplayOutcome = nullptr;
 
+    /// The begin and end time points of the kernel execution.
+    using ClockTy = std::chrono::steady_clock;
+    mutable std::chrono::time_point<ClockTy> BeginTime, EndTime;
+
     /// The number of occurrences during the execution.
     mutable size_t Occurrences = 0;
 
@@ -129,6 +134,16 @@ struct RecordReplayTy {
               NumTeams == Other.NumTeams && NumThreads == Other.NumThreads &&
               SharedMemorySize == Other.SharedMemorySize);
     }
+
+    /// Record the begin and ending of the kernel execution.
+    void recordBeginTime() const { BeginTime = ClockTy::now(); }
+    void recordEndTime() const { EndTime = ClockTy::now(); }
+
+    /// Get the kernel execution time in nanoseconds.
+    uint64_t getRecordedTimeNano() const {
+      using NanoDurationTy = std::chrono::duration<uint64_t, std::nano>;
+      return std::chrono::duration_cast<NanoDurationTy>(EndTime - BeginTime).count();
+    }
   };
 
   struct InstanceHasher {
@@ -210,6 +225,13 @@ struct RecordReplayTy {
                    uint32_t NumThreads, uint32_t SharedMemorySize,
                    KernelReplayOutcomeTy *ReplayOutcome);
 
+  /// Unregister an instance once it has been replayed. Instances during recording
+  /// cannot be unregistered. Accessing the instance beyond this point is invalid.
+  Error unregisterInstance(const InstanceTy &Instance);
+
+  /// Populate the replay outcome struct to forward some replay information.
+  void populateReplayOutcome(const InstanceTy &Instance, KernelReplayOutcomeTy &Outcome);
+
   /// Record the prologue data.
   virtual Error
   recordPrologueImpl(const GenericKernelTy &Kernel, const InstanceTy &Instance,
diff --git a/offload/plugins-nextgen/common/src/RecordReplay.cpp b/offload/plugins-nextgen/common/src/RecordReplay.cpp
index 0b03e3405ce58..efcd12e5414b1 100644
--- a/offload/plugins-nextgen/common/src/RecordReplay.cpp
+++ b/offload/plugins-nextgen/common/src/RecordReplay.cpp
@@ -89,17 +89,19 @@ Error RecordReplayTy::deinit() {
 
 Error RecordReplayTy::emitInstanceReport() {
   std::lock_guard<std::mutex> LG(InstancesLock);
-  llvm::outs() << "=== record report begin ===\n";
-  llvm::outs() << "directory: "
+  llvm::outs() << "=== Kernel Record Report ===\n";
+  llvm::outs() << "Directory: "
                << std::filesystem::absolute(OutputDirectory).string() << "\n";
-  llvm::outs() << "kernels: " << Instances.size() << "\n";
+  llvm::outs() << "Total Instances: " << Instances.size() << "\n";
+  llvm::outs() << "JSON Filename, Kernel Name, Time (ns), Occurrences:\n";
 
   SmallString<128> Filename;
   for (const auto &Inst : Instances)
     llvm::outs()
         << getFilename(Inst, FileTy::Descriptor, /*IncludeDir=*/false).c_str()
-        << ": " << Inst.Kernel.getName() << "\n";
-  llvm::outs() << "=== record report end ===\n";
+        << ", " << Inst.Kernel.getName() << ", " << Inst.getRecordedTimeNano() << ", " << Inst.Occurrences << "\n";
+  llvm::outs() << "=== End Kernel Record Report ===\n";
+
   return Plugin::success();
 }
 
@@ -116,6 +118,16 @@ RecordReplayTy::registerInstance(const GenericKernelTy &Kernel,
   return {*It, Inserted};
 }
 
+Error RecordReplayTy::unregisterInstance(const InstanceTy &Instance) {
+  assert(isReplaying() && "Cannot unregister instance when recording.");
+
+  std::lock_guard<std::mutex> LG(InstancesLock);
+  size_t Erased = Instances.erase(Instance);
+  if (Erased != 1)
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT, "invalid instance");
+  return Plugin::success();
+}
+
 Expected<void *> RecordReplayTy::allocate(uint64_t Size) {
   assert(StartAddr && "Expected memory has been pre-allocated");
   constexpr int Alignment = 16;
@@ -147,34 +159,55 @@ Expected<RecordReplayTy::HandleTy> RecordReplayTy::recordPrologue(
       (KernelExtraArgs) ? KernelExtraArgs->ReplayOutcome : nullptr);
 
   HandleTy Handle{&Instance, First};
-  if (isReplaying() || !First)
+  if (!First)
     return Handle;
 
-  if (auto Err = recordDescImpl(Kernel, Instance, KernelArgs, LaunchParams))
-    return Err;
+  if (isRecording()) {
+    if (auto Err = recordDescImpl(Kernel, Instance, KernelArgs, LaunchParams))
+      return Err;
 
-  if (auto Err = recordPrologueImpl(Kernel, Instance, KernelArgs, LaunchParams))
-    return Err;
+    if (auto Err = recordPrologueImpl(Kernel, Instance, KernelArgs, LaunchParams))
+      return Err;
+  }
+
+  // Start the timer for the kernel execution.
+  Instance.recordBeginTime();
 
   return Handle;
 }
 
 Error RecordReplayTy::recordEpilogue(const GenericKernelTy &Kernel,
                                      HandleTy Handle) {
-  if (!shouldRecordEpilogue() || !Handle.Active)
+  if (!Handle.Active)
     return Plugin::success();
 
+  // Stop the timer for the kernel execution.
   const InstanceTy &Instance = *Handle.Instance;
-  if (auto Err = recordEpilogueImpl(Kernel, Instance))
-    return Err;
+  Instance.recordEndTime();
+
+  if (shouldRecordEpilogue())
+    if (auto Err = recordEpilogueImpl(Kernel, Instance))
+      return Err;
+
+  if (isReplaying() && Instance.ReplayOutcome)
+    populateReplayOutcome(Instance, *Instance.ReplayOutcome);
 
-  // If necessary, inform the replaying tool about where the epilogue snapshot
-  // file has been stored.
-  if (isReplaying() && Instance.ReplayOutcome) {
+  // After a replay, unregister the instance so it can be replayed again. Do
+  // not access the instance object beyond this point.
+  if (isReplaying())
+    return unregisterInstance(Instance);
+
+  return Plugin::success();
+}
+
+void RecordReplayTy::populateReplayOutcome(const InstanceTy &Instance, KernelReplayOutcomeTy &Outcome) {
+  // Only save the epilogue output filename if it was recorded.
+  if (shouldRecordEpilogue()) {
     SmallString<128> Filename = getFilename(Instance, FileTy::EpilogueSnapshot);
-    Instance.ReplayOutcome->OutputFilepath = Filename;
+    Outcome.OutputFilepath = Filename;
   }
-  return Plugin::success();
+  // Save the kernel replay time.
+  Outcome.KernelReplayTimeNano = Instance.getRecordedTimeNano();
 }
 
 Error NativeRecordReplayTy::recordPrologueImpl(
diff --git a/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp b/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp
index 7e8ceb7c24c08..119887d0e866f 100644
--- a/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp
+++ b/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp
@@ -58,6 +58,9 @@ static cl::opt<uint32_t> NumThreadsOpt("num-threads",
 static cl::opt<int32_t> DeviceIdOpt("device-id", cl::desc("Set the device id."),
                                     cl::init(-1), cl::cat(ReplayOptions));
 
+static cl::opt<uint32_t> RepetitionsOpt("repetitions", cl::desc("Set the number of replay repetitions."),
+                                    cl::init(1), cl::cat(ReplayOptions));
+
 template <typename... ArgsTy>
 Error createErr(const char *ErrFmt, ArgsTy &&...Args) {
   return llvm::createStringError(llvm::inconvertibleErrorCode(), ErrFmt,
@@ -132,7 +135,6 @@ Error verifyReplayOutput(StringRef RecordOutputFilename,
     return createErr("replay device memory failed to verify");
 
   // Sucessfully verified.
-  outs() << TOOL_PREFIX << "Replay device memory verified\n";
   return Error::success();
 }
 
@@ -315,26 +317,38 @@ Error replayKernel() {
   auto RecordInputBuffer = std::move(RecordInputBufferOrErr.get());
 
   KernelReplayOutcomeTy Outcome;
-  Rc = __tgt_target_kernel_replay(
-      /*Loc=*/nullptr, DeviceId, OffloadEntries[0].Address,
-      const_cast<char *>(RecordInputBuffer->getBufferStart()),
-      RecordInputBuffer->getBufferSize(),
-      NumGlobals ? &OffloadEntries[1] : nullptr, NumGlobals, TgtArgs.data(),
-      TgtArgOffsets.data(), NumArgs, NumTeams, NumThreads, SharedMemorySize,
-      LoopTripCount, &Outcome);
-  if (Rc != OMP_TGT_SUCCESS)
-    return createErr("failed to replay kernel");
 
-  // Verify the replay output if requested.
-  if (VerifyOpt) {
-    if (Outcome.OutputFilepath.empty())
-      return createErr("replay output file was not generated");
-
-    Filepath.replace_extension("record_output");
-    return verifyReplayOutput(Filepath.c_str(), Outcome.OutputFilepath.c_str());
+  // Perform the kernel replay and verification (if needed) for each repetition.
+  for (uint32_t R = 0; R < RepetitionsOpt; ++R) {
+    Rc = __tgt_target_kernel_replay(
+        /*Loc=*/nullptr, DeviceId, OffloadEntries[0].Address,
+        const_cast<char *>(RecordInputBuffer->getBufferStart()), R > 0 ? Outcome.ReplayDeviceAlloc : nullptr,
+        RecordInputBuffer->getBufferSize(),
+        NumGlobals ? &OffloadEntries[1] : nullptr, NumGlobals, TgtArgs.data(),
+        TgtArgOffsets.data(), NumArgs, NumTeams, NumThreads, SharedMemorySize,
+        LoopTripCount, &Outcome);
+    if (Rc != OMP_TGT_SUCCESS)
+      return createErr("failed to replay kernel");
+
+    // Verify the replay output if requested.
+    if (VerifyOpt) {
+      if (Outcome.OutputFilepath.empty())
+        return createErr("replay output file was not generated");
+
+      Filepath.replace_extension("record_output");
+      if (auto Err = verifyReplayOutput(Filepath.c_str(), Outcome.OutputFilepath.c_str()))
+        return Err;
+    }
+
+    outs() << TOOL_PREFIX << " Replay time (" << R << "): " << Outcome.KernelReplayTimeNano << " ns\n";
   }
 
-  outs() << TOOL_PREFIX << "Replay finished (verification skipped)\n";
+  // At this point, any verification done was successful.
+  if (VerifyOpt)
+    outs() << TOOL_PREFIX << " Replay done, device memory verified\n";
+  else
+    outs() << TOOL_PREFIX << " Replay done, verification skipped\n";
+
   return Error::success();
 }
 

>From e70bce751fd7d13fcb2017308d8fda86f9d41e10 Mon Sep 17 00:00:00 2001
From: Kevin Sala <salapenades1 at llnl.gov>
Date: Tue, 21 Apr 2026 18:43:37 -0700
Subject: [PATCH 2/3] Add fixes

---
 offload/include/Shared/APITypes.h             |  2 +-
 offload/include/omptarget.h                   | 11 ++++----
 offload/libomptarget/interface.cpp            | 26 ++++++++++---------
 offload/libomptarget/omptarget.cpp            |  7 ++---
 offload/libomptarget/private.h                | 17 ++++++------
 .../common/include/RecordReplay.h             | 17 +++++++-----
 .../common/src/RecordReplay.cpp               | 11 +++++---
 .../kernelreplay/llvm-omp-kernel-replay.cpp   | 15 +++++++----
 8 files changed, 60 insertions(+), 46 deletions(-)

diff --git a/offload/include/Shared/APITypes.h b/offload/include/Shared/APITypes.h
index 488ae68106d8f..5e61bc7c842e7 100644
--- a/offload/include/Shared/APITypes.h
+++ b/offload/include/Shared/APITypes.h
@@ -136,7 +136,7 @@ struct KernelReplayOutcomeTy {
   llvm::SmallString<128> OutputFilepath;
   /// The execution time of the kernel replay in nanoseconds. This time includes
   /// the the kernel launch and synchronization time. Replay I/O is excluded.
-  uint64_t KernelReplayTimeNano = 0;
+  uint64_t KernelReplayTimeNs = 0;
   /// The pointer to the device memory allocation used to replay. This can be
   /// reused for future replays of the same kernel.
   void *ReplayDeviceAlloc = nullptr;
diff --git a/offload/include/omptarget.h b/offload/include/omptarget.h
index 7cb306dcf6b2e..e5d9852ad48a6 100644
--- a/offload/include/omptarget.h
+++ b/offload/include/omptarget.h
@@ -427,11 +427,12 @@ void __tgt_target_nowait_query(void **AsyncHandle);
 /// Executes a target kernel by replaying recorded kernel arguments and
 /// device memory.
 int __tgt_target_kernel_replay(
-    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory, void *ReusableDeviceAlloc,
-    int64_t DeviceMemorySize, const llvm::offloading::EntryTy *Globals,
-    int32_t NumGlobals, void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs,
-    int32_t NumTeams, int32_t ThreadLimit, uint32_t SharedMemorySize,
-    uint64_t LoopTripCount, KernelReplayOutcomeTy *ReplayOutcome);
+    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory,
+    void *ReuseDeviceAlloc, int64_t DeviceMemorySize,
+    const llvm::offloading::EntryTy *Globals, int32_t NumGlobals,
+    void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs, int32_t NumTeams,
+    int32_t ThreadLimit, uint32_t SharedMemorySize, uint64_t LoopTripCount,
+    KernelReplayOutcomeTy *ReplayOutcome);
 
 void __tgt_set_info_flag(uint32_t);
 
diff --git a/offload/libomptarget/interface.cpp b/offload/libomptarget/interface.cpp
index 576d7c52ba62a..1049cd72d0958 100644
--- a/offload/libomptarget/interface.cpp
+++ b/offload/libomptarget/interface.cpp
@@ -509,9 +509,9 @@ EXTERN int __tgt_activate_record_replay(int64_t DeviceId, uint64_t MemorySize,
 /// \param DeviceMemory A pointer to an array storing device memory data to move
 ///                     prior to kernel execution.
 /// \param DeviceMemorySize The size of the above device memory data in bytes.
-/// \param ReusableDeviceAlloc Pointer to a device memory allocation that should
-///                            be reused for the replay. If null, the replay will
-///                            allocate the necessary device buffer.
+/// \param ReuseDeviceAlloc Pointer to a device memory allocation that should
+///                            be reused for the replay. If null, the replay
+///                            will allocate the necessary device buffer.
 /// \param TgtArgs An array of pointers of the pre-recorded target kernel
 ///                arguments.
 /// \param TgtOffsets An array of pointers of the pre-recorded target kernel
@@ -523,11 +523,12 @@ EXTERN int __tgt_activate_record_replay(int64_t DeviceId, uint64_t MemorySize,
 /// \param LoopTripCount The pre-recorded value of the loop tripcount, if any.
 /// \return OMP_TGT_SUCCESS on success, OMP_TGT_FAIL on failure.
 EXTERN int __tgt_target_kernel_replay(
-    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory, void *ReusableDeviceAlloc,
-    int64_t DeviceMemorySize, const llvm::offloading::EntryTy *Globals,
-    int32_t NumGlobals, void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs,
-    int32_t NumTeams, int32_t ThreadLimit, uint32_t SharedMemorySize,
-    uint64_t LoopTripCount, KernelReplayOutcomeTy *ReplayOutcome) {
+    ident_t *Loc, int64_t DeviceId, void *HostPtr, void *DeviceMemory,
+    void *ReuseDeviceAlloc, int64_t DeviceMemorySize,
+    const llvm::offloading::EntryTy *Globals, int32_t NumGlobals,
+    void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs, int32_t NumTeams,
+    int32_t ThreadLimit, uint32_t SharedMemorySize, uint64_t LoopTripCount,
+    KernelReplayOutcomeTy *ReplayOutcome) {
   assert(PM && "Runtime not initialized");
   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
   if (checkDevice(DeviceId, Loc)) {
@@ -544,10 +545,11 @@ EXTERN int __tgt_target_kernel_replay(
                     /*CodePtr=*/OMPT_GET_RETURN_ADDRESS);)
 
   AsyncInfoTy AsyncInfo(*DeviceOrErr);
-  int Rc = target_replay(
-      Loc, *DeviceOrErr, HostPtr, DeviceMemory, DeviceMemorySize, ReusableDeviceAlloc, Globals,
-      NumGlobals, TgtArgs, TgtOffsets, NumArgs, NumTeams, ThreadLimit,
-      SharedMemorySize, LoopTripCount, AsyncInfo, ReplayOutcome);
+  int Rc =
+      target_replay(Loc, *DeviceOrErr, HostPtr, DeviceMemory, DeviceMemorySize,
+                    ReuseDeviceAlloc, Globals, NumGlobals, TgtArgs, TgtOffsets,
+                    NumArgs, NumTeams, ThreadLimit, SharedMemorySize,
+                    LoopTripCount, AsyncInfo, ReplayOutcome);
 
   if (Rc == OFFLOAD_SUCCESS)
     Rc = AsyncInfo.synchronize();
diff --git a/offload/libomptarget/omptarget.cpp b/offload/libomptarget/omptarget.cpp
index 42a44178b3249..82a0ed73317d5 100644
--- a/offload/libomptarget/omptarget.cpp
+++ b/offload/libomptarget/omptarget.cpp
@@ -2390,7 +2390,8 @@ int target_activate_rr(DeviceTy &Device, uint64_t MemorySize, void *VAddr,
 /// device memory to launch the target kernel with the pre-recorded
 /// configuration.
 int target_replay(ident_t *Loc, DeviceTy &Device, void *HostPtr,
-                  void *DeviceMemory, int64_t DeviceMemorySize, void *ReusableDeviceAlloc,
+                  void *DeviceMemory, int64_t DeviceMemorySize,
+                  void *ReuseDeviceAlloc,
                   const llvm::offloading::EntryTy *Globals, int32_t NumGlobals,
                   void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs,
                   int32_t NumTeams, int32_t ThreadLimit,
@@ -2449,10 +2450,10 @@ int target_replay(ident_t *Loc, DeviceTy &Device, void *HostPtr,
   }
 
   // Reuse a previous device allocation or allocate a new device buffer.
-  void *&TgtPtr = ReusableDeviceAlloc;
+  void *&TgtPtr = ReuseDeviceAlloc;
   if (!TgtPtr)
     TgtPtr = Device.allocData(DeviceMemorySize, /*HstPtr=*/nullptr,
-                                  TARGET_ALLOC_DEFAULT);
+                              TARGET_ALLOC_DEFAULT);
   if (!TgtPtr) {
     REPORT() << "Failed to allocate device memory.";
     return OFFLOAD_FAIL;
diff --git a/offload/libomptarget/private.h b/offload/libomptarget/private.h
index 9e670ee902ab0..e52028cc060d9 100644
--- a/offload/libomptarget/private.h
+++ b/offload/libomptarget/private.h
@@ -30,15 +30,14 @@ extern int target_activate_rr(DeviceTy &Device, uint64_t MemorySize,
                               void *ReqAddr, bool IsRecord, bool SaveOutput,
                               bool EmitReport, const char *OutputDirPath);
 
-extern int target_replay(ident_t *Loc, DeviceTy &Device, void *HostPtr,
-                         void *DeviceMemory, int64_t DeviceMemorySize, void *ReusableDeviceAlloc,
-                         const llvm::offloading::EntryTy *Globals,
-                         int32_t NumGlobals, void **TgtArgs,
-                         ptrdiff_t *TgtOffsets, int32_t NumArgs,
-                         int32_t NumTeams, int32_t ThreadLimit,
-                         uint32_t SharedMemorySize, uint64_t LoopTripCount,
-                         AsyncInfoTy &AsyncInfo,
-                         KernelReplayOutcomeTy *ReplayOutcome);
+extern int
+target_replay(ident_t *Loc, DeviceTy &Device, void *HostPtr, void *DeviceMemory,
+              int64_t DeviceMemorySize, void *ReuseDeviceAlloc,
+              const llvm::offloading::EntryTy *Globals, int32_t NumGlobals,
+              void **TgtArgs, ptrdiff_t *TgtOffsets, int32_t NumArgs,
+              int32_t NumTeams, int32_t ThreadLimit, uint32_t SharedMemorySize,
+              uint64_t LoopTripCount, AsyncInfoTy &AsyncInfo,
+              KernelReplayOutcomeTy *ReplayOutcome);
 
 extern void handleTargetOutcome(bool Success, ident_t *Loc);
 
diff --git a/offload/plugins-nextgen/common/include/RecordReplay.h b/offload/plugins-nextgen/common/include/RecordReplay.h
index 76d722bc169b8..65a861cc8a0cc 100644
--- a/offload/plugins-nextgen/common/include/RecordReplay.h
+++ b/offload/plugins-nextgen/common/include/RecordReplay.h
@@ -11,9 +11,9 @@
 #ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_RECORDREPLAY_H
 #define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_RECORDREPLAY_H
 
+#include <chrono>
 #include <cstddef>
 #include <cstdint>
-#include <chrono>
 #include <filesystem>
 #include <mutex>
 #include <unordered_set>
@@ -140,9 +140,10 @@ struct RecordReplayTy {
     void recordEndTime() const { EndTime = ClockTy::now(); }
 
     /// Get the kernel execution time in nanoseconds.
-    uint64_t getRecordedTimeNano() const {
-      using NanoDurationTy = std::chrono::duration<uint64_t, std::nano>;
-      return std::chrono::duration_cast<NanoDurationTy>(EndTime - BeginTime).count();
+    uint64_t getRecordedTimeNs() const {
+      using DurationNsTy = std::chrono::duration<uint64_t, std::nano>;
+      return std::chrono::duration_cast<DurationNsTy>(EndTime - BeginTime)
+          .count();
     }
   };
 
@@ -225,12 +226,14 @@ struct RecordReplayTy {
                    uint32_t NumThreads, uint32_t SharedMemorySize,
                    KernelReplayOutcomeTy *ReplayOutcome);
 
-  /// Unregister an instance once it has been replayed. Instances during recording
-  /// cannot be unregistered. Accessing the instance beyond this point is invalid.
+  /// Unregister an instance once it has been replayed. Instances during
+  /// recording cannot be unregistered. Accessing the instance beyond this point
+  /// is invalid.
   Error unregisterInstance(const InstanceTy &Instance);
 
   /// Populate the replay outcome struct to forward some replay information.
-  void populateReplayOutcome(const InstanceTy &Instance, KernelReplayOutcomeTy &Outcome);
+  void populateReplayOutcome(const InstanceTy &Instance,
+                             KernelReplayOutcomeTy &Outcome);
 
   /// Record the prologue data.
   virtual Error
diff --git a/offload/plugins-nextgen/common/src/RecordReplay.cpp b/offload/plugins-nextgen/common/src/RecordReplay.cpp
index efcd12e5414b1..8c4b012fdc9e2 100644
--- a/offload/plugins-nextgen/common/src/RecordReplay.cpp
+++ b/offload/plugins-nextgen/common/src/RecordReplay.cpp
@@ -99,7 +99,8 @@ Error RecordReplayTy::emitInstanceReport() {
   for (const auto &Inst : Instances)
     llvm::outs()
         << getFilename(Inst, FileTy::Descriptor, /*IncludeDir=*/false).c_str()
-        << ", " << Inst.Kernel.getName() << ", " << Inst.getRecordedTimeNano() << ", " << Inst.Occurrences << "\n";
+        << ", " << Inst.Kernel.getName() << ", " << Inst.getRecordedTimeNs()
+        << ", " << Inst.Occurrences << "\n";
   llvm::outs() << "=== End Kernel Record Report ===\n";
 
   return Plugin::success();
@@ -166,7 +167,8 @@ Expected<RecordReplayTy::HandleTy> RecordReplayTy::recordPrologue(
     if (auto Err = recordDescImpl(Kernel, Instance, KernelArgs, LaunchParams))
       return Err;
 
-    if (auto Err = recordPrologueImpl(Kernel, Instance, KernelArgs, LaunchParams))
+    if (auto Err =
+            recordPrologueImpl(Kernel, Instance, KernelArgs, LaunchParams))
       return Err;
   }
 
@@ -200,14 +202,15 @@ Error RecordReplayTy::recordEpilogue(const GenericKernelTy &Kernel,
   return Plugin::success();
 }
 
-void RecordReplayTy::populateReplayOutcome(const InstanceTy &Instance, KernelReplayOutcomeTy &Outcome) {
+void RecordReplayTy::populateReplayOutcome(const InstanceTy &Instance,
+                                           KernelReplayOutcomeTy &Outcome) {
   // Only save the epilogue output filename if it was recorded.
   if (shouldRecordEpilogue()) {
     SmallString<128> Filename = getFilename(Instance, FileTy::EpilogueSnapshot);
     Outcome.OutputFilepath = Filename;
   }
   // Save the kernel replay time.
-  Outcome.KernelReplayTimeNano = Instance.getRecordedTimeNano();
+  Outcome.KernelReplayTimeNs = Instance.getRecordedTimeNs();
 }
 
 Error NativeRecordReplayTy::recordPrologueImpl(
diff --git a/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp b/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp
index 119887d0e866f..7526a81b450d8 100644
--- a/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp
+++ b/offload/tools/kernelreplay/llvm-omp-kernel-replay.cpp
@@ -58,8 +58,10 @@ static cl::opt<uint32_t> NumThreadsOpt("num-threads",
 static cl::opt<int32_t> DeviceIdOpt("device-id", cl::desc("Set the device id."),
                                     cl::init(-1), cl::cat(ReplayOptions));
 
-static cl::opt<uint32_t> RepetitionsOpt("repetitions", cl::desc("Set the number of replay repetitions."),
-                                    cl::init(1), cl::cat(ReplayOptions));
+static cl::opt<uint32_t>
+    RepetitionsOpt("repetitions",
+                   cl::desc("Set the number of replay repetitions."),
+                   cl::init(1), cl::cat(ReplayOptions));
 
 template <typename... ArgsTy>
 Error createErr(const char *ErrFmt, ArgsTy &&...Args) {
@@ -322,7 +324,8 @@ Error replayKernel() {
   for (uint32_t R = 0; R < RepetitionsOpt; ++R) {
     Rc = __tgt_target_kernel_replay(
         /*Loc=*/nullptr, DeviceId, OffloadEntries[0].Address,
-        const_cast<char *>(RecordInputBuffer->getBufferStart()), R > 0 ? Outcome.ReplayDeviceAlloc : nullptr,
+        const_cast<char *>(RecordInputBuffer->getBufferStart()),
+        R > 0 ? Outcome.ReplayDeviceAlloc : nullptr,
         RecordInputBuffer->getBufferSize(),
         NumGlobals ? &OffloadEntries[1] : nullptr, NumGlobals, TgtArgs.data(),
         TgtArgOffsets.data(), NumArgs, NumTeams, NumThreads, SharedMemorySize,
@@ -336,11 +339,13 @@ Error replayKernel() {
         return createErr("replay output file was not generated");
 
       Filepath.replace_extension("record_output");
-      if (auto Err = verifyReplayOutput(Filepath.c_str(), Outcome.OutputFilepath.c_str()))
+      if (auto Err = verifyReplayOutput(Filepath.c_str(),
+                                        Outcome.OutputFilepath.c_str()))
         return Err;
     }
 
-    outs() << TOOL_PREFIX << " Replay time (" << R << "): " << Outcome.KernelReplayTimeNano << " ns\n";
+    outs() << TOOL_PREFIX << " Replay time (" << R
+           << "): " << Outcome.KernelReplayTimeNs << " ns\n";
   }
 
   // At this point, any verification done was successful.

>From 70cc11dfa0814807abf9b790ab4db40f94859cef Mon Sep 17 00:00:00 2001
From: Kevin Sala <salapenades1 at llnl.gov>
Date: Tue, 21 Apr 2026 18:54:02 -0700
Subject: [PATCH 3/3] Fix format

---
 offload/libomptarget/interface.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/offload/libomptarget/interface.cpp b/offload/libomptarget/interface.cpp
index 1049cd72d0958..f65ca3cadee8c 100644
--- a/offload/libomptarget/interface.cpp
+++ b/offload/libomptarget/interface.cpp
@@ -509,9 +509,9 @@ EXTERN int __tgt_activate_record_replay(int64_t DeviceId, uint64_t MemorySize,
 /// \param DeviceMemory A pointer to an array storing device memory data to move
 ///                     prior to kernel execution.
 /// \param DeviceMemorySize The size of the above device memory data in bytes.
-/// \param ReuseDeviceAlloc Pointer to a device memory allocation that should
-///                            be reused for the replay. If null, the replay
-///                            will allocate the necessary device buffer.
+/// \param ReuseDeviceAlloc Pointer to a device memory allocation that should be
+///                         reused for the replay. If null, the replay will
+///                         allocate the necessary device buffer.
 /// \param TgtArgs An array of pointers of the pre-recorded target kernel
 ///                arguments.
 /// \param TgtOffsets An array of pointers of the pre-recorded target kernel



More information about the llvm-commits mailing list