Skip to content

Commit 692c687

Browse files
committed
[Libomptarget] Remove global ctor and use reference counting
Summary: Currently we rely on global constructors to initialize and shut down the OpenMP runtime library and plugin manager. This causes some issues because we do not have a defined lifetime that we can rely on to release and allocate resources. This patch instead adds some simple reference counted initialization and deinitialization function. A future patch will use the `deinit` interface to more intelligently handle plugin deinitilization. Right now we do nothing and rely on `atexit` inside of the plugins to tear them down. This isn't great because it limits our ability to control these things. Note that I made the `__tgt_register_lib` functions do the initialization instead of adding calls to the new runtime functions in the linker wrapper. The reason for this is because in the past it's been easier to not introduce a new function call, since sometimes the user's compiler will link against an older `libomptarget`. Maybe if we change the name with offloading in the future we can simplify this. Depends on #80460
1 parent 43dd1e8 commit 692c687

File tree

7 files changed

+82
-13
lines changed

7 files changed

+82
-13
lines changed

openmp/libomptarget/include/PluginManager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,12 @@ struct PluginManager {
206206
ProtectedObj<DeviceContainerTy> Devices;
207207
};
208208

209+
/// Initialize the plugin manager and OpenMP runtime.
210+
void initRuntime();
211+
212+
/// Deinitialize the plugin and delete it.
213+
void deinitRuntime();
214+
209215
extern PluginManager *PM;
210216

211217
#endif // OMPTARGET_PLUGIN_MANAGER_H

openmp/libomptarget/include/omptarget.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,12 @@ void *llvm_omp_target_dynamic_shared_alloc();
310310
/// add the clauses of the requires directives in a given file
311311
void __tgt_register_requires(int64_t Flags);
312312

313+
/// Initializes the runtime library.
314+
void __tgt_rtl_init();
315+
316+
/// Deinitializes the runtime library.
317+
void __tgt_rtl_deinit();
318+
313319
/// adds a target shared library to the target execution image
314320
void __tgt_register_lib(__tgt_bin_desc *Desc);
315321

openmp/libomptarget/src/OffloadRTL.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,37 @@
2020
extern void llvm::omp::target::ompt::connectLibrary();
2121
#endif
2222

23-
__attribute__((constructor(101))) void init() {
23+
static std::mutex PluginMtx;
24+
static std::atomic<uint32_t> RefCount = 0;
25+
26+
void initRuntime() {
27+
std::scoped_lock<decltype(PluginMtx)> Lock(PluginMtx);
2428
Profiler::get();
2529
TIMESCOPE();
2630

27-
DP("Init offload library!\n");
28-
29-
PM = new PluginManager();
31+
if (PM == nullptr) {
32+
DP("Init offload library!\n");
33+
PM = new PluginManager();
3034

3135
#ifdef OMPT_SUPPORT
32-
// Initialize OMPT first
33-
llvm::omp::target::ompt::connectLibrary();
36+
// Initialize OMPT first
37+
llvm::omp::target::ompt::connectLibrary();
3438
#endif
3539

36-
PM->init();
40+
PM->init();
41+
PM->registerDelayedLibraries();
42+
}
3743

38-
PM->registerDelayedLibraries();
44+
RefCount++;
3945
}
4046

41-
__attribute__((destructor(101))) void deinit() {
42-
DP("Deinit offload library!\n");
43-
delete PM;
47+
void deinitRuntime() {
48+
std::scoped_lock<decltype(PluginMtx)> Lock(PluginMtx);
49+
if (PM == nullptr)
50+
return;
51+
52+
if (RefCount-- == 0) {
53+
DP("Deinit offload library!\n");
54+
delete PM;
55+
}
4456
}

openmp/libomptarget/src/PluginManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
using namespace llvm;
2222
using namespace llvm::sys;
2323

24-
PluginManager *PM;
24+
PluginManager *PM = nullptr;
2525

2626
// List of all plugins that can support offloading.
2727
static const char *RTLNames[] = {ENABLED_OFFLOAD_PLUGINS};

openmp/libomptarget/src/exports

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
VERS1.0 {
22
global:
3+
__tgt_rtl_init;
4+
__tgt_rtl_deinit;
35
__tgt_register_requires;
46
__tgt_register_lib;
57
__tgt_unregister_lib;

openmp/libomptarget/src/interface.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,13 @@ EXTERN void __tgt_register_requires(int64_t Flags) {
3636
PM->addRequirements(Flags);
3737
}
3838

39+
EXTERN void __tgt_rtl_init() { initRuntime(); }
40+
EXTERN void __tgt_rtl_deinit() { deinitRuntime(); }
41+
3942
////////////////////////////////////////////////////////////////////////////////
4043
/// adds a target shared library to the target execution image
4144
EXTERN void __tgt_register_lib(__tgt_bin_desc *Desc) {
45+
initRuntime();
4246
if (PM->delayRegisterLib(Desc))
4347
return;
4448

@@ -47,12 +51,17 @@ EXTERN void __tgt_register_lib(__tgt_bin_desc *Desc) {
4751

4852
////////////////////////////////////////////////////////////////////////////////
4953
/// Initialize all available devices without registering any image
50-
EXTERN void __tgt_init_all_rtls() { PM->initAllPlugins(); }
54+
EXTERN void __tgt_init_all_rtls() {
55+
assert(PM && "Runtime not initialized");
56+
PM->initAllPlugins();
57+
}
5158

5259
////////////////////////////////////////////////////////////////////////////////
5360
/// unloads a target shared library
5461
EXTERN void __tgt_unregister_lib(__tgt_bin_desc *Desc) {
5562
PM->unregisterLib(Desc);
63+
64+
deinitRuntime();
5665
}
5766

5867
template <typename TargetAsyncInfoTy>
@@ -62,6 +71,7 @@ targetData(ident_t *Loc, int64_t DeviceId, int32_t ArgNum, void **ArgsBase,
6271
map_var_info_t *ArgNames, void **ArgMappers,
6372
TargetDataFuncPtrTy TargetDataFunction, const char *RegionTypeMsg,
6473
const char *RegionName) {
74+
assert(PM && "Runtime not initialized");
6575
static_assert(std::is_convertible_v<TargetAsyncInfoTy, AsyncInfoTy>,
6676
"TargetAsyncInfoTy must be convertible to AsyncInfoTy.");
6777

@@ -236,6 +246,7 @@ template <typename TargetAsyncInfoTy>
236246
static inline int targetKernel(ident_t *Loc, int64_t DeviceId, int32_t NumTeams,
237247
int32_t ThreadLimit, void *HostPtr,
238248
KernelArgsTy *KernelArgs) {
249+
assert(PM && "Runtime not initialized");
239250
static_assert(std::is_convertible_v<TargetAsyncInfoTy, AsyncInfoTy>,
240251
"Target AsyncInfoTy must be convertible to AsyncInfoTy.");
241252
DP("Entering target region for device %" PRId64 " with entry point " DPxMOD
@@ -341,6 +352,7 @@ EXTERN int __tgt_activate_record_replay(int64_t DeviceId, uint64_t MemorySize,
341352
void *VAddr, bool IsRecord,
342353
bool SaveOutput,
343354
uint64_t &ReqPtrArgOffset) {
355+
assert(PM && "Runtime not initialized");
344356
auto DeviceOrErr = PM->getDevice(DeviceId);
345357
if (!DeviceOrErr)
346358
FATAL_MESSAGE(DeviceId, "%s", toString(DeviceOrErr.takeError()).c_str());
@@ -375,6 +387,7 @@ EXTERN int __tgt_target_kernel_replay(ident_t *Loc, int64_t DeviceId,
375387
ptrdiff_t *TgtOffsets, int32_t NumArgs,
376388
int32_t NumTeams, int32_t ThreadLimit,
377389
uint64_t LoopTripCount) {
390+
assert(PM && "Runtime not initialized");
378391

379392
if (checkDeviceAndCtors(DeviceId, Loc)) {
380393
DP("Not offloading to device %" PRId64 "\n", DeviceId);
@@ -425,6 +438,8 @@ EXTERN void __tgt_push_mapper_component(void *RtMapperHandle, void *Base,
425438
}
426439

427440
EXTERN void __tgt_set_info_flag(uint32_t NewInfoLevel) {
441+
assert(PM && "Runtime not initialized");
442+
428443
std::atomic<uint32_t> &InfoLevel = getInfoLevelInternal();
429444
InfoLevel.store(NewInfoLevel);
430445
for (auto &R : PM->pluginAdaptors()) {
@@ -434,6 +449,8 @@ EXTERN void __tgt_set_info_flag(uint32_t NewInfoLevel) {
434449
}
435450

436451
EXTERN int __tgt_print_device_info(int64_t DeviceId) {
452+
assert(PM && "Runtime not initialized");
453+
437454
auto DeviceOrErr = PM->getDevice(DeviceId);
438455
if (!DeviceOrErr)
439456
FATAL_MESSAGE(DeviceId, "%s", toString(DeviceOrErr.takeError()).c_str());
@@ -442,6 +459,8 @@ EXTERN int __tgt_print_device_info(int64_t DeviceId) {
442459
}
443460

444461
EXTERN void __tgt_target_nowait_query(void **AsyncHandle) {
462+
assert(PM && "Runtime not initialized");
463+
445464
if (!AsyncHandle || !*AsyncHandle) {
446465
FATAL_MESSAGE0(
447466
1, "Receive an invalid async handle from the current OpenMP task. Is "
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %libomptarget-compile-run-and-check-generic
2+
3+
#include <omp.h>
4+
#include <stdio.h>
5+
6+
extern void __tgt_rtl_init(void);
7+
extern void __tgt_rtl_deinit(void);
8+
9+
// Sanity checks to make sure that this works and is thread safe.
10+
int main() {
11+
__tgt_rtl_init();
12+
#pragma omp parallel num_threads(8)
13+
{
14+
__tgt_rtl_init();
15+
__tgt_rtl_deinit();
16+
}
17+
__tgt_rtl_deinit();
18+
19+
__tgt_rtl_init();
20+
__tgt_rtl_deinit();
21+
22+
// CHECK: PASS
23+
printf("PASS\n");
24+
}

0 commit comments

Comments
 (0)