Skip to content

Commit fa9e90f

Browse files
committed
[Reland][Libomptarget] Statically link all plugin runtimes (#87009)
This patch overhauls the `libomptarget` and plugin interface. Currently, we define a C API and compile each plugin as a separate shared library. Then, `libomptarget` loads these API functions and forwards its internal calls to them. This was originally designed to allow multiple implementations of a library to be live. However, since then no one has used this functionality and it prevents us from using much nicer interfaces. If the old behavior is desired it should instead be implemented as a separate plugin. This patch replaces the `PluginAdaptorTy` interface with the `GenericPluginTy` that is used by the plugins. Each plugin exports a `createPlugin_<name>` function that is used to get the specific implementation. This code is now shared with `libomptarget`. There are some notable improvements to this. 1. Massively improved lifetimes of life runtime objects 2. The plugins can use a C++ interface 3. Global state does not need to be duplicated for each plugin + libomptarget 4. Easier to use and add features and improve error handling 5. Less function call overhead / Improved LTO performance. Additional changes in this plugin are related to contending with the fact that state is now shared. Initialization and deinitialization is now handled correctly and in phase with the underlying runtime, allowing us to actually know when something is getting deallocated. Depends on #86971 #86875 #86868
1 parent 846ffc7 commit fa9e90f

File tree

24 files changed

+125
-523
lines changed

24 files changed

+125
-523
lines changed

clang/test/Driver/linker-wrapper-image.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030

3131
// OPENMP: define internal void @.omp_offloading.descriptor_reg() section ".text.startup" {
3232
// OPENMP-NEXT: entry:
33-
// OPENMP-NEXT: %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg)
3433
// OPENMP-NEXT: call void @__tgt_register_lib(ptr @.omp_offloading.descriptor)
34+
// OPENMP-NEXT: %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg)
3535
// OPENMP-NEXT: ret void
3636
// OPENMP-NEXT: }
3737

llvm/lib/Frontend/Offloading/OffloadWrapper.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,13 @@ void createRegisterFunction(Module &M, GlobalVariable *BinDesc,
232232
// Construct function body
233233
IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
234234

235+
Builder.CreateCall(RegFuncC, BinDesc);
236+
235237
// Register the destructors with 'atexit'. This is expected by the CUDA
236238
// runtime and ensures that we clean up before dynamic objects are destroyed.
237-
// This needs to be done before the runtime is called and registers its own.
239+
// This needs to be done after plugin initialization to ensure that it is
240+
// called before the plugin runtime is destroyed.
238241
Builder.CreateCall(AtExit, UnregFunc);
239-
240-
Builder.CreateCall(RegFuncC, BinDesc);
241242
Builder.CreateRetVoid();
242243

243244
// Add this function to constructors.

offload/include/PluginManager.h

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
#ifndef OMPTARGET_PLUGIN_MANAGER_H
1414
#define OMPTARGET_PLUGIN_MANAGER_H
1515

16+
#include "PluginInterface.h"
17+
1618
#include "DeviceImage.h"
1719
#include "ExclusiveAccess.h"
1820
#include "Shared/APITypes.h"
19-
#include "Shared/PluginAPI.h"
2021
#include "Shared/Requirements.h"
2122

2223
#include "device.h"
@@ -34,38 +35,7 @@
3435
#include <mutex>
3536
#include <string>
3637

37-
struct PluginManager;
38-
39-
/// Plugin adaptors should be created via `PluginAdaptorTy::create` which will
40-
/// invoke the constructor and call `PluginAdaptorTy::init`. Eventual errors are
41-
/// reported back to the caller, otherwise a valid and initialized adaptor is
42-
/// returned.
43-
struct PluginAdaptorTy {
44-
/// Try to create a plugin adaptor from a filename.
45-
static llvm::Expected<std::unique_ptr<PluginAdaptorTy>>
46-
create(const std::string &Name);
47-
48-
/// Name of the shared object file representing the plugin.
49-
std::string Name;
50-
51-
/// Access to the shared object file representing the plugin.
52-
std::unique_ptr<llvm::sys::DynamicLibrary> LibraryHandler;
53-
54-
#define PLUGIN_API_HANDLE(NAME) \
55-
using NAME##_ty = decltype(__tgt_rtl_##NAME); \
56-
NAME##_ty *NAME = nullptr;
57-
58-
#include "Shared/PluginAPI.inc"
59-
#undef PLUGIN_API_HANDLE
60-
61-
/// Create a plugin adaptor for filename \p Name with a dynamic library \p DL.
62-
PluginAdaptorTy(const std::string &Name,
63-
std::unique_ptr<llvm::sys::DynamicLibrary> DL);
64-
65-
/// Initialize the plugin adaptor, this can fail in which case the adaptor is
66-
/// useless.
67-
llvm::Error init();
68-
};
38+
using GenericPluginTy = llvm::omp::target::plugin::GenericPluginTy;
6939

7040
/// Struct for the data required to handle plugins
7141
struct PluginManager {
@@ -80,6 +50,8 @@ struct PluginManager {
8050

8151
void init();
8252

53+
void deinit();
54+
8355
// Register a shared library with all (compatible) RTLs.
8456
void registerLib(__tgt_bin_desc *Desc);
8557

@@ -92,10 +64,9 @@ struct PluginManager {
9264
std::make_unique<DeviceImageTy>(TgtBinDesc, TgtDeviceImage));
9365
}
9466

95-
/// Initialize as many devices as possible for this plugin adaptor. Devices
96-
/// that fail to initialize are ignored. Returns the offset the devices were
97-
/// registered at.
98-
void initDevices(PluginAdaptorTy &RTL);
67+
/// Initialize as many devices as possible for this plugin. Devices that fail
68+
/// to initialize are ignored.
69+
void initDevices(GenericPluginTy &RTL);
9970

10071
/// Return the device presented to the user as device \p DeviceNo if it is
10172
/// initialized and ready. Otherwise return an error explaining the problem.
@@ -151,8 +122,8 @@ struct PluginManager {
151122
// Initialize all plugins.
152123
void initAllPlugins();
153124

154-
/// Iterator range for all plugin adaptors (in use or not, but always valid).
155-
auto pluginAdaptors() { return llvm::make_pointee_range(PluginAdaptors); }
125+
/// Iterator range for all plugins (in use or not, but always valid).
126+
auto plugins() { return llvm::make_pointee_range(Plugins); }
156127

157128
/// Return the user provided requirements.
158129
int64_t getRequirements() const { return Requirements.getRequirements(); }
@@ -164,14 +135,14 @@ struct PluginManager {
164135
bool RTLsLoaded = false;
165136
llvm::SmallVector<__tgt_bin_desc *> DelayedBinDesc;
166137

167-
// List of all plugin adaptors, in use or not.
168-
llvm::SmallVector<std::unique_ptr<PluginAdaptorTy>> PluginAdaptors;
138+
// List of all plugins, in use or not.
139+
llvm::SmallVector<std::unique_ptr<GenericPluginTy>> Plugins;
169140

170-
// Mapping of plugin adaptors to offsets in the device table.
171-
llvm::DenseMap<const PluginAdaptorTy *, int32_t> DeviceOffsets;
141+
// Mapping of plugins to offsets in the device table.
142+
llvm::DenseMap<const GenericPluginTy *, int32_t> DeviceOffsets;
172143

173-
// Mapping of plugin adaptors to the number of used devices.
174-
llvm::DenseMap<const PluginAdaptorTy *, int32_t> DeviceUsed;
144+
// Mapping of plugins to the number of used devices.
145+
llvm::DenseMap<const GenericPluginTy *, int32_t> DeviceUsed;
175146

176147
// Set of all device images currently in use.
177148
llvm::DenseSet<const __tgt_device_image *> UsedImages;

offload/include/device.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,19 @@
3333
#include "llvm/ADT/DenseMap.h"
3434
#include "llvm/ADT/SmallVector.h"
3535

36+
#include "PluginInterface.h"
37+
using GenericPluginTy = llvm::omp::target::plugin::GenericPluginTy;
38+
3639
// Forward declarations.
37-
struct PluginAdaptorTy;
3840
struct __tgt_bin_desc;
3941
struct __tgt_target_table;
4042

4143
struct DeviceTy {
4244
int32_t DeviceID;
43-
PluginAdaptorTy *RTL;
45+
GenericPluginTy *RTL;
4446
int32_t RTLDeviceID;
4547

46-
DeviceTy(PluginAdaptorTy *RTL, int32_t DeviceID, int32_t RTLDeviceID);
48+
DeviceTy(GenericPluginTy *RTL, int32_t DeviceID, int32_t RTLDeviceID);
4749
// DeviceTy is not copyable
4850
DeviceTy(const DeviceTy &D) = delete;
4951
DeviceTy &operator=(const DeviceTy &D) = delete;

offload/plugins-nextgen/CMakeLists.txt

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
set(common_dir ${CMAKE_CURRENT_SOURCE_DIR}/common)
1515
add_subdirectory(common)
1616
function(add_target_library target_name lib_name)
17-
add_llvm_library(${target_name} SHARED
17+
add_llvm_library(${target_name} STATIC
1818
LINK_COMPONENTS
1919
${LLVM_TARGETS_TO_BUILD}
2020
AggressiveInstCombine
@@ -46,27 +46,14 @@ function(add_target_library target_name lib_name)
4646
)
4747

4848
llvm_update_compile_flags(${target_name})
49+
target_include_directories(${target_name} PUBLIC ${common_dir}/include)
4950
target_link_libraries(${target_name} PRIVATE
5051
PluginCommon ${OPENMP_PTHREAD_LIB})
5152

5253
target_compile_definitions(${target_name} PRIVATE TARGET_NAME=${lib_name})
5354
target_compile_definitions(${target_name} PRIVATE
5455
DEBUG_PREFIX="TARGET ${lib_name} RTL")
55-
56-
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
57-
# On FreeBSD, the 'environ' symbol is undefined at link time, but resolved by
58-
# the dynamic linker at runtime. Therefore, allow the symbol to be undefined
59-
# when creating a shared library.
60-
target_link_libraries(${target_name} PRIVATE "-Wl,--allow-shlib-undefined")
61-
else()
62-
target_link_libraries(${target_name} PRIVATE "-Wl,-z,defs")
63-
endif()
64-
65-
if(LIBOMP_HAVE_VERSION_SCRIPT_FLAG)
66-
target_link_libraries(${target_name} PRIVATE
67-
"-Wl,--version-script=${common_dir}/../exports")
68-
endif()
69-
set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET protected)
56+
set_target_properties(${target_name} PROPERTIES POSITION_INDEPENDENT_CODE ON)
7057
endfunction()
7158

7259
foreach(plugin IN LISTS LIBOMPTARGET_PLUGINS_TO_BUILD)

offload/plugins-nextgen/amdgpu/CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,3 @@ else()
5757
libomptarget_say("Not generating AMDGPU tests, no supported devices detected."
5858
" Use 'LIBOMPTARGET_FORCE_AMDGPU_TESTS' to override.")
5959
endif()
60-
61-
# Install plugin under the lib destination folder.
62-
install(TARGETS omptarget.rtl.amdgpu LIBRARY DESTINATION "${OFFLOAD_INSTALL_LIBDIR}")
63-
set_target_properties(omptarget.rtl.amdgpu PROPERTIES
64-
INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$ORIGIN:${CMAKE_CURRENT_BINARY_DIR}/..")

offload/plugins-nextgen/amdgpu/src/rtl.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3064,10 +3064,6 @@ struct AMDGPUPluginTy final : public GenericPluginTy {
30643064
// HSA functions from now on, e.g., hsa_shut_down.
30653065
Initialized = true;
30663066

3067-
#ifdef OMPT_SUPPORT
3068-
ompt::connectLibrary();
3069-
#endif
3070-
30713067
// Register event handler to detect memory errors on the devices.
30723068
Status = hsa_amd_register_system_event_handler(eventHandler, nullptr);
30733069
if (auto Err = Plugin::check(
@@ -3155,6 +3151,8 @@ struct AMDGPUPluginTy final : public GenericPluginTy {
31553151

31563152
Triple::ArchType getTripleArch() const override { return Triple::amdgcn; }
31573153

3154+
const char *getName() const override { return GETNAME(TARGET_NAME); }
3155+
31583156
/// Get the ELF code for recognizing the compatible image binary.
31593157
uint16_t getMagicElfBits() const override { return ELF::EM_AMDGPU; }
31603158

@@ -3387,8 +3385,6 @@ Error AMDGPUKernelTy::printLaunchInfoDetails(GenericDeviceTy &GenericDevice,
33873385
return Plugin::success();
33883386
}
33893387

3390-
GenericPluginTy *PluginTy::createPlugin() { return new AMDGPUPluginTy(); }
3391-
33923388
template <typename... ArgsTy>
33933389
static Error Plugin::check(int32_t Code, const char *ErrFmt, ArgsTy... Args) {
33943390
hsa_status_t ResultCode = static_cast<hsa_status_t>(Code);
@@ -3476,3 +3472,9 @@ void *AMDGPUDeviceTy::allocate(size_t Size, void *, TargetAllocTy Kind) {
34763472
} // namespace target
34773473
} // namespace omp
34783474
} // namespace llvm
3475+
3476+
extern "C" {
3477+
llvm::omp::target::plugin::GenericPluginTy *createPlugin_amdgpu() {
3478+
return new llvm::omp::target::plugin::AMDGPUPluginTy();
3479+
}
3480+
}

offload/plugins-nextgen/common/CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,4 @@ target_include_directories(PluginCommon PUBLIC
6666
${LIBOMPTARGET_INCLUDE_DIR}
6767
)
6868

69-
set_target_properties(PluginCommon PROPERTIES
70-
POSITION_INDEPENDENT_CODE ON
71-
CXX_VISIBILITY_PRESET protected)
69+
set_target_properties(PluginCommon PROPERTIES POSITION_INDEPENDENT_CODE ON)

offload/plugins-nextgen/common/include/PluginInterface.h

Lines changed: 4 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,9 @@ struct GenericPluginTy {
10101010
/// Get the target triple of this plugin.
10111011
virtual Triple::ArchType getTripleArch() const = 0;
10121012

1013+
/// Get the constant name identifier for this plugin.
1014+
virtual const char *getName() const = 0;
1015+
10131016
/// Allocate a structure using the internal allocator.
10141017
template <typename Ty> Ty *allocate() {
10151018
return reinterpret_cast<Ty *>(Allocator.Allocate(sizeof(Ty), alignof(Ty)));
@@ -1226,7 +1229,7 @@ namespace Plugin {
12261229
/// Create a success error. This is the same as calling Error::success(), but
12271230
/// it is recommended to use this one for consistency with Plugin::error() and
12281231
/// Plugin::check().
1229-
static Error success() { return Error::success(); }
1232+
static inline Error success() { return Error::success(); }
12301233

12311234
/// Create a string error.
12321235
template <typename... ArgsTy>
@@ -1246,95 +1249,6 @@ template <typename... ArgsTy>
12461249
static Error check(int32_t ErrorCode, const char *ErrFmt, ArgsTy... Args);
12471250
} // namespace Plugin
12481251

1249-
/// Class for simplifying the getter operation of the plugin. Anywhere on the
1250-
/// code, the current plugin can be retrieved by Plugin::get(). The class also
1251-
/// declares functions to create plugin-specific object instances. The check(),
1252-
/// createPlugin(), createDevice() and createGlobalHandler() functions should be
1253-
/// defined by each plugin implementation.
1254-
class PluginTy {
1255-
// Reference to the plugin instance.
1256-
static GenericPluginTy *SpecificPlugin;
1257-
1258-
PluginTy() {
1259-
if (auto Err = init())
1260-
REPORT("Failed to initialize plugin: %s\n",
1261-
toString(std::move(Err)).data());
1262-
}
1263-
1264-
~PluginTy() {
1265-
if (auto Err = deinit())
1266-
REPORT("Failed to deinitialize plugin: %s\n",
1267-
toString(std::move(Err)).data());
1268-
}
1269-
1270-
PluginTy(const PluginTy &) = delete;
1271-
void operator=(const PluginTy &) = delete;
1272-
1273-
/// Create and intialize the plugin instance.
1274-
static Error init() {
1275-
assert(!SpecificPlugin && "Plugin already created");
1276-
1277-
// Create the specific plugin.
1278-
SpecificPlugin = createPlugin();
1279-
assert(SpecificPlugin && "Plugin was not created");
1280-
1281-
// Initialize the plugin.
1282-
return SpecificPlugin->init();
1283-
}
1284-
1285-
// Deinitialize and destroy the plugin instance.
1286-
static Error deinit() {
1287-
assert(SpecificPlugin && "Plugin no longer valid");
1288-
1289-
for (int32_t DevNo = 0, NumDev = SpecificPlugin->getNumDevices();
1290-
DevNo < NumDev; ++DevNo)
1291-
if (auto Err = SpecificPlugin->deinitDevice(DevNo))
1292-
return Err;
1293-
1294-
// Deinitialize the plugin.
1295-
if (auto Err = SpecificPlugin->deinit())
1296-
return Err;
1297-
1298-
// Delete the plugin instance.
1299-
delete SpecificPlugin;
1300-
1301-
// Invalidate the plugin reference.
1302-
SpecificPlugin = nullptr;
1303-
1304-
return Plugin::success();
1305-
}
1306-
1307-
public:
1308-
/// Initialize the plugin if needed. The plugin could have been initialized by
1309-
/// a previous call to Plugin::get().
1310-
static Error initIfNeeded() {
1311-
// Trigger the initialization if needed.
1312-
get();
1313-
1314-
return Error::success();
1315-
}
1316-
1317-
/// Get a reference (or create if it was not created) to the plugin instance.
1318-
static GenericPluginTy &get() {
1319-
// This static variable will initialize the underlying plugin instance in
1320-
// case there was no previous explicit initialization. The initialization is
1321-
// thread safe.
1322-
static PluginTy Plugin;
1323-
1324-
assert(SpecificPlugin && "Plugin is not active");
1325-
return *SpecificPlugin;
1326-
}
1327-
1328-
/// Get a reference to the plugin with a specific plugin-specific type.
1329-
template <typename Ty> static Ty &get() { return static_cast<Ty &>(get()); }
1330-
1331-
/// Indicate whether the plugin is active.
1332-
static bool isActive() { return SpecificPlugin != nullptr; }
1333-
1334-
/// Create a plugin instance.
1335-
static GenericPluginTy *createPlugin();
1336-
};
1337-
13381252
/// Auxiliary interface class for GenericDeviceResourceManagerTy. This class
13391253
/// acts as a reference to a device resource, such as a stream, and requires
13401254
/// some basic functions to be implemented. The derived class should define an

offload/plugins-nextgen/common/include/Utils/ELF.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
#ifndef LLVM_OPENMP_LIBOMPTARGET_PLUGINS_ELF_UTILS_H
1414
#define LLVM_OPENMP_LIBOMPTARGET_PLUGINS_ELF_UTILS_H
1515

16-
#include "Shared/PluginAPI.h"
17-
1816
#include "llvm/Object/ELF.h"
1917
#include "llvm/Object/ELFObjectFile.h"
2018

0 commit comments

Comments
 (0)