[llvm] [Offload] Implement `olShutDown` (PR #144055)
Ross Brunton via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 16 06:13:48 PDT 2025
https://github.com/RossBrunton updated https://github.com/llvm/llvm-project/pull/144055
>From 05e05fee50b23d5e8b12f3c5fc2eccb6ed190ab9 Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Thu, 12 Jun 2025 12:11:09 +0100
Subject: [PATCH 1/7] [Offload] Add an `unloadBinary` interface to
PluginInterface
This allows removal of a specific Image from a Device, rather than
requiring all image data to outlive the device they were created for.
This is required for `ol_program_handle_t`s, which now specify the
lifetime of the buffer used to create the program.
---
offload/liboffload/API/Program.td | 4 +-
offload/liboffload/src/OffloadImpl.cpp | 3 +
offload/plugins-nextgen/amdgpu/src/rtl.cpp | 23 +++---
.../common/include/PluginInterface.h | 4 +
.../common/src/PluginInterface.cpp | 75 ++++++++++---------
offload/plugins-nextgen/cuda/src/rtl.cpp | 29 +++----
6 files changed, 76 insertions(+), 62 deletions(-)
diff --git a/offload/liboffload/API/Program.td b/offload/liboffload/API/Program.td
index 8c88fe6e21e6a..8ad85bec17b03 100644
--- a/offload/liboffload/API/Program.td
+++ b/offload/liboffload/API/Program.td
@@ -13,7 +13,9 @@
def : Function {
let name = "olCreateProgram";
let desc = "Create a program for the device from the binary image pointed to by `ProgData`.";
- let details = [];
+ let details = [
+ "`ProgData` must remain valid for the entire lifetime of the output `Program` handle",
+ ];
let params = [
Param<"ol_device_handle_t", "Device", "handle of the device", PARAM_IN>,
Param<"const void*", "ProgData", "pointer to the program binary data", PARAM_IN>,
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index d2b331905ab77..c1df0197c1c0b 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -465,6 +465,9 @@ Error olCreateProgram_impl(ol_device_handle_t Device, const void *ProgData,
}
Error olDestroyProgram_impl(ol_program_handle_t Program) {
+ if (auto Err = Program->Image->getDevice().unloadBinary(Program->Image))
+ return Err;
+
return olDestroy(Program);
}
diff --git a/offload/plugins-nextgen/amdgpu/src/rtl.cpp b/offload/plugins-nextgen/amdgpu/src/rtl.cpp
index e4c32713e2c15..4ec3d5113a1fb 100644
--- a/offload/plugins-nextgen/amdgpu/src/rtl.cpp
+++ b/offload/plugins-nextgen/amdgpu/src/rtl.cpp
@@ -2023,6 +2023,16 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
return Plugin::success();
}
+ Error unloadBinaryImpl(DeviceImageTy *Image) override {
+ AMDGPUDeviceImageTy &AMDImage = static_cast<AMDGPUDeviceImageTy &>(*Image);
+
+ // Unload the executable of the image.
+ if (auto Err = AMDImage.unloadExecutable())
+ return Err;
+
+ return Plugin::success();
+ }
+
/// Deinitialize the device and release its resources.
Error deinitImpl() override {
// Deinitialize the stream and event pools.
@@ -2035,19 +2045,6 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
if (auto Err = AMDGPUSignalManager.deinit())
return Err;
- // Close modules if necessary.
- if (!LoadedImages.empty()) {
- // Each image has its own module.
- for (DeviceImageTy *Image : LoadedImages) {
- AMDGPUDeviceImageTy &AMDImage =
- static_cast<AMDGPUDeviceImageTy &>(*Image);
-
- // Unload the executable of the image.
- if (auto Err = AMDImage.unloadExecutable())
- return Err;
- }
- }
-
// Invalidate agent reference.
Agent = {0};
diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index d2437908a0a6f..7af61074bb322 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -712,6 +712,10 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
virtual Expected<DeviceImageTy *>
loadBinaryImpl(const __tgt_device_image *TgtImage, int32_t ImageId) = 0;
+ /// Unload a previously loaded Image from the device
+ Error unloadBinary(DeviceImageTy *Image);
+ virtual Error unloadBinaryImpl(DeviceImageTy *Image) = 0;
+
/// Setup the device environment if needed. Notice this setup may not be run
/// on some plugins. By default, it will be executed, but plugins can change
/// this behavior by overriding the shouldSetupDeviceEnvironment function.
diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index f9a6b3c1f4324..bb503c1ff7a54 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -821,26 +821,52 @@ Error GenericDeviceTy::init(GenericPluginTy &Plugin) {
return Plugin::success();
}
-Error GenericDeviceTy::deinit(GenericPluginTy &Plugin) {
- for (DeviceImageTy *Image : LoadedImages)
- if (auto Err = callGlobalDestructors(Plugin, *Image))
- return Err;
+Error GenericDeviceTy::unloadBinary(DeviceImageTy *Image) {
+ if (auto Err = callGlobalDestructors(Plugin, *Image))
+ return Err;
if (OMPX_DebugKind.get() & uint32_t(DeviceDebugKind::AllocationTracker)) {
GenericGlobalHandlerTy &GHandler = Plugin.getGlobalHandler();
- for (auto *Image : LoadedImages) {
- DeviceMemoryPoolTrackingTy ImageDeviceMemoryPoolTracking = {0, 0, ~0U, 0};
- GlobalTy TrackerGlobal("__omp_rtl_device_memory_pool_tracker",
- sizeof(DeviceMemoryPoolTrackingTy),
- &ImageDeviceMemoryPoolTracking);
- if (auto Err =
- GHandler.readGlobalFromDevice(*this, *Image, TrackerGlobal)) {
- consumeError(std::move(Err));
- continue;
- }
- DeviceMemoryPoolTracking.combine(ImageDeviceMemoryPoolTracking);
+ DeviceMemoryPoolTrackingTy ImageDeviceMemoryPoolTracking = {0, 0, ~0U, 0};
+ GlobalTy TrackerGlobal("__omp_rtl_device_memory_pool_tracker",
+ sizeof(DeviceMemoryPoolTrackingTy),
+ &ImageDeviceMemoryPoolTracking);
+ if (auto Err =
+ GHandler.readGlobalFromDevice(*this, *Image, TrackerGlobal)) {
+ consumeError(std::move(Err));
}
+ DeviceMemoryPoolTracking.combine(ImageDeviceMemoryPoolTracking);
+ }
+
+ GenericGlobalHandlerTy &Handler = Plugin.getGlobalHandler();
+ auto ProfOrErr = Handler.readProfilingGlobals(*this, *Image);
+ if (!ProfOrErr)
+ return ProfOrErr.takeError();
+
+ if (!ProfOrErr->empty()) {
+ // Dump out profdata
+ if ((OMPX_DebugKind.get() & uint32_t(DeviceDebugKind::PGODump)) ==
+ uint32_t(DeviceDebugKind::PGODump))
+ ProfOrErr->dump();
+
+ // Write data to profiling file
+ if (auto Err = ProfOrErr->write())
+ return Err;
+ }
+
+ LoadedImages.erase(
+ std::find(LoadedImages.begin(), LoadedImages.end(), Image));
+ return unloadBinaryImpl(Image);
+}
+
+Error GenericDeviceTy::deinit(GenericPluginTy &Plugin) {
+ while (!LoadedImages.empty()) {
+ if (auto Err = unloadBinary(LoadedImages.back()))
+ return Err;
+ }
+
+ if (OMPX_DebugKind.get() & uint32_t(DeviceDebugKind::AllocationTracker)) {
// TODO: Write this by default into a file.
printf("\n\n|-----------------------\n"
"| Device memory tracker:\n"
@@ -856,25 +882,6 @@ Error GenericDeviceTy::deinit(GenericPluginTy &Plugin) {
DeviceMemoryPoolTracking.AllocationMax);
}
- for (auto *Image : LoadedImages) {
- GenericGlobalHandlerTy &Handler = Plugin.getGlobalHandler();
- auto ProfOrErr = Handler.readProfilingGlobals(*this, *Image);
- if (!ProfOrErr)
- return ProfOrErr.takeError();
-
- if (ProfOrErr->empty())
- continue;
-
- // Dump out profdata
- if ((OMPX_DebugKind.get() & uint32_t(DeviceDebugKind::PGODump)) ==
- uint32_t(DeviceDebugKind::PGODump))
- ProfOrErr->dump();
-
- // Write data to profiling file
- if (auto Err = ProfOrErr->write())
- return Err;
- }
-
// Delete the memory manager before deinitializing the device. Otherwise,
// we may delete device allocations after the device is deinitialized.
if (MemoryManager)
diff --git a/offload/plugins-nextgen/cuda/src/rtl.cpp b/offload/plugins-nextgen/cuda/src/rtl.cpp
index 44ccfc47a21c9..db3c990afc2d6 100644
--- a/offload/plugins-nextgen/cuda/src/rtl.cpp
+++ b/offload/plugins-nextgen/cuda/src/rtl.cpp
@@ -358,6 +358,21 @@ struct CUDADeviceTy : public GenericDeviceTy {
return Plugin::success();
}
+ Error unloadBinaryImpl(DeviceImageTy *Image) override {
+ assert(Context && "Invalid CUDA context");
+
+ // Each image has its own module.
+ for (DeviceImageTy *Image : LoadedImages) {
+ CUDADeviceImageTy &CUDAImage = static_cast<CUDADeviceImageTy &>(*Image);
+
+ // Unload the module of the image.
+ if (auto Err = CUDAImage.unloadModule())
+ return Err;
+ }
+
+ return Plugin::success();
+ }
+
/// Deinitialize the device and release its resources.
Error deinitImpl() override {
if (Context) {
@@ -372,20 +387,6 @@ struct CUDADeviceTy : public GenericDeviceTy {
if (auto Err = CUDAEventManager.deinit())
return Err;
- // Close modules if necessary.
- if (!LoadedImages.empty()) {
- assert(Context && "Invalid CUDA context");
-
- // Each image has its own module.
- for (DeviceImageTy *Image : LoadedImages) {
- CUDADeviceImageTy &CUDAImage = static_cast<CUDADeviceImageTy &>(*Image);
-
- // Unload the module of the image.
- if (auto Err = CUDAImage.unloadModule())
- return Err;
- }
- }
-
if (Context) {
CUresult Res = cuDevicePrimaryCtxRelease(Device);
if (auto Err =
>From 3544ad8daa89f696f323f136d092edcd9a5eab33 Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Thu, 12 Jun 2025 12:25:23 +0100
Subject: [PATCH 2/7] Fix cuda
---
offload/plugins-nextgen/cuda/src/rtl.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/offload/plugins-nextgen/cuda/src/rtl.cpp b/offload/plugins-nextgen/cuda/src/rtl.cpp
index db3c990afc2d6..eb313d0a4f093 100644
--- a/offload/plugins-nextgen/cuda/src/rtl.cpp
+++ b/offload/plugins-nextgen/cuda/src/rtl.cpp
@@ -362,13 +362,11 @@ struct CUDADeviceTy : public GenericDeviceTy {
assert(Context && "Invalid CUDA context");
// Each image has its own module.
- for (DeviceImageTy *Image : LoadedImages) {
- CUDADeviceImageTy &CUDAImage = static_cast<CUDADeviceImageTy &>(*Image);
+ CUDADeviceImageTy &CUDAImage = static_cast<CUDADeviceImageTy &>(*Image);
- // Unload the module of the image.
- if (auto Err = CUDAImage.unloadModule())
- return Err;
- }
+ // Unload the module of the image.
+ if (auto Err = CUDAImage.unloadModule())
+ return Err;
return Plugin::success();
}
>From 67d88096ffb168740991734c4ddf7a122793377e Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Thu, 12 Jun 2025 15:51:47 +0100
Subject: [PATCH 3/7] Review feedback
---
offload/liboffload/API/Program.td | 2 +-
offload/plugins-nextgen/amdgpu/src/rtl.cpp | 5 +----
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/offload/liboffload/API/Program.td b/offload/liboffload/API/Program.td
index 8ad85bec17b03..0476fa1f7c27a 100644
--- a/offload/liboffload/API/Program.td
+++ b/offload/liboffload/API/Program.td
@@ -14,7 +14,7 @@ def : Function {
let name = "olCreateProgram";
let desc = "Create a program for the device from the binary image pointed to by `ProgData`.";
let details = [
- "`ProgData` must remain valid for the entire lifetime of the output `Program` handle",
+ "The provided `ProgData` will be copied and need not outlive the returned handle",
];
let params = [
Param<"ol_device_handle_t", "Device", "handle of the device", PARAM_IN>,
diff --git a/offload/plugins-nextgen/amdgpu/src/rtl.cpp b/offload/plugins-nextgen/amdgpu/src/rtl.cpp
index 4ec3d5113a1fb..5f80a97d02cb6 100644
--- a/offload/plugins-nextgen/amdgpu/src/rtl.cpp
+++ b/offload/plugins-nextgen/amdgpu/src/rtl.cpp
@@ -2027,10 +2027,7 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
AMDGPUDeviceImageTy &AMDImage = static_cast<AMDGPUDeviceImageTy &>(*Image);
// Unload the executable of the image.
- if (auto Err = AMDImage.unloadExecutable())
- return Err;
-
- return Plugin::success();
+ return AMDImage.unloadExecutable();
}
/// Deinitialize the device and release its resources.
>From 654fd57ac91267473ac9226176acd514951ff2fd Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Thu, 12 Jun 2025 10:47:19 +0100
Subject: [PATCH 4/7] [Offload] Implement `olShutDown` and remove global
reference counting
`olShutDown` was not properly calling deinit on the platforms, resulting
in random segfaults on AMD devices.
The spec has been updated to remove references to `olInit`/`olShutDown`
doing reference counting. Implementations may wrap liboffload with their
own reference counting if required. This matches the behaviour of
handle types which also don't use reference counting.
---
offload/liboffload/API/Common.td | 7 +++----
offload/liboffload/src/OffloadImpl.cpp | 18 +++++++++++++++---
2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/offload/liboffload/API/Common.td b/offload/liboffload/API/Common.td
index 7674da0438c29..e611dd9105251 100644
--- a/offload/liboffload/API/Common.td
+++ b/offload/liboffload/API/Common.td
@@ -152,8 +152,7 @@ def : Function {
let name = "olInit";
let desc = "Perform initialization of the Offload library and plugins";
let details = [
- "This must be the first API call made by a user of the Offload library",
- "Each call will increment an internal reference count that is decremented by `olShutDown`"
+ "This must be the first API call made by a user of the Offload library"
];
let params = [];
let returns = [];
@@ -163,8 +162,8 @@ def : Function {
let name = "olShutDown";
let desc = "Release the resources in use by Offload";
let details = [
- "This decrements an internal reference count. When this reaches 0, all resources will be released",
- "Subsequent API calls made after this are not valid"
+ "All resources owned by the Offload library and plugins will be released",
+ "Subsequent API calls made after calling `olShutDown` are undefined behavior"
];
let params = [];
let returns = [];
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index c1df0197c1c0b..ae2975e3ec3c5 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -168,15 +168,27 @@ void initPlugins() {
!std::getenv("OFFLOAD_DISABLE_VALIDATION");
}
-// TODO: We can properly reference count here and manage the resources in a more
-// clever way
Error olInit_impl() {
static std::once_flag InitFlag;
std::call_once(InitFlag, initPlugins);
return Error::success();
}
-Error olShutDown_impl() { return Error::success(); }
+
+Error olShutDown_impl() {
+ llvm::Error Result = Error::success();
+
+ for (auto &P : Platforms()) {
+ // Host plugin is nullptr and has no deinit
+ if (!P.Plugin)
+ continue;
+
+ if (auto Res = P.Plugin->deinit())
+ Result = llvm::joinErrors(std::move(Result), std::move(Res));
+ }
+
+ return Result;
+}
Error olGetPlatformInfoImplDetail(ol_platform_handle_t Platform,
ol_platform_info_t PropName, size_t PropSize,
>From a1092e2e6904d4355712ee951d6479c3ea4c6cc4 Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Mon, 16 Jun 2025 10:04:44 +0100
Subject: [PATCH 5/7] Bring back reference counting
---
offload/liboffload/API/Common.td | 7 +++--
offload/liboffload/src/OffloadImpl.cpp | 30 +++++++++++++------
offload/unittests/OffloadAPI/CMakeLists.txt | 4 +++
.../OffloadAPI/common/Environment.cpp | 2 ++
offload/unittests/OffloadAPI/init/olInit.cpp | 25 ++++++++++++++++
5 files changed, 56 insertions(+), 12 deletions(-)
create mode 100644 offload/unittests/OffloadAPI/init/olInit.cpp
diff --git a/offload/liboffload/API/Common.td b/offload/liboffload/API/Common.td
index e611dd9105251..cb20c4244c1b1 100644
--- a/offload/liboffload/API/Common.td
+++ b/offload/liboffload/API/Common.td
@@ -152,7 +152,8 @@ def : Function {
let name = "olInit";
let desc = "Perform initialization of the Offload library and plugins";
let details = [
- "This must be the first API call made by a user of the Offload library"
+ "This must be the first API call made by a user of the Offload library",
+ "Each call will increment an internal reference count that is decremented by `olShutDown`"
];
let params = [];
let returns = [];
@@ -162,8 +163,8 @@ def : Function {
let name = "olShutDown";
let desc = "Release the resources in use by Offload";
let details = [
- "All resources owned by the Offload library and plugins will be released",
- "Subsequent API calls made after calling `olShutDown` are undefined behavior"
+ "This decrements an internal reference count. When this reaches 0, all resources will be released",
+ "Subsequent API calls to methods other than `olInit` made after resources are released are undefined behavior"
];
let params = [];
let returns = [];
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index ae2975e3ec3c5..c377439d7c0d6 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -94,15 +94,16 @@ struct AllocInfo {
};
using AllocInfoMapT = DenseMap<void *, AllocInfo>;
-AllocInfoMapT &allocInfoMap() {
- static AllocInfoMapT AllocInfoMap{};
- return AllocInfoMap;
-}
+static AllocInfoMapT *AllocInfoMap;
+AllocInfoMapT &allocInfoMap() { return *AllocInfoMap; }
using PlatformVecT = SmallVector<ol_platform_impl_t, 4>;
-PlatformVecT &Platforms() {
- static PlatformVecT Platforms;
- return Platforms;
+static PlatformVecT *PlatformList;
+PlatformVecT &Platforms() { return *PlatformList; }
+
+static std::atomic_int &GlobalRefCount() {
+ static std::atomic_int Ref{0};
+ return Ref;
}
ol_device_handle_t HostDevice() {
@@ -130,6 +131,9 @@ constexpr ol_platform_backend_t pluginNameToBackend(StringRef Name) {
#include "Shared/Targets.def"
void initPlugins() {
+ PlatformList = new PlatformVecT();
+ AllocInfoMap = new AllocInfoMapT();
+
// Attempt to create an instance of each supported plugin.
#define PLUGIN_TARGET(Name) \
do { \
@@ -169,13 +173,16 @@ void initPlugins() {
}
Error olInit_impl() {
- static std::once_flag InitFlag;
- std::call_once(InitFlag, initPlugins);
+ if (++GlobalRefCount() == 1)
+ initPlugins();
return Error::success();
}
Error olShutDown_impl() {
+ if (--GlobalRefCount() != 0)
+ return Error::success();
+
llvm::Error Result = Error::success();
for (auto &P : Platforms()) {
@@ -187,6 +194,11 @@ Error olShutDown_impl() {
Result = llvm::joinErrors(std::move(Result), std::move(Res));
}
+ delete PlatformList;
+ PlatformList = nullptr;
+ delete AllocInfoMap;
+ AllocInfoMap = nullptr;
+
return Result;
}
diff --git a/offload/unittests/OffloadAPI/CMakeLists.txt b/offload/unittests/OffloadAPI/CMakeLists.txt
index 2844b675e5de1..05e862865ed33 100644
--- a/offload/unittests/OffloadAPI/CMakeLists.txt
+++ b/offload/unittests/OffloadAPI/CMakeLists.txt
@@ -12,6 +12,10 @@ add_offload_unittest("event"
event/olDestroyEvent.cpp
event/olWaitEvent.cpp)
+add_offload_unittest("init"
+ init/olInit.cpp)
+target_compile_definitions("init.unittests" PRIVATE DISABLE_WRAPPER)
+
add_offload_unittest("kernel"
kernel/olGetKernel.cpp
kernel/olLaunchKernel.cpp)
diff --git a/offload/unittests/OffloadAPI/common/Environment.cpp b/offload/unittests/OffloadAPI/common/Environment.cpp
index 943347246b6d2..739da4515af0e 100644
--- a/offload/unittests/OffloadAPI/common/Environment.cpp
+++ b/offload/unittests/OffloadAPI/common/Environment.cpp
@@ -15,6 +15,7 @@
using namespace llvm;
+#ifndef DISABLE_WRAPPER
// Wrapper so we don't have to constantly init and shutdown Offload in every
// test, while having sensible lifetime for the platform environment
struct OffloadInitWrapper {
@@ -22,6 +23,7 @@ struct OffloadInitWrapper {
~OffloadInitWrapper() { olShutDown(); }
};
static OffloadInitWrapper Wrapper{};
+#endif
static cl::opt<std::string>
SelectedPlatform("platform", cl::desc("Only test the specified platform"),
diff --git a/offload/unittests/OffloadAPI/init/olInit.cpp b/offload/unittests/OffloadAPI/init/olInit.cpp
new file mode 100644
index 0000000000000..7e9eb4f944dd8
--- /dev/null
+++ b/offload/unittests/OffloadAPI/init/olInit.cpp
@@ -0,0 +1,25 @@
+//===------- Offload API tests - olInit -----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "../common/Fixtures.hpp"
+#include <OffloadAPI.h>
+#include <gtest/gtest.h>
+
+struct olInitTest : ::testing::Test {};
+
+TEST_F(olInitTest, Success) {
+ ASSERT_SUCCESS(olInit());
+ ASSERT_SUCCESS(olShutDown());
+}
+
+TEST_F(olInitTest, RepeatedInit) {
+ for (size_t I = 0; I < 10; I ++) {
+ ASSERT_SUCCESS(olInit());
+ ASSERT_SUCCESS(olShutDown());
+ }
+}
>From 058bc19b4e3c20fe3cedfe947a1e9136914d394d Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Mon, 16 Jun 2025 10:09:31 +0100
Subject: [PATCH 6/7] Clang-format
---
offload/unittests/OffloadAPI/init/olInit.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/offload/unittests/OffloadAPI/init/olInit.cpp b/offload/unittests/OffloadAPI/init/olInit.cpp
index 7e9eb4f944dd8..bca7924f6f374 100644
--- a/offload/unittests/OffloadAPI/init/olInit.cpp
+++ b/offload/unittests/OffloadAPI/init/olInit.cpp
@@ -18,7 +18,7 @@ TEST_F(olInitTest, Success) {
}
TEST_F(olInitTest, RepeatedInit) {
- for (size_t I = 0; I < 10; I ++) {
+ for (size_t I = 0; I < 10; I++) {
ASSERT_SUCCESS(olInit());
ASSERT_SUCCESS(olShutDown());
}
>From afe7a564c27379848a4f130561e28db49e3642a6 Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Mon, 16 Jun 2025 14:13:20 +0100
Subject: [PATCH 7/7] Add mutex guard
---
offload/liboffload/src/OffloadImpl.cpp | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index c377439d7c0d6..89261ead508d5 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -173,6 +173,12 @@ void initPlugins() {
}
Error olInit_impl() {
+ // While the refcount increment ensures that only thread performs
+ // initialization, we need to ensure that other threads are blocked until it
+ // is completed - hence this mutex.
+ static std::mutex Init{};
+ std::lock_guard<std::mutex> Guard{Init};
+
if (++GlobalRefCount() == 1)
initPlugins();
More information about the llvm-commits
mailing list