Skip to content

Commit fb4ab95

Browse files
jhuber6ronlieb
authored andcommitted
[Libomptarget] Remove global ctor and use reference counting (llvm#80499)
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 llvm#80460 Change-Id: I70815457fab9b5d68db8e48b3b5e1c75951c05f5
1 parent 761733f commit fb4ab95

File tree

7 files changed

+88
-15
lines changed

7 files changed

+88
-15
lines changed

openmp/libomptarget/include/PluginManager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ struct PluginManager {
210210
ProtectedObj<DeviceContainerTy> Devices;
211211
};
212212

213+
/// Initialize the plugin manager and OpenMP runtime.
214+
void initRuntime();
215+
216+
/// Deinitialize the plugin and delete it.
217+
void deinitRuntime();
218+
213219
extern PluginManager *PM;
214220

215221
#endif // OMPTARGET_PLUGIN_MANAGER_H

openmp/libomptarget/include/omptarget.h

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

324+
/// Initializes the runtime library.
325+
void __tgt_rtl_init();
326+
327+
/// Deinitializes the runtime library.
328+
void __tgt_rtl_deinit();
329+
324330
/// adds a target shared library to the target execution image
325331
void __tgt_register_lib(__tgt_bin_desc *Desc);
326332

openmp/libomptarget/src/OffloadRTL.cpp

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

23-
__attribute__((constructor(101))) void init() {
23+
static std::mutex PluginMtx;
24+
static 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+
PM = new PluginManager();
3033

34+
RefCount++;
35+
if (RefCount == 1) {
36+
DP("Init offload library!\n");
3137
#ifdef OMPT_SUPPORT
32-
// Initialize OMPT first
33-
llvm::omp::target::ompt::connectLibrary();
38+
// Initialize OMPT first
39+
llvm::omp::target::ompt::connectLibrary();
3440
#endif
3541

36-
PM->init();
37-
38-
PM->registerDelayedLibraries();
42+
PM->init();
43+
PM->registerDelayedLibraries();
44+
}
3945
}
4046

41-
__attribute__((destructor(101))) void deinit() {
47+
void deinitRuntime() {
48+
std::scoped_lock<decltype(PluginMtx)> Lock(PluginMtx);
49+
assert(PM && "Runtime not initialized");
50+
51+
if (RefCount == 1) {
52+
DP("Deinit offload library!\n");
53+
delete PM;
54+
PM = nullptr;
55+
}
4256

43-
DP("Deinit offload library!\n");
44-
delete PM;
57+
RefCount--;
4558
}
4659

4760
// HACK: These depricated device stubs still needs host versions for fallback

openmp/libomptarget/src/PluginManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
using namespace llvm;
2424
using namespace llvm::sys;
2525

26-
PluginManager *PM;
26+
PluginManager *PM = nullptr;
2727

2828
// List of all plugins that can support offloading.
2929
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: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ EXTERN void __tgt_register_requires(int64_t Flags) {
3838
__PRETTY_FUNCTION__);
3939
}
4040

41+
EXTERN void __tgt_rtl_init() { initRuntime(); }
42+
EXTERN void __tgt_rtl_deinit() { deinitRuntime(); }
43+
4144
////////////////////////////////////////////////////////////////////////////////
4245
/// adds a target shared library to the target execution image
4346
EXTERN void __tgt_register_lib(__tgt_bin_desc *Desc) {
4447
TIMESCOPE();
48+
initRuntime();
4549
if (PM->delayRegisterLib(Desc))
4650
return;
4751

@@ -50,13 +54,18 @@ EXTERN void __tgt_register_lib(__tgt_bin_desc *Desc) {
5054

5155
////////////////////////////////////////////////////////////////////////////////
5256
/// Initialize all available devices without registering any image
53-
EXTERN void __tgt_init_all_rtls() { PM->initAllPlugins(); }
57+
EXTERN void __tgt_init_all_rtls() {
58+
assert(PM && "Runtime not initialized");
59+
PM->initAllPlugins();
60+
}
5461

5562
////////////////////////////////////////////////////////////////////////////////
5663
/// unloads a target shared library
5764
EXTERN void __tgt_unregister_lib(__tgt_bin_desc *Desc) {
5865
TIMESCOPE();
5966
PM->unregisterLib(Desc);
67+
68+
deinitRuntime();
6069
}
6170

6271
template <typename TargetAsyncInfoTy>
@@ -66,6 +75,7 @@ targetData(ident_t *Loc, int64_t DeviceId, int32_t ArgNum, void **ArgsBase,
6675
map_var_info_t *ArgNames, void **ArgMappers,
6776
TargetDataFuncPtrTy TargetDataFunction, const char *RegionTypeMsg,
6877
const char *RegionName) {
78+
assert(PM && "Runtime not initialized");
6979
static_assert(std::is_convertible_v<TargetAsyncInfoTy, AsyncInfoTy>,
7080
"TargetAsyncInfoTy must be convertible to AsyncInfoTy.");
7181

@@ -255,6 +265,7 @@ template <typename TargetAsyncInfoTy>
255265
static inline int targetKernel(ident_t *Loc, int64_t DeviceId, int32_t NumTeams,
256266
int32_t ThreadLimit, void *HostPtr,
257267
KernelArgsTy *KernelArgs) {
268+
assert(PM && "Runtime not initialized");
258269
static_assert(std::is_convertible_v<TargetAsyncInfoTy, AsyncInfoTy>,
259270
"Target AsyncInfoTy must be convertible to AsyncInfoTy.");
260271

@@ -362,6 +373,7 @@ EXTERN int __tgt_activate_record_replay(int64_t DeviceId, uint64_t MemorySize,
362373
void *VAddr, bool IsRecord,
363374
bool SaveOutput,
364375
uint64_t &ReqPtrArgOffset) {
376+
assert(PM && "Runtime not initialized");
365377
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
366378
auto DeviceOrErr = PM->getDevice(DeviceId);
367379
if (!DeviceOrErr)
@@ -397,7 +409,7 @@ EXTERN int __tgt_target_kernel_replay(ident_t *Loc, int64_t DeviceId,
397409
ptrdiff_t *TgtOffsets, int32_t NumArgs,
398410
int32_t NumTeams, int32_t ThreadLimit,
399411
uint64_t LoopTripCount) {
400-
412+
assert(PM && "Runtime not initialized");
401413
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
402414
if (checkDeviceAndCtors(DeviceId, Loc)) {
403415
DP("Not offloading to device %" PRId64 "\n", DeviceId);
@@ -456,6 +468,7 @@ EXTERN void __tgt_push_mapper_component(void *RtMapperHandle, void *Base,
456468
}
457469

458470
EXTERN void __tgt_set_info_flag(uint32_t NewInfoLevel) {
471+
assert(PM && "Runtime not initialized");
459472
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
460473
std::atomic<uint32_t> &InfoLevel = getInfoLevelInternal();
461474
InfoLevel.store(NewInfoLevel);
@@ -466,6 +479,7 @@ EXTERN void __tgt_set_info_flag(uint32_t NewInfoLevel) {
466479
}
467480

468481
EXTERN int __tgt_print_device_info(int64_t DeviceId) {
482+
assert(PM && "Runtime not initialized");
469483
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
470484
auto DeviceOrErr = PM->getDevice(DeviceId);
471485
if (!DeviceOrErr)
@@ -475,7 +489,9 @@ EXTERN int __tgt_print_device_info(int64_t DeviceId) {
475489
}
476490

477491
EXTERN void __tgt_target_nowait_query(void **AsyncHandle) {
492+
assert(PM && "Runtime not initialized");
478493
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
494+
479495
if (!AsyncHandle || !*AsyncHandle) {
480496
FATAL_MESSAGE0(
481497
1, "Receive an invalid async handle from the current OpenMP task. Is "
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %libomptarget-compile-generic
2+
// RUN: env LIBOMPTARGET_DEBUG=1 %libomptarget-run-generic 2>&1 \
3+
// RUN: %fcheck-generic
4+
5+
// REQUIRES: libomptarget-debug
6+
7+
#include <omp.h>
8+
#include <stdio.h>
9+
10+
extern void __tgt_rtl_init(void);
11+
extern void __tgt_rtl_deinit(void);
12+
13+
// Sanity checks to make sure that this works and is thread safe.
14+
int main() {
15+
// CHECK: Init offload library!
16+
// CHECK: Deinit offload library!
17+
__tgt_rtl_init();
18+
#pragma omp parallel num_threads(8)
19+
{
20+
__tgt_rtl_init();
21+
__tgt_rtl_deinit();
22+
}
23+
__tgt_rtl_deinit();
24+
25+
__tgt_rtl_init();
26+
__tgt_rtl_deinit();
27+
28+
// CHECK: PASS
29+
printf("PASS\n");
30+
}

0 commit comments

Comments
 (0)