Skip to content

Commit 68db7ae

Browse files
authored
[OpenMP] Reorganize the initialization of PluginAdaptorTy (#74397)
This introduces checked errors into the creation and initialization of `PluginAdaptorTy`. We also allow the adaptor to "hide" devices from the user if the initialization failed. The new organization avoids the "initOnce" stuff but we still do not eagerly initialize the plugin devices (I think we should merge `PluginAdaptorTy::initDevices` into `PluginAdaptorTy::init`)
1 parent bb0f162 commit 68db7ae

File tree

5 files changed

+137
-99
lines changed

5 files changed

+137
-99
lines changed

openmp/libomptarget/include/PluginManager.h

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,29 @@
3434
#include <mutex>
3535
#include <string>
3636

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.
3743
struct PluginAdaptorTy {
38-
PluginAdaptorTy(const std::string &Name);
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+
/// Initialize as many devices as possible for this plugin adaptor. Devices
49+
/// that fail to initialize are ignored.
50+
void initDevices(PluginManager &PM);
3951

4052
bool isUsed() const { return DeviceOffset >= 0; }
4153

42-
/// Return the number of devices available to this plugin.
43-
int32_t getNumDevices() const { return NumberOfDevices; }
54+
/// Return the number of devices visible to the underlying plugin.
55+
int32_t getNumberOfPluginDevices() const { return NumberOfPluginDevices; }
56+
57+
/// Return the number of devices successfully initialized and visible to the
58+
/// user.
59+
int32_t getNumberOfUserDevices() const { return NumberOfUserDevices; }
4460

4561
/// Add all offload entries described by \p DI to the devices managed by this
4662
/// plugin.
@@ -51,9 +67,6 @@ struct PluginAdaptorTy {
5167
/// registered with this RTL.
5268
int32_t DeviceOffset = -1;
5369

54-
/// Number of devices this RTL deals with.
55-
int32_t NumberOfDevices = -1;
56-
5770
/// Name of the shared object file representing the plugin.
5871
std::string Name;
5972

@@ -73,6 +86,22 @@ struct PluginAdaptorTy {
7386
// It is easier to enforce thread-safety at the libomptarget level,
7487
// so that developers of new RTLs do not have to worry about it.
7588
std::mutex Mtx;
89+
90+
private:
91+
/// Number of devices the underling plugins sees.
92+
int32_t NumberOfPluginDevices = -1;
93+
94+
/// Number of devices exposed to the user. This can be less than the number of
95+
/// devices for the plugin if some failed to initialize.
96+
int32_t NumberOfUserDevices = 0;
97+
98+
/// Create a plugin adaptor for filename \p Name with a dynamic library \p DL.
99+
PluginAdaptorTy(const std::string &Name,
100+
std::unique_ptr<llvm::sys::DynamicLibrary> DL);
101+
102+
/// Initialize the plugin adaptor, this can fail in which case the adaptor is
103+
/// useless.
104+
llvm::Error init();
76105
};
77106

78107
/// Struct for the data required to handle plugins
@@ -150,20 +179,15 @@ struct PluginManager {
150179
int getNumUsedPlugins() const {
151180
int NCI = 0;
152181
for (auto &P : PluginAdaptors)
153-
NCI += P.isUsed();
182+
NCI += P->isUsed();
154183
return NCI;
155184
}
156185

157-
// Initialize \p Plugin if it has not been initialized.
158-
void initPlugin(PluginAdaptorTy &Plugin);
159-
160186
// Initialize all plugins.
161187
void initAllPlugins();
162188

163189
/// Iterator range for all plugin adaptors (in use or not, but always valid).
164-
auto pluginAdaptors() {
165-
return llvm::make_range(PluginAdaptors.begin(), PluginAdaptors.end());
166-
}
190+
auto pluginAdaptors() { return llvm::make_pointee_range(PluginAdaptors); }
167191

168192
/// Return the user provided requirements.
169193
int64_t getRequirements() const { return Requirements.getRequirements(); }
@@ -176,7 +200,7 @@ struct PluginManager {
176200
llvm::SmallVector<__tgt_bin_desc *> DelayedBinDesc;
177201

178202
// List of all plugin adaptors, in use or not.
179-
std::list<PluginAdaptorTy> PluginAdaptors;
203+
llvm::SmallVector<std::unique_ptr<PluginAdaptorTy>> PluginAdaptors;
180204

181205
/// Executable images and information extracted from the input images passed
182206
/// to the runtime.

openmp/libomptarget/include/device.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ struct DeviceTy {
5151
PluginAdaptorTy *RTL;
5252
int32_t RTLDeviceID;
5353

54-
bool IsInit;
55-
std::once_flag InitFlag;
5654
bool HasMappedGlobalData = false;
5755

5856
/// Host data to device map type with a wrapper key indirection that allows
@@ -72,13 +70,16 @@ struct DeviceTy {
7270

7371
std::mutex PendingGlobalsMtx;
7472

75-
DeviceTy(PluginAdaptorTy *RTL);
73+
DeviceTy(PluginAdaptorTy *RTL, int32_t DeviceID, int32_t RTLDeviceID);
7674
// DeviceTy is not copyable
7775
DeviceTy(const DeviceTy &D) = delete;
7876
DeviceTy &operator=(const DeviceTy &D) = delete;
7977

8078
~DeviceTy();
8179

80+
/// Try to initialize the device and return any failure.
81+
llvm::Error init();
82+
8283
// Return true if data can be copied to DstDevice directly
8384
bool isDataExchangable(const DeviceTy &DstDevice);
8485

@@ -145,8 +146,6 @@ struct DeviceTy {
145146
int associatePtr(void *HstPtrBegin, void *TgtPtrBegin, int64_t Size);
146147
int disassociatePtr(void *HstPtrBegin);
147148

148-
// calls to RTL
149-
int32_t initOnce();
150149
__tgt_target_table *loadBinary(__tgt_device_image *Img);
151150

152151
// device memory allocation/deallocation routines
@@ -237,9 +236,6 @@ struct DeviceTy {
237236
void dumpOffloadEntries();
238237

239238
private:
240-
// Call to RTL
241-
void init(); // To be called only via DeviceTy::initOnce()
242-
243239
/// Deinitialize the device (and plugin).
244240
void deinit();
245241

openmp/libomptarget/plugins-nextgen/common/src/PluginInterface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,7 +1712,7 @@ int32_t __tgt_rtl_number_of_devices() { return Plugin::get().getNumDevices(); }
17121712

17131713
int64_t __tgt_rtl_init_requires(int64_t RequiresFlags) {
17141714
Plugin::get().setRequiresFlag(RequiresFlags);
1715-
return RequiresFlags;
1715+
return OFFLOAD_SUCCESS;
17161716
}
17171717

17181718
int32_t __tgt_rtl_is_data_exchangable(int32_t SrcDeviceId,

openmp/libomptarget/src/PluginManager.cpp

Lines changed: 78 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "llvm/Support/Error.h"
1717
#include "llvm/Support/ErrorHandling.h"
18+
#include <memory>
1819

1920
using namespace llvm;
2021
using namespace llvm::sys;
@@ -30,27 +31,43 @@ static const char *RTLNames[] = {
3031
/* AMDGPU target */ "libomptarget.rtl.amdgpu",
3132
};
3233

33-
PluginAdaptorTy::PluginAdaptorTy(const std::string &Name) : Name(Name) {
34+
Expected<std::unique_ptr<PluginAdaptorTy>>
35+
PluginAdaptorTy::create(const std::string &Name) {
3436
DP("Attempting to load library '%s'...\n", Name.c_str());
3537

3638
std::string ErrMsg;
37-
LibraryHandler = std::make_unique<DynamicLibrary>(
39+
auto LibraryHandler = std::make_unique<DynamicLibrary>(
3840
DynamicLibrary::getPermanentLibrary(Name.c_str(), &ErrMsg));
3941

4042
if (!LibraryHandler->isValid()) {
4143
// Library does not exist or cannot be found.
42-
DP("Unable to load library '%s': %s!\n", Name.c_str(), ErrMsg.c_str());
43-
return;
44+
return createStringError(inconvertibleErrorCode(),
45+
"Unable to load library '%s': %s!\n", Name.c_str(),
46+
ErrMsg.c_str());
4447
}
4548

4649
DP("Successfully loaded library '%s'!\n", Name.c_str());
50+
auto PluginAdaptor = std::unique_ptr<PluginAdaptorTy>(
51+
new PluginAdaptorTy(Name, std::move(LibraryHandler)));
52+
if (auto Err = PluginAdaptor->init())
53+
return Err;
54+
return PluginAdaptor;
55+
}
56+
57+
PluginAdaptorTy::PluginAdaptorTy(const std::string &Name,
58+
std::unique_ptr<llvm::sys::DynamicLibrary> DL)
59+
: Name(Name), LibraryHandler(std::move(DL)) {}
60+
61+
Error PluginAdaptorTy::init() {
4762

4863
#define PLUGIN_API_HANDLE(NAME, MANDATORY) \
4964
NAME = reinterpret_cast<decltype(NAME)>( \
5065
LibraryHandler->getAddressOfSymbol(GETNAME(__tgt_rtl_##NAME))); \
5166
if (MANDATORY && !NAME) { \
52-
DP("Invalid plugin as necessary interface is not found.\n"); \
53-
return; \
67+
return createStringError(inconvertibleErrorCode(), \
68+
"Invalid plugin as necessary interface function " \
69+
"(%s) was not found.\n", \
70+
NAME); \
5471
}
5572

5673
#include "Shared/PluginAPI.inc"
@@ -59,22 +76,25 @@ PluginAdaptorTy::PluginAdaptorTy(const std::string &Name) : Name(Name) {
5976
// Remove plugin on failure to call optional init_plugin
6077
int32_t Rc = init_plugin();
6178
if (Rc != OFFLOAD_SUCCESS) {
62-
DP("Unable to initialize library '%s': %u!\n", Name.c_str(), Rc);
63-
return;
79+
return createStringError(inconvertibleErrorCode(),
80+
"Unable to initialize library '%s': %u!\n",
81+
Name.c_str(), Rc);
6482
}
6583

6684
// No devices are supported by this RTL?
67-
NumberOfDevices = number_of_devices();
68-
if (!NumberOfDevices) {
69-
DP("No devices supported in this RTL\n");
70-
return;
85+
NumberOfPluginDevices = number_of_devices();
86+
if (!NumberOfPluginDevices) {
87+
return createStringError(inconvertibleErrorCode(),
88+
"No devices supported in this RTL\n");
7189
}
7290

73-
DP("Registered '%s' with %d devices!\n", Name.c_str(), NumberOfDevices);
91+
DP("Registered '%s' with %d plugin visible devices!\n", Name.c_str(),
92+
NumberOfPluginDevices);
93+
return Error::success();
7494
}
7595

7696
void PluginAdaptorTy::addOffloadEntries(DeviceImageTy &DI) {
77-
for (int32_t I = 0; I < NumberOfDevices; ++I) {
97+
for (int32_t I = 0, E = getNumberOfUserDevices(); I < E; ++I) {
7898
auto DeviceOrErr = PM->getDevice(DeviceOffset + I);
7999
if (!DeviceOrErr)
80100
FATAL_MESSAGE(DeviceOffset + I, "%s",
@@ -92,45 +112,61 @@ void PluginManager::init() {
92112
// Attempt to open all the plugins and, if they exist, check if the interface
93113
// is correct and if they are supporting any devices.
94114
for (const char *Name : RTLNames) {
95-
PluginAdaptors.emplace_back(std::string(Name) + ".so");
96-
if (PluginAdaptors.back().getNumDevices() <= 0)
97-
PluginAdaptors.pop_back();
115+
auto PluginAdaptorOrErr =
116+
PluginAdaptorTy::create(std::string(Name) + ".so");
117+
if (!PluginAdaptorOrErr) {
118+
[[maybe_unused]] std::string InfoMsg =
119+
toString(PluginAdaptorOrErr.takeError());
120+
DP("%s", InfoMsg.c_str());
121+
} else {
122+
PluginAdaptors.push_back(std::move(*PluginAdaptorOrErr));
123+
}
98124
}
99125

100126
DP("RTLs loaded!\n");
101127
}
102128

103-
void PluginManager::initPlugin(PluginAdaptorTy &Plugin) {
104-
// If this RTL is not already in use, initialize it.
105-
if (Plugin.isUsed() || !Plugin.NumberOfDevices)
129+
void PluginAdaptorTy::initDevices(PluginManager &PM) {
130+
if (isUsed())
106131
return;
107132

133+
// If this RTL is not already in use, initialize it.
134+
assert(getNumberOfPluginDevices() > 0 &&
135+
"Tried to initialize useless plugin adaptor");
136+
108137
// Initialize the device information for the RTL we are about to use.
109-
auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
110-
const size_t Start = ExclusiveDevicesAccessor->size();
111-
ExclusiveDevicesAccessor->reserve(Start + Plugin.NumberOfDevices);
112-
for (int32_t DeviceId = 0; DeviceId < Plugin.NumberOfDevices; DeviceId++) {
113-
ExclusiveDevicesAccessor->push_back(std::make_unique<DeviceTy>(&Plugin));
114-
// global device ID
115-
(*ExclusiveDevicesAccessor)[Start + DeviceId]->DeviceID = Start + DeviceId;
116-
// RTL local device ID
117-
(*ExclusiveDevicesAccessor)[Start + DeviceId]->RTLDeviceID = DeviceId;
118-
}
138+
auto ExclusiveDevicesAccessor = PM.getExclusiveDevicesAccessor();
119139

120140
// Initialize the index of this RTL and save it in the used RTLs.
121-
Plugin.DeviceOffset = Start;
141+
DeviceOffset = ExclusiveDevicesAccessor->size();
122142

123143
// If possible, set the device identifier offset in the plugin.
124-
if (Plugin.set_device_offset)
125-
Plugin.set_device_offset(Start);
144+
if (set_device_offset)
145+
set_device_offset(DeviceOffset);
146+
147+
int32_t NumPD = getNumberOfPluginDevices();
148+
ExclusiveDevicesAccessor->reserve(DeviceOffset + NumPD);
149+
for (int32_t PDevI = 0, UserDevId = DeviceOffset; PDevI < NumPD; PDevI++) {
150+
auto Device = std::make_unique<DeviceTy>(this, UserDevId, PDevI);
151+
if (auto Err = Device->init()) {
152+
DP("Skip plugin known device %d: %s\n", PDevI,
153+
toString(std::move(Err)).c_str());
154+
continue;
155+
}
156+
157+
ExclusiveDevicesAccessor->push_back(std::move(Device));
158+
++NumberOfUserDevices;
159+
++UserDevId;
160+
}
126161

127-
DP("RTL " DPxMOD " has index %d!\n", DPxPTR(Plugin.LibraryHandler.get()),
128-
Plugin.DeviceOffset);
162+
DP("Plugin adaptor " DPxMOD " has index %d, exposes %d out of %d devices!\n",
163+
DPxPTR(LibraryHandler.get()), DeviceOffset, NumberOfUserDevices,
164+
NumberOfPluginDevices);
129165
}
130166

131167
void PluginManager::initAllPlugins() {
132168
for (auto &R : PluginAdaptors)
133-
initPlugin(R);
169+
R->initDevices(*this);
134170
}
135171

136172
static void registerImageIntoTranslationTable(TranslationTable &TT,
@@ -143,15 +179,16 @@ static void registerImageIntoTranslationTable(TranslationTable &TT,
143179

144180
// Resize the Targets Table and Images to accommodate the new targets if
145181
// required
146-
unsigned TargetsTableMinimumSize = RTL.DeviceOffset + RTL.NumberOfDevices;
182+
unsigned TargetsTableMinimumSize =
183+
RTL.DeviceOffset + RTL.getNumberOfUserDevices();
147184

148185
if (TT.TargetsTable.size() < TargetsTableMinimumSize) {
149186
TT.TargetsImages.resize(TargetsTableMinimumSize, 0);
150187
TT.TargetsTable.resize(TargetsTableMinimumSize, 0);
151188
}
152189

153190
// Register the image in all devices for this target type.
154-
for (int32_t I = 0; I < RTL.NumberOfDevices; ++I) {
191+
for (int32_t I = 0; I < RTL.getNumberOfUserDevices(); ++I) {
155192
// If we are changing the image we are also invalidating the target table.
156193
if (TT.TargetsImages[RTL.DeviceOffset + I] != Image) {
157194
TT.TargetsImages[RTL.DeviceOffset + I] = Image;
@@ -194,7 +231,7 @@ void PluginManager::registerLib(__tgt_bin_desc *Desc) {
194231
DP("Image " DPxMOD " is compatible with RTL %s!\n",
195232
DPxPTR(Img->ImageStart), R.Name.c_str());
196233

197-
PM->initPlugin(R);
234+
R.initDevices(*this);
198235

199236
// Initialize (if necessary) translation table for this library.
200237
PM->TrlTblMtx.lock();
@@ -263,7 +300,7 @@ void PluginManager::unregisterLib(__tgt_bin_desc *Desc) {
263300

264301
// Execute dtors for static objects if the device has been used, i.e.
265302
// if its PendingCtors list has been emptied.
266-
for (int32_t I = 0; I < FoundRTL->NumberOfDevices; ++I) {
303+
for (int32_t I = 0; I < FoundRTL->getNumberOfUserDevices(); ++I) {
267304
auto DeviceOrErr = PM->getDevice(FoundRTL->DeviceOffset + I);
268305
if (!DeviceOrErr)
269306
FATAL_MESSAGE(FoundRTL->DeviceOffset + I, "%s",
@@ -337,17 +374,5 @@ Expected<DeviceTy &> PluginManager::getDevice(uint32_t DeviceNo) {
337374
"Device number '%i' out of range, only %i devices available", DeviceNo,
338375
ExclusiveDevicesAccessor->size());
339376

340-
DeviceTy &Device = *(*ExclusiveDevicesAccessor)[DeviceNo];
341-
342-
DP("Is the device %d (local ID %d) initialized? %d\n", DeviceNo,
343-
Device.RTLDeviceID, Device.IsInit);
344-
345-
// Init the device if not done before
346-
if (!Device.IsInit && Device.initOnce() != OFFLOAD_SUCCESS) {
347-
return createStringError(inconvertibleErrorCode(),
348-
"Failed to init device %d\n", DeviceNo);
349-
}
350-
351-
DP("Device %d is ready to use.\n", DeviceNo);
352-
return Device;
377+
return *(*ExclusiveDevicesAccessor)[DeviceNo];
353378
}

0 commit comments

Comments
 (0)