[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