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 "OffloadPolicy.h" |
15 | #include "Shared/Debug.h" |
16 | #include "Shared/Profile.h" |
17 | #include "device.h" |
18 | |
19 | #include "llvm/Support/Error.h" |
20 | #include "llvm/Support/ErrorHandling.h" |
21 | #include <memory> |
22 | |
23 | using namespace llvm; |
24 | using namespace llvm::sys; |
25 | |
26 | PluginManager *PM = nullptr; |
27 | |
28 | // Every plugin exports this method to create an instance of the plugin type. |
29 | #define PLUGIN_TARGET(Name) extern "C" GenericPluginTy *createPlugin_##Name(); |
30 | #include "Shared/Targets.def" |
31 | |
32 | void PluginManager::init() { |
33 | TIMESCOPE(); |
34 | if (OffloadPolicy::isOffloadDisabled()) { |
35 | DP("Offload is disabled. Skipping plugin initialization\n" ); |
36 | return; |
37 | } |
38 | |
39 | DP("Loading RTLs...\n" ); |
40 | |
41 | // Attempt to create an instance of each supported plugin. |
42 | #define PLUGIN_TARGET(Name) \ |
43 | do { \ |
44 | Plugins.emplace_back( \ |
45 | std::unique_ptr<GenericPluginTy>(createPlugin_##Name())); \ |
46 | } while (false); |
47 | #include "Shared/Targets.def" |
48 | |
49 | DP("RTLs loaded!\n" ); |
50 | } |
51 | |
52 | void PluginManager::deinit() { |
53 | TIMESCOPE(); |
54 | DP("Unloading RTLs...\n" ); |
55 | |
56 | for (auto &Plugin : Plugins) { |
57 | if (!Plugin->is_initialized()) |
58 | continue; |
59 | |
60 | if (auto Err = Plugin->deinit()) { |
61 | [[maybe_unused]] std::string InfoMsg = toString(std::move(Err)); |
62 | DP("Failed to deinit plugin: %s\n" , InfoMsg.c_str()); |
63 | } |
64 | Plugin.release(); |
65 | } |
66 | |
67 | DP("RTLs unloaded!\n" ); |
68 | } |
69 | |
70 | bool PluginManager::initializePlugin(GenericPluginTy &Plugin) { |
71 | if (Plugin.is_initialized()) |
72 | return true; |
73 | |
74 | if (auto Err = Plugin.init()) { |
75 | [[maybe_unused]] std::string InfoMsg = toString(std::move(Err)); |
76 | DP("Failed to init plugin: %s\n" , InfoMsg.c_str()); |
77 | return false; |
78 | } |
79 | |
80 | DP("Registered plugin %s with %d visible device(s)\n" , Plugin.getName(), |
81 | Plugin.number_of_devices()); |
82 | return true; |
83 | } |
84 | |
85 | bool PluginManager::initializeDevice(GenericPluginTy &Plugin, |
86 | int32_t DeviceId) { |
87 | if (Plugin.is_device_initialized(DeviceId)) { |
88 | auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor(); |
89 | (*ExclusiveDevicesAccessor)[PM->DeviceIds[std::make_pair(&Plugin, |
90 | DeviceId)]] |
91 | ->setHasPendingImages(true); |
92 | return true; |
93 | } |
94 | |
95 | // Initialize the device information for the RTL we are about to use. |
96 | auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor(); |
97 | |
98 | int32_t UserId = ExclusiveDevicesAccessor->size(); |
99 | |
100 | // Set the device identifier offset in the plugin. |
101 | #ifdef OMPT_SUPPORT |
102 | Plugin.set_device_identifier(UserId, DeviceId); |
103 | #endif |
104 | |
105 | auto Device = std::make_unique<DeviceTy>(&Plugin, UserId, DeviceId); |
106 | if (auto Err = Device->init()) { |
107 | [[maybe_unused]] std::string InfoMsg = toString(std::move(Err)); |
108 | DP("Failed to init device %d: %s\n" , DeviceId, InfoMsg.c_str()); |
109 | return false; |
110 | } |
111 | |
112 | ExclusiveDevicesAccessor->push_back(std::move(Device)); |
113 | |
114 | // We need to map between the plugin's device identifier and the one |
115 | // that OpenMP will use. |
116 | PM->DeviceIds[std::make_pair(&Plugin, DeviceId)] = UserId; |
117 | |
118 | return true; |
119 | } |
120 | |
121 | void PluginManager::initializeAllDevices() { |
122 | for (auto &Plugin : plugins()) { |
123 | if (!initializePlugin(Plugin)) |
124 | continue; |
125 | |
126 | for (int32_t DeviceId = 0; DeviceId < Plugin.number_of_devices(); |
127 | ++DeviceId) { |
128 | initializeDevice(Plugin, DeviceId); |
129 | } |
130 | } |
131 | } |
132 | |
133 | // Returns a pointer to the binary descriptor, upgrading from a legacy format if |
134 | // necessary. |
135 | __tgt_bin_desc *PluginManager::upgradeLegacyEntries(__tgt_bin_desc *Desc) { |
136 | struct LegacyEntryTy { |
137 | void *Address; |
138 | char *SymbolName; |
139 | size_t Size; |
140 | int32_t Flags; |
141 | int32_t Data; |
142 | }; |
143 | |
144 | if (UpgradedDescriptors.contains(Desc)) |
145 | return &UpgradedDescriptors[Desc]; |
146 | |
147 | if (Desc->HostEntriesBegin == Desc->HostEntriesEnd || |
148 | Desc->HostEntriesBegin->Reserved == 0) |
149 | return Desc; |
150 | |
151 | // The new format mandates that each entry starts with eight bytes of zeroes. |
152 | // This allows us to detect the old format as this is a null pointer. |
153 | llvm::SmallVector<llvm::offloading::EntryTy, 0> &NewEntries = |
154 | LegacyEntries.emplace_back(); |
155 | for (LegacyEntryTy &Entry : llvm::make_range( |
156 | reinterpret_cast<LegacyEntryTy *>(Desc->HostEntriesBegin), |
157 | reinterpret_cast<LegacyEntryTy *>(Desc->HostEntriesEnd))) { |
158 | llvm::offloading::EntryTy &NewEntry = NewEntries.emplace_back(); |
159 | |
160 | NewEntry.Address = Entry.Address; |
161 | NewEntry.Flags = Entry.Flags; |
162 | NewEntry.Data = Entry.Data; |
163 | NewEntry.Size = Entry.Size; |
164 | NewEntry.SymbolName = Entry.SymbolName; |
165 | NewEntry.Kind = object::OffloadKind::OFK_OpenMP; |
166 | } |
167 | |
168 | // Create a new image struct so we can update the entries list. |
169 | llvm::SmallVector<__tgt_device_image, 0> &NewImages = |
170 | LegacyImages.emplace_back(); |
171 | for (int32_t Image = 0; Image < Desc->NumDeviceImages; ++Image) |
172 | NewImages.emplace_back( |
173 | __tgt_device_image{Desc->DeviceImages[Image].ImageStart, |
174 | Desc->DeviceImages[Image].ImageEnd, |
175 | NewEntries.begin(), NewEntries.end()}); |
176 | |
177 | // Create the new binary descriptor containing the newly created memory. |
178 | __tgt_bin_desc &NewDesc = UpgradedDescriptors[Desc]; |
179 | NewDesc.DeviceImages = NewImages.begin(); |
180 | NewDesc.NumDeviceImages = Desc->NumDeviceImages; |
181 | NewDesc.HostEntriesBegin = NewEntries.begin(); |
182 | NewDesc.HostEntriesEnd = NewEntries.end(); |
183 | |
184 | return &NewDesc; |
185 | } |
186 | |
187 | void PluginManager::registerLib(__tgt_bin_desc *Desc) { |
188 | PM->RTLsMtx.lock(); |
189 | |
190 | // Upgrade the entries from the legacy implementation if necessary. |
191 | Desc = upgradeLegacyEntries(Desc); |
192 | |
193 | // Add in all the OpenMP requirements associated with this binary. |
194 | for (llvm::offloading::EntryTy &Entry : |
195 | llvm::make_range(Desc->HostEntriesBegin, Desc->HostEntriesEnd)) |
196 | if (Entry.Kind == object::OffloadKind::OFK_OpenMP && |
197 | Entry.Flags == OMP_REGISTER_REQUIRES) |
198 | PM->addRequirements(Entry.Data); |
199 | |
200 | // Extract the executable image and extra information if available. |
201 | for (int32_t i = 0; i < Desc->NumDeviceImages; ++i) |
202 | PM->addDeviceImage(*Desc, Desc->DeviceImages[i]); |
203 | |
204 | // Register the images with the RTLs that understand them, if any. |
205 | llvm::DenseMap<GenericPluginTy *, llvm::DenseSet<int32_t>> UsedDevices; |
206 | for (int32_t i = 0; i < Desc->NumDeviceImages; ++i) { |
207 | // Obtain the image and information that was previously extracted. |
208 | __tgt_device_image *Img = &Desc->DeviceImages[i]; |
209 | |
210 | GenericPluginTy *FoundRTL = nullptr; |
211 | |
212 | // Scan the RTLs that have associated images until we find one that supports |
213 | // the current image. |
214 | for (auto &R : plugins()) { |
215 | if (!R.is_plugin_compatible(Img)) |
216 | continue; |
217 | |
218 | if (!initializePlugin(R)) |
219 | continue; |
220 | |
221 | if (!R.number_of_devices()) { |
222 | DP("Skipping plugin %s with no visible devices\n" , R.getName()); |
223 | continue; |
224 | } |
225 | |
226 | for (int32_t DeviceId = 0; DeviceId < R.number_of_devices(); ++DeviceId) { |
227 | // We only want a single matching image to be registered for each binary |
228 | // descriptor. This prevents multiple of the same image from being |
229 | // registered for the same device in the case that they are mutually |
230 | // compatible, such as sm_80 and sm_89. |
231 | if (UsedDevices[&R].contains(DeviceId)) { |
232 | DP("Image " DPxMOD |
233 | " is a duplicate, not loaded on RTL %s device %d!\n" , |
234 | DPxPTR(Img->ImageStart), R.getName(), DeviceId); |
235 | continue; |
236 | } |
237 | |
238 | if (!R.is_device_compatible(DeviceId, Img)) |
239 | continue; |
240 | |
241 | DP("Image " DPxMOD " is compatible with RTL %s device %d!\n" , |
242 | DPxPTR(Img->ImageStart), R.getName(), DeviceId); |
243 | |
244 | if (!initializeDevice(R, DeviceId)) |
245 | continue; |
246 | |
247 | // Initialize (if necessary) translation table for this library. |
248 | PM->TrlTblMtx.lock(); |
249 | if (!PM->HostEntriesBeginToTransTable.count(Desc->HostEntriesBegin)) { |
250 | PM->HostEntriesBeginRegistrationOrder.push_back( |
251 | Desc->HostEntriesBegin); |
252 | TranslationTable &TT = |
253 | (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin]; |
254 | TT.HostTable.EntriesBegin = Desc->HostEntriesBegin; |
255 | TT.HostTable.EntriesEnd = Desc->HostEntriesEnd; |
256 | } |
257 | |
258 | // Retrieve translation table for this library. |
259 | TranslationTable &TT = |
260 | (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin]; |
261 | |
262 | DP("Registering image " DPxMOD " with RTL %s!\n" , |
263 | DPxPTR(Img->ImageStart), R.getName()); |
264 | |
265 | auto UserId = PM->DeviceIds[std::make_pair(&R, DeviceId)]; |
266 | if (TT.TargetsTable.size() < static_cast<size_t>(UserId + 1)) { |
267 | TT.DeviceTables.resize(UserId + 1, {}); |
268 | TT.TargetsImages.resize(UserId + 1, nullptr); |
269 | TT.TargetsEntries.resize(UserId + 1, {}); |
270 | TT.TargetsTable.resize(UserId + 1, nullptr); |
271 | } |
272 | |
273 | // Register the image for this target type and invalidate the table. |
274 | TT.TargetsImages[UserId] = Img; |
275 | TT.TargetsTable[UserId] = nullptr; |
276 | |
277 | UsedDevices[&R].insert(DeviceId); |
278 | PM->UsedImages.insert(Img); |
279 | FoundRTL = &R; |
280 | |
281 | PM->TrlTblMtx.unlock(); |
282 | } |
283 | } |
284 | if (!FoundRTL) |
285 | DP("No RTL found for image " DPxMOD "!\n" , DPxPTR(Img->ImageStart)); |
286 | } |
287 | PM->RTLsMtx.unlock(); |
288 | |
289 | bool UseAutoZeroCopy = false; |
290 | |
291 | auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor(); |
292 | // APUs are homogeneous set of GPUs. Check the first device for |
293 | // configuring Auto Zero-Copy. |
294 | if (ExclusiveDevicesAccessor->size() > 0) { |
295 | auto &Device = *(*ExclusiveDevicesAccessor)[0]; |
296 | UseAutoZeroCopy = Device.useAutoZeroCopy(); |
297 | } |
298 | |
299 | if (UseAutoZeroCopy) |
300 | addRequirements(OMPX_REQ_AUTO_ZERO_COPY); |
301 | |
302 | DP("Done registering entries!\n" ); |
303 | } |
304 | |
305 | // Temporary forward declaration, old style CTor/DTor handling is going away. |
306 | int target(ident_t *Loc, DeviceTy &Device, void *HostPtr, |
307 | KernelArgsTy &KernelArgs, AsyncInfoTy &AsyncInfo); |
308 | |
309 | void PluginManager::unregisterLib(__tgt_bin_desc *Desc) { |
310 | DP("Unloading target library!\n" ); |
311 | |
312 | Desc = upgradeLegacyEntries(Desc); |
313 | |
314 | PM->RTLsMtx.lock(); |
315 | // Find which RTL understands each image, if any. |
316 | for (DeviceImageTy &DI : PM->deviceImages()) { |
317 | // Obtain the image and information that was previously extracted. |
318 | __tgt_device_image *Img = &DI.getExecutableImage(); |
319 | |
320 | GenericPluginTy *FoundRTL = NULL; |
321 | |
322 | // Scan the RTLs that have associated images until we find one that supports |
323 | // the current image. We only need to scan RTLs that are already being used. |
324 | for (auto &R : plugins()) { |
325 | if (R.is_initialized()) |
326 | continue; |
327 | |
328 | // Ensure that we do not use any unused images associated with this RTL. |
329 | if (!UsedImages.contains(Img)) |
330 | continue; |
331 | |
332 | FoundRTL = &R; |
333 | |
334 | DP("Unregistered image " DPxMOD " from RTL\n" , DPxPTR(Img->ImageStart)); |
335 | |
336 | break; |
337 | } |
338 | |
339 | // if no RTL was found proceed to unregister the next image |
340 | if (!FoundRTL) { |
341 | DP("No RTLs in use support the image " DPxMOD "!\n" , |
342 | DPxPTR(Img->ImageStart)); |
343 | } |
344 | } |
345 | PM->RTLsMtx.unlock(); |
346 | DP("Done unregistering images!\n" ); |
347 | |
348 | // Remove entries from PM->HostPtrToTableMap |
349 | PM->TblMapMtx.lock(); |
350 | for (llvm::offloading::EntryTy *Cur = Desc->HostEntriesBegin; |
351 | Cur < Desc->HostEntriesEnd; ++Cur) { |
352 | if (Cur->Kind == object::OffloadKind::OFK_OpenMP) |
353 | PM->HostPtrToTableMap.erase(Cur->Address); |
354 | } |
355 | |
356 | // Remove translation table for this descriptor. |
357 | auto TransTable = |
358 | PM->HostEntriesBeginToTransTable.find(Desc->HostEntriesBegin); |
359 | if (TransTable != PM->HostEntriesBeginToTransTable.end()) { |
360 | DP("Removing translation table for descriptor " DPxMOD "\n" , |
361 | DPxPTR(Desc->HostEntriesBegin)); |
362 | PM->HostEntriesBeginToTransTable.erase(TransTable); |
363 | } else { |
364 | DP("Translation table for descriptor " DPxMOD " cannot be found, probably " |
365 | "it has been already removed.\n" , |
366 | DPxPTR(Desc->HostEntriesBegin)); |
367 | } |
368 | |
369 | PM->TblMapMtx.unlock(); |
370 | |
371 | DP("Done unregistering library!\n" ); |
372 | } |
373 | |
374 | /// Map global data and execute pending ctors |
375 | static int loadImagesOntoDevice(DeviceTy &Device) { |
376 | /* |
377 | * Map global data |
378 | */ |
379 | int32_t DeviceId = Device.DeviceID; |
380 | int Rc = OFFLOAD_SUCCESS; |
381 | { |
382 | std::lock_guard<decltype(PM->TrlTblMtx)> LG(PM->TrlTblMtx); |
383 | for (auto *HostEntriesBegin : PM->HostEntriesBeginRegistrationOrder) { |
384 | TranslationTable *TransTable = |
385 | &PM->HostEntriesBeginToTransTable[HostEntriesBegin]; |
386 | DP("Trans table %p : %p\n" , TransTable->HostTable.EntriesBegin, |
387 | TransTable->HostTable.EntriesEnd); |
388 | if (TransTable->HostTable.EntriesBegin == |
389 | TransTable->HostTable.EntriesEnd) { |
390 | // No host entry so no need to proceed |
391 | continue; |
392 | } |
393 | |
394 | if (TransTable->TargetsTable[DeviceId] != 0) { |
395 | // Library entries have already been processed |
396 | continue; |
397 | } |
398 | |
399 | // 1) get image. |
400 | assert(TransTable->TargetsImages.size() > (size_t)DeviceId && |
401 | "Not expecting a device ID outside the table's bounds!" ); |
402 | __tgt_device_image *Img = TransTable->TargetsImages[DeviceId]; |
403 | if (!Img) { |
404 | REPORT("No image loaded for device id %d.\n" , DeviceId); |
405 | Rc = OFFLOAD_FAIL; |
406 | break; |
407 | } |
408 | |
409 | // 2) Load the image onto the given device. |
410 | auto BinaryOrErr = Device.loadBinary(Img); |
411 | if (llvm::Error Err = BinaryOrErr.takeError()) { |
412 | REPORT("Failed to load image %s\n" , |
413 | llvm::toString(std::move(Err)).c_str()); |
414 | Rc = OFFLOAD_FAIL; |
415 | break; |
416 | } |
417 | |
418 | // 3) Create the translation table. |
419 | llvm::SmallVector<llvm::offloading::EntryTy> &DeviceEntries = |
420 | TransTable->TargetsEntries[DeviceId]; |
421 | for (llvm::offloading::EntryTy &Entry : |
422 | llvm::make_range(Img->EntriesBegin, Img->EntriesEnd)) { |
423 | if (Entry.Kind != object::OffloadKind::OFK_OpenMP) |
424 | continue; |
425 | |
426 | __tgt_device_binary &Binary = *BinaryOrErr; |
427 | |
428 | llvm::offloading::EntryTy DeviceEntry = Entry; |
429 | if (Entry.Size) { |
430 | if (Device.RTL->get_global(Binary, Entry.Size, Entry.SymbolName, |
431 | &DeviceEntry.Address) != OFFLOAD_SUCCESS) |
432 | REPORT("Failed to load symbol %s\n" , Entry.SymbolName); |
433 | |
434 | // If unified memory is active, the corresponding global is a device |
435 | // reference to the host global. We need to initialize the pointer on |
436 | // the device to point to the memory on the host. |
437 | if ((PM->getRequirements() & OMP_REQ_UNIFIED_SHARED_MEMORY) || |
438 | (PM->getRequirements() & OMPX_REQ_AUTO_ZERO_COPY)) { |
439 | if (Device.RTL->data_submit(DeviceId, DeviceEntry.Address, |
440 | Entry.Address, |
441 | Entry.Size) != OFFLOAD_SUCCESS) |
442 | REPORT("Failed to write symbol for USM %s\n" , Entry.SymbolName); |
443 | } |
444 | } else if (Entry.Address) { |
445 | if (Device.RTL->get_function(Binary, Entry.SymbolName, |
446 | &DeviceEntry.Address) != OFFLOAD_SUCCESS) |
447 | REPORT("Failed to load kernel %s\n" , Entry.SymbolName); |
448 | } |
449 | DP("Entry point " DPxMOD " maps to%s %s (" DPxMOD ")\n" , |
450 | DPxPTR(Entry.Address), (Entry.Size) ? " global" : "" , |
451 | Entry.SymbolName, DPxPTR(DeviceEntry.Address)); |
452 | |
453 | DeviceEntries.emplace_back(DeviceEntry); |
454 | } |
455 | |
456 | // Set the storage for the table and get a pointer to it. |
457 | __tgt_target_table DeviceTable{&DeviceEntries[0], |
458 | &DeviceEntries[0] + DeviceEntries.size()}; |
459 | TransTable->DeviceTables[DeviceId] = DeviceTable; |
460 | __tgt_target_table *TargetTable = TransTable->TargetsTable[DeviceId] = |
461 | &TransTable->DeviceTables[DeviceId]; |
462 | |
463 | MappingInfoTy::HDTTMapAccessorTy HDTTMap = |
464 | Device.getMappingInfo().HostDataToTargetMap.getExclusiveAccessor(); |
465 | |
466 | __tgt_target_table *HostTable = &TransTable->HostTable; |
467 | for (llvm::offloading::EntryTy * |
468 | CurrDeviceEntry = TargetTable->EntriesBegin, |
469 | *CurrHostEntry = HostTable->EntriesBegin, |
470 | *EntryDeviceEnd = TargetTable->EntriesEnd; |
471 | CurrDeviceEntry != EntryDeviceEnd; |
472 | CurrDeviceEntry++, CurrHostEntry++) { |
473 | if (CurrDeviceEntry->Size == 0 || |
474 | CurrDeviceEntry->Kind != object::OffloadKind::OFK_OpenMP) |
475 | continue; |
476 | |
477 | assert(CurrDeviceEntry->Size == CurrHostEntry->Size && |
478 | "data size mismatch" ); |
479 | |
480 | // Fortran may use multiple weak declarations for the same symbol, |
481 | // therefore we must allow for multiple weak symbols to be loaded from |
482 | // the fat binary. Treat these mappings as any other "regular" |
483 | // mapping. Add entry to map. |
484 | if (Device.getMappingInfo().getTgtPtrBegin( |
485 | HDTTMap, CurrHostEntry->Address, CurrHostEntry->Size)) |
486 | continue; |
487 | |
488 | void *CurrDeviceEntryAddr = CurrDeviceEntry->Address; |
489 | |
490 | // For indirect mapping, follow the indirection and map the actual |
491 | // target. |
492 | if (CurrDeviceEntry->Flags & OMP_DECLARE_TARGET_INDIRECT) { |
493 | AsyncInfoTy AsyncInfo(Device); |
494 | void *DevPtr; |
495 | Device.retrieveData(&DevPtr, CurrDeviceEntryAddr, sizeof(void *), |
496 | AsyncInfo, /*Entry=*/nullptr, &HDTTMap); |
497 | if (AsyncInfo.synchronize() != OFFLOAD_SUCCESS) |
498 | return OFFLOAD_FAIL; |
499 | CurrDeviceEntryAddr = DevPtr; |
500 | } |
501 | |
502 | DP("Add mapping from host " DPxMOD " to device " DPxMOD " with size %zu" |
503 | ", name \"%s\"\n" , |
504 | DPxPTR(CurrHostEntry->Address), DPxPTR(CurrDeviceEntry->Address), |
505 | CurrDeviceEntry->Size, CurrDeviceEntry->SymbolName); |
506 | HDTTMap->emplace(new HostDataToTargetTy( |
507 | (uintptr_t)CurrHostEntry->Address /*HstPtrBase*/, |
508 | (uintptr_t)CurrHostEntry->Address /*HstPtrBegin*/, |
509 | (uintptr_t)CurrHostEntry->Address + |
510 | CurrHostEntry->Size /*HstPtrEnd*/, |
511 | (uintptr_t)CurrDeviceEntryAddr /*TgtAllocBegin*/, |
512 | (uintptr_t)CurrDeviceEntryAddr /*TgtPtrBegin*/, |
513 | false /*UseHoldRefCount*/, CurrHostEntry->SymbolName, |
514 | true /*IsRefCountINF*/)); |
515 | |
516 | // Notify about the new mapping. |
517 | if (Device.notifyDataMapped(CurrHostEntry->Address, |
518 | CurrHostEntry->Size)) |
519 | return OFFLOAD_FAIL; |
520 | } |
521 | } |
522 | Device.setHasPendingImages(false); |
523 | } |
524 | |
525 | if (Rc != OFFLOAD_SUCCESS) |
526 | return Rc; |
527 | |
528 | static Int32Envar DumpOffloadEntries = |
529 | Int32Envar("OMPTARGET_DUMP_OFFLOAD_ENTRIES" , -1); |
530 | if (DumpOffloadEntries.get() == DeviceId) |
531 | Device.dumpOffloadEntries(); |
532 | |
533 | return OFFLOAD_SUCCESS; |
534 | } |
535 | |
536 | Expected<DeviceTy &> PluginManager::getDevice(uint32_t DeviceNo) { |
537 | DeviceTy *DevicePtr; |
538 | { |
539 | auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor(); |
540 | if (DeviceNo >= ExclusiveDevicesAccessor->size()) |
541 | return error::createOffloadError( |
542 | error::ErrorCode::INVALID_VALUE, |
543 | "device number '%i' out of range, only %i devices available" , |
544 | DeviceNo, ExclusiveDevicesAccessor->size()); |
545 | |
546 | DevicePtr = &*(*ExclusiveDevicesAccessor)[DeviceNo]; |
547 | } |
548 | |
549 | // Check whether global data has been mapped for this device |
550 | if (DevicePtr->hasPendingImages()) |
551 | if (loadImagesOntoDevice(*DevicePtr) != OFFLOAD_SUCCESS) |
552 | return error::createOffloadError(error::ErrorCode::BACKEND_FAILURE, |
553 | "failed to load images on device '%i'" , |
554 | DeviceNo); |
555 | return *DevicePtr; |
556 | } |
557 | |