llvm-project
280 строк · 9.5 Кб
1//===-- PluginManager.cpp - Plugin loading and communication API ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Functionality for handling plugins.
10//
11//===----------------------------------------------------------------------===//
12
13#include "PluginManager.h"
14#include "Shared/Debug.h"
15#include "Shared/Profile.h"
16
17#include "llvm/Support/Error.h"
18#include "llvm/Support/ErrorHandling.h"
19#include <memory>
20
21using namespace llvm;
22using namespace llvm::sys;
23
24PluginManager *PM = nullptr;
25
26// Every plugin exports this method to create an instance of the plugin type.
27#define PLUGIN_TARGET(Name) extern "C" GenericPluginTy *createPlugin_##Name();
28#include "Shared/Targets.def"
29
30void PluginManager::init() {
31TIMESCOPE();
32DP("Loading RTLs...\n");
33
34// Attempt to create an instance of each supported plugin.
35#define PLUGIN_TARGET(Name) \
36do { \
37Plugins.emplace_back( \
38std::unique_ptr<GenericPluginTy>(createPlugin_##Name())); \
39} while (false);
40#include "Shared/Targets.def"
41
42DP("RTLs loaded!\n");
43}
44
45void PluginManager::deinit() {
46TIMESCOPE();
47DP("Unloading RTLs...\n");
48
49for (auto &Plugin : Plugins) {
50if (!Plugin->is_initialized())
51continue;
52
53if (auto Err = Plugin->deinit()) {
54[[maybe_unused]] std::string InfoMsg = toString(std::move(Err));
55DP("Failed to deinit plugin: %s\n", InfoMsg.c_str());
56}
57Plugin.release();
58}
59
60DP("RTLs unloaded!\n");
61}
62
63void PluginManager::initAllPlugins() {
64for (auto &R : plugins()) {
65if (auto Err = R.init()) {
66[[maybe_unused]] std::string InfoMsg = toString(std::move(Err));
67DP("Failed to init plugin: %s\n", InfoMsg.c_str());
68continue;
69}
70DP("Registered plugin %s with %d visible device(s)\n", R.getName(),
71R.number_of_devices());
72}
73}
74
75void PluginManager::registerLib(__tgt_bin_desc *Desc) {
76PM->RTLsMtx.lock();
77
78// Add in all the OpenMP requirements associated with this binary.
79for (__tgt_offload_entry &Entry :
80llvm::make_range(Desc->HostEntriesBegin, Desc->HostEntriesEnd))
81if (Entry.flags == OMP_REGISTER_REQUIRES)
82PM->addRequirements(Entry.data);
83
84// Extract the exectuable image and extra information if availible.
85for (int32_t i = 0; i < Desc->NumDeviceImages; ++i)
86PM->addDeviceImage(*Desc, Desc->DeviceImages[i]);
87
88// Register the images with the RTLs that understand them, if any.
89for (DeviceImageTy &DI : PM->deviceImages()) {
90// Obtain the image and information that was previously extracted.
91__tgt_device_image *Img = &DI.getExecutableImage();
92
93GenericPluginTy *FoundRTL = nullptr;
94
95// Scan the RTLs that have associated images until we find one that supports
96// the current image.
97for (auto &R : PM->plugins()) {
98if (!R.is_plugin_compatible(Img))
99continue;
100
101if (!R.is_initialized()) {
102if (auto Err = R.init()) {
103[[maybe_unused]] std::string InfoMsg = toString(std::move(Err));
104DP("Failed to init plugin: %s\n", InfoMsg.c_str());
105continue;
106}
107DP("Registered plugin %s with %d visible device(s)\n", R.getName(),
108R.number_of_devices());
109}
110
111if (!R.number_of_devices()) {
112DP("Skipping plugin %s with no visible devices\n", R.getName());
113continue;
114}
115
116for (int32_t DeviceId = 0; DeviceId < R.number_of_devices(); ++DeviceId) {
117if (!R.is_device_compatible(DeviceId, Img))
118continue;
119
120DP("Image " DPxMOD " is compatible with RTL %s device %d!\n",
121DPxPTR(Img->ImageStart), R.getName(), DeviceId);
122
123if (!R.is_device_initialized(DeviceId)) {
124// Initialize the device information for the RTL we are about to use.
125auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
126
127int32_t UserId = ExclusiveDevicesAccessor->size();
128
129// Set the device identifier offset in the plugin.
130#ifdef OMPT_SUPPORT
131R.set_device_identifier(UserId, DeviceId);
132#endif
133
134auto Device = std::make_unique<DeviceTy>(&R, UserId, DeviceId);
135if (auto Err = Device->init()) {
136[[maybe_unused]] std::string InfoMsg = toString(std::move(Err));
137DP("Failed to init device %d: %s\n", DeviceId, InfoMsg.c_str());
138continue;
139}
140
141ExclusiveDevicesAccessor->push_back(std::move(Device));
142
143// We need to map between the plugin's device identifier and the one
144// that OpenMP will use.
145PM->DeviceIds[std::make_pair(&R, DeviceId)] = UserId;
146}
147
148// Initialize (if necessary) translation table for this library.
149PM->TrlTblMtx.lock();
150if (!PM->HostEntriesBeginToTransTable.count(Desc->HostEntriesBegin)) {
151PM->HostEntriesBeginRegistrationOrder.push_back(
152Desc->HostEntriesBegin);
153TranslationTable &TT =
154(PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
155TT.HostTable.EntriesBegin = Desc->HostEntriesBegin;
156TT.HostTable.EntriesEnd = Desc->HostEntriesEnd;
157}
158
159// Retrieve translation table for this library.
160TranslationTable &TT =
161(PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
162
163DP("Registering image " DPxMOD " with RTL %s!\n",
164DPxPTR(Img->ImageStart), R.getName());
165
166auto UserId = PM->DeviceIds[std::make_pair(&R, DeviceId)];
167if (TT.TargetsTable.size() < static_cast<size_t>(UserId + 1)) {
168TT.DeviceTables.resize(UserId + 1, {});
169TT.TargetsImages.resize(UserId + 1, nullptr);
170TT.TargetsEntries.resize(UserId + 1, {});
171TT.TargetsTable.resize(UserId + 1, nullptr);
172}
173
174// Register the image for this target type and invalidate the table.
175TT.TargetsImages[UserId] = Img;
176TT.TargetsTable[UserId] = nullptr;
177
178PM->UsedImages.insert(Img);
179FoundRTL = &R;
180
181PM->TrlTblMtx.unlock();
182}
183}
184if (!FoundRTL)
185DP("No RTL found for image " DPxMOD "!\n", DPxPTR(Img->ImageStart));
186}
187PM->RTLsMtx.unlock();
188
189bool UseAutoZeroCopy = Plugins.size() > 0;
190
191auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
192for (const auto &Device : *ExclusiveDevicesAccessor)
193UseAutoZeroCopy &= Device->useAutoZeroCopy();
194
195// Auto Zero-Copy can only be currently triggered when the system is an
196// homogeneous APU architecture without attached discrete GPUs.
197// If all devices suggest to use it, change requirment flags to trigger
198// zero-copy behavior when mapping memory.
199if (UseAutoZeroCopy)
200addRequirements(OMPX_REQ_AUTO_ZERO_COPY);
201
202DP("Done registering entries!\n");
203}
204
205// Temporary forward declaration, old style CTor/DTor handling is going away.
206int target(ident_t *Loc, DeviceTy &Device, void *HostPtr,
207KernelArgsTy &KernelArgs, AsyncInfoTy &AsyncInfo);
208
209void PluginManager::unregisterLib(__tgt_bin_desc *Desc) {
210DP("Unloading target library!\n");
211
212PM->RTLsMtx.lock();
213// Find which RTL understands each image, if any.
214for (DeviceImageTy &DI : PM->deviceImages()) {
215// Obtain the image and information that was previously extracted.
216__tgt_device_image *Img = &DI.getExecutableImage();
217
218GenericPluginTy *FoundRTL = NULL;
219
220// Scan the RTLs that have associated images until we find one that supports
221// the current image. We only need to scan RTLs that are already being used.
222for (auto &R : PM->plugins()) {
223if (R.is_initialized())
224continue;
225
226// Ensure that we do not use any unused images associated with this RTL.
227if (!UsedImages.contains(Img))
228continue;
229
230FoundRTL = &R;
231
232DP("Unregistered image " DPxMOD " from RTL\n", DPxPTR(Img->ImageStart));
233
234break;
235}
236
237// if no RTL was found proceed to unregister the next image
238if (!FoundRTL) {
239DP("No RTLs in use support the image " DPxMOD "!\n",
240DPxPTR(Img->ImageStart));
241}
242}
243PM->RTLsMtx.unlock();
244DP("Done unregistering images!\n");
245
246// Remove entries from PM->HostPtrToTableMap
247PM->TblMapMtx.lock();
248for (__tgt_offload_entry *Cur = Desc->HostEntriesBegin;
249Cur < Desc->HostEntriesEnd; ++Cur) {
250PM->HostPtrToTableMap.erase(Cur->addr);
251}
252
253// Remove translation table for this descriptor.
254auto TransTable =
255PM->HostEntriesBeginToTransTable.find(Desc->HostEntriesBegin);
256if (TransTable != PM->HostEntriesBeginToTransTable.end()) {
257DP("Removing translation table for descriptor " DPxMOD "\n",
258DPxPTR(Desc->HostEntriesBegin));
259PM->HostEntriesBeginToTransTable.erase(TransTable);
260} else {
261DP("Translation table for descriptor " DPxMOD " cannot be found, probably "
262"it has been already removed.\n",
263DPxPTR(Desc->HostEntriesBegin));
264}
265
266PM->TblMapMtx.unlock();
267
268DP("Done unregistering library!\n");
269}
270
271Expected<DeviceTy &> PluginManager::getDevice(uint32_t DeviceNo) {
272auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
273if (DeviceNo >= ExclusiveDevicesAccessor->size())
274return createStringError(
275inconvertibleErrorCode(),
276"Device number '%i' out of range, only %i devices available", DeviceNo,
277ExclusiveDevicesAccessor->size());
278
279return *(*ExclusiveDevicesAccessor)[DeviceNo];
280}
281