1 //===----------- rtl.cpp - Target independent OpenMP target RTL -----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.txt for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Functionality for handling RTL plugins.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "device.h"
15 #include "private.h"
16 #include "rtl.h"
17 
18 #include <cassert>
19 #include <cstdlib>
20 #include <cstring>
21 #include <dlfcn.h>
22 #include <mutex>
23 #include <string>
24 
25 // List of all plugins that can support offloading.
26 static const char *RTLNames[] = {
27     /* PowerPC target */ "libomptarget.rtl.ppc64.so",
28     /* x86_64 target  */ "libomptarget.rtl.x86_64.so",
29     /* CUDA target    */ "libomptarget.rtl.cuda.so",
30     /* AArch64 target */ "libomptarget.rtl.aarch64.so"};
31 
32 RTLsTy RTLs;
33 std::mutex RTLsMtx;
34 
35 HostEntriesBeginToTransTableTy HostEntriesBeginToTransTable;
36 std::mutex TrlTblMtx;
37 
38 HostPtrToTableMapTy HostPtrToTableMap;
39 std::mutex TblMapMtx;
40 
41 void RTLsTy::LoadRTLs() {
42 #ifdef OMPTARGET_DEBUG
43   if (char *envStr = getenv("LIBOMPTARGET_DEBUG")) {
44     DebugLevel = std::stoi(envStr);
45   }
46 #endif // OMPTARGET_DEBUG
47 
48   // Parse environment variable OMP_TARGET_OFFLOAD (if set)
49   char *envStr = getenv("OMP_TARGET_OFFLOAD");
50   if (envStr && !strcmp(envStr, "DISABLED")) {
51     DP("Target offloading disabled by environment\n");
52     return;
53   }
54 
55   DP("Loading RTLs...\n");
56 
57   // Attempt to open all the plugins and, if they exist, check if the interface
58   // is correct and if they are supporting any devices.
59   for (auto *Name : RTLNames) {
60     DP("Loading library '%s'...\n", Name);
61     void *dynlib_handle = dlopen(Name, RTLD_NOW);
62 
63     if (!dynlib_handle) {
64       // Library does not exist or cannot be found.
65       DP("Unable to load library '%s': %s!\n", Name, dlerror());
66       continue;
67     }
68 
69     DP("Successfully loaded library '%s'!\n", Name);
70 
71     // Retrieve the RTL information from the runtime library.
72     RTLInfoTy R;
73 
74     R.LibraryHandler = dynlib_handle;
75     R.isUsed = false;
76 
77 #ifdef OMPTARGET_DEBUG
78     R.RTLName = Name;
79 #endif
80 
81     if (!(*((void**) &R.is_valid_binary) = dlsym(
82               dynlib_handle, "__tgt_rtl_is_valid_binary")))
83       continue;
84     if (!(*((void**) &R.number_of_devices) = dlsym(
85               dynlib_handle, "__tgt_rtl_number_of_devices")))
86       continue;
87     if (!(*((void**) &R.init_device) = dlsym(
88               dynlib_handle, "__tgt_rtl_init_device")))
89       continue;
90     if (!(*((void**) &R.load_binary) = dlsym(
91               dynlib_handle, "__tgt_rtl_load_binary")))
92       continue;
93     if (!(*((void**) &R.data_alloc) = dlsym(
94               dynlib_handle, "__tgt_rtl_data_alloc")))
95       continue;
96     if (!(*((void**) &R.data_submit) = dlsym(
97               dynlib_handle, "__tgt_rtl_data_submit")))
98       continue;
99     if (!(*((void**) &R.data_retrieve) = dlsym(
100               dynlib_handle, "__tgt_rtl_data_retrieve")))
101       continue;
102     if (!(*((void**) &R.data_delete) = dlsym(
103               dynlib_handle, "__tgt_rtl_data_delete")))
104       continue;
105     if (!(*((void**) &R.run_region) = dlsym(
106               dynlib_handle, "__tgt_rtl_run_target_region")))
107       continue;
108     if (!(*((void**) &R.run_team_region) = dlsym(
109               dynlib_handle, "__tgt_rtl_run_target_team_region")))
110       continue;
111 
112     // No devices are supported by this RTL?
113     if (!(R.NumberOfDevices = R.number_of_devices())) {
114       DP("No devices supported in this RTL\n");
115       continue;
116     }
117 
118     DP("Registering RTL %s supporting %d devices!\n",
119         R.RTLName.c_str(), R.NumberOfDevices);
120 
121     // The RTL is valid! Will save the information in the RTLs list.
122     AllRTLs.push_back(R);
123   }
124 
125   DP("RTLs loaded!\n");
126 
127   return;
128 }
129 
130 ////////////////////////////////////////////////////////////////////////////////
131 // Functionality for registering libs
132 
133 static void RegisterImageIntoTranslationTable(TranslationTable &TT,
134     RTLInfoTy &RTL, __tgt_device_image *image) {
135 
136   // same size, as when we increase one, we also increase the other.
137   assert(TT.TargetsTable.size() == TT.TargetsImages.size() &&
138          "We should have as many images as we have tables!");
139 
140   // Resize the Targets Table and Images to accommodate the new targets if
141   // required
142   unsigned TargetsTableMinimumSize = RTL.Idx + RTL.NumberOfDevices;
143 
144   if (TT.TargetsTable.size() < TargetsTableMinimumSize) {
145     TT.TargetsImages.resize(TargetsTableMinimumSize, 0);
146     TT.TargetsTable.resize(TargetsTableMinimumSize, 0);
147   }
148 
149   // Register the image in all devices for this target type.
150   for (int32_t i = 0; i < RTL.NumberOfDevices; ++i) {
151     // If we are changing the image we are also invalidating the target table.
152     if (TT.TargetsImages[RTL.Idx + i] != image) {
153       TT.TargetsImages[RTL.Idx + i] = image;
154       TT.TargetsTable[RTL.Idx + i] = 0; // lazy initialization of target table.
155     }
156   }
157 }
158 
159 ////////////////////////////////////////////////////////////////////////////////
160 // Functionality for registering Ctors/Dtors
161 
162 static void RegisterGlobalCtorsDtorsForImage(__tgt_bin_desc *desc,
163     __tgt_device_image *img, RTLInfoTy *RTL) {
164 
165   for (int32_t i = 0; i < RTL->NumberOfDevices; ++i) {
166     DeviceTy &Device = Devices[RTL->Idx + i];
167     Device.PendingGlobalsMtx.lock();
168     Device.HasPendingGlobals = true;
169     for (__tgt_offload_entry *entry = img->EntriesBegin;
170         entry != img->EntriesEnd; ++entry) {
171       if (entry->flags & OMP_DECLARE_TARGET_CTOR) {
172         DP("Adding ctor " DPxMOD " to the pending list.\n",
173             DPxPTR(entry->addr));
174         Device.PendingCtorsDtors[desc].PendingCtors.push_back(entry->addr);
175       } else if (entry->flags & OMP_DECLARE_TARGET_DTOR) {
176         // Dtors are pushed in reverse order so they are executed from end
177         // to beginning when unregistering the library!
178         DP("Adding dtor " DPxMOD " to the pending list.\n",
179             DPxPTR(entry->addr));
180         Device.PendingCtorsDtors[desc].PendingDtors.push_front(entry->addr);
181       }
182 
183       if (entry->flags & OMP_DECLARE_TARGET_LINK) {
184         DP("The \"link\" attribute is not yet supported!\n");
185       }
186     }
187     Device.PendingGlobalsMtx.unlock();
188   }
189 }
190 
191 void RTLsTy::RegisterLib(__tgt_bin_desc *desc) {
192   // Attempt to load all plugins available in the system.
193   std::call_once(initFlag, &RTLsTy::LoadRTLs, this);
194 
195   RTLsMtx.lock();
196   // Register the images with the RTLs that understand them, if any.
197   for (int32_t i = 0; i < desc->NumDeviceImages; ++i) {
198     // Obtain the image.
199     __tgt_device_image *img = &desc->DeviceImages[i];
200 
201     RTLInfoTy *FoundRTL = NULL;
202 
203     // Scan the RTLs that have associated images until we find one that supports
204     // the current image.
205     for (auto &R : RTLs.AllRTLs) {
206       if (!R.is_valid_binary(img)) {
207         DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
208             DPxPTR(img->ImageStart), R.RTLName.c_str());
209         continue;
210       }
211 
212       DP("Image " DPxMOD " is compatible with RTL %s!\n",
213           DPxPTR(img->ImageStart), R.RTLName.c_str());
214 
215       // If this RTL is not already in use, initialize it.
216       if (!R.isUsed) {
217         // Initialize the device information for the RTL we are about to use.
218         DeviceTy device(&R);
219 
220         size_t start = Devices.size();
221         Devices.resize(start + R.NumberOfDevices, device);
222         for (int32_t device_id = 0; device_id < R.NumberOfDevices;
223             device_id++) {
224           // global device ID
225           Devices[start + device_id].DeviceID = start + device_id;
226           // RTL local device ID
227           Devices[start + device_id].RTLDeviceID = device_id;
228 
229           // Save pointer to device in RTL in case we want to unregister the RTL
230           R.Devices.push_back(&Devices[start + device_id]);
231         }
232 
233         // Initialize the index of this RTL and save it in the used RTLs.
234         R.Idx = (RTLs.UsedRTLs.empty())
235                     ? 0
236                     : RTLs.UsedRTLs.back()->Idx +
237                           RTLs.UsedRTLs.back()->NumberOfDevices;
238         assert((size_t) R.Idx == start &&
239             "RTL index should equal the number of devices used so far.");
240         R.isUsed = true;
241         RTLs.UsedRTLs.push_back(&R);
242 
243         DP("RTL " DPxMOD " has index %d!\n", DPxPTR(R.LibraryHandler), R.Idx);
244       }
245 
246       // Initialize (if necessary) translation table for this library.
247       TrlTblMtx.lock();
248       if(!HostEntriesBeginToTransTable.count(desc->HostEntriesBegin)){
249         TranslationTable &tt =
250             HostEntriesBeginToTransTable[desc->HostEntriesBegin];
251         tt.HostTable.EntriesBegin = desc->HostEntriesBegin;
252         tt.HostTable.EntriesEnd = desc->HostEntriesEnd;
253       }
254 
255       // Retrieve translation table for this library.
256       TranslationTable &TransTable =
257           HostEntriesBeginToTransTable[desc->HostEntriesBegin];
258 
259       DP("Registering image " DPxMOD " with RTL %s!\n",
260           DPxPTR(img->ImageStart), R.RTLName.c_str());
261       RegisterImageIntoTranslationTable(TransTable, R, img);
262       TrlTblMtx.unlock();
263       FoundRTL = &R;
264 
265       // Load ctors/dtors for static objects
266       RegisterGlobalCtorsDtorsForImage(desc, img, FoundRTL);
267 
268       // if an RTL was found we are done - proceed to register the next image
269       break;
270     }
271 
272     if (!FoundRTL) {
273       DP("No RTL found for image " DPxMOD "!\n", DPxPTR(img->ImageStart));
274     }
275   }
276   RTLsMtx.unlock();
277 
278 
279   DP("Done registering entries!\n");
280 }
281 
282 void RTLsTy::UnregisterLib(__tgt_bin_desc *desc) {
283   DP("Unloading target library!\n");
284 
285   RTLsMtx.lock();
286   // Find which RTL understands each image, if any.
287   for (int32_t i = 0; i < desc->NumDeviceImages; ++i) {
288     // Obtain the image.
289     __tgt_device_image *img = &desc->DeviceImages[i];
290 
291     RTLInfoTy *FoundRTL = NULL;
292 
293     // Scan the RTLs that have associated images until we find one that supports
294     // the current image. We only need to scan RTLs that are already being used.
295     for (auto *R : RTLs.UsedRTLs) {
296 
297       assert(R->isUsed && "Expecting used RTLs.");
298 
299       if (!R->is_valid_binary(img)) {
300         DP("Image " DPxMOD " is NOT compatible with RTL " DPxMOD "!\n",
301             DPxPTR(img->ImageStart), DPxPTR(R->LibraryHandler));
302         continue;
303       }
304 
305       DP("Image " DPxMOD " is compatible with RTL " DPxMOD "!\n",
306           DPxPTR(img->ImageStart), DPxPTR(R->LibraryHandler));
307 
308       FoundRTL = R;
309 
310       // Execute dtors for static objects if the device has been used, i.e.
311       // if its PendingCtors list has been emptied.
312       for (int32_t i = 0; i < FoundRTL->NumberOfDevices; ++i) {
313         DeviceTy &Device = Devices[FoundRTL->Idx + i];
314         Device.PendingGlobalsMtx.lock();
315         if (Device.PendingCtorsDtors[desc].PendingCtors.empty()) {
316           for (auto &dtor : Device.PendingCtorsDtors[desc].PendingDtors) {
317             int rc = target(Device.DeviceID, dtor, 0, NULL, NULL, NULL, NULL, 1,
318                 1, true /*team*/);
319             if (rc != OFFLOAD_SUCCESS) {
320               DP("Running destructor " DPxMOD " failed.\n", DPxPTR(dtor));
321             }
322           }
323           // Remove this library's entry from PendingCtorsDtors
324           Device.PendingCtorsDtors.erase(desc);
325         }
326         Device.PendingGlobalsMtx.unlock();
327       }
328 
329       DP("Unregistered image " DPxMOD " from RTL " DPxMOD "!\n",
330           DPxPTR(img->ImageStart), DPxPTR(R->LibraryHandler));
331 
332       break;
333     }
334 
335     // if no RTL was found proceed to unregister the next image
336     if (!FoundRTL){
337       DP("No RTLs in use support the image " DPxMOD "!\n",
338           DPxPTR(img->ImageStart));
339     }
340   }
341   RTLsMtx.unlock();
342   DP("Done unregistering images!\n");
343 
344   // Remove entries from HostPtrToTableMap
345   TblMapMtx.lock();
346   for (__tgt_offload_entry *cur = desc->HostEntriesBegin;
347       cur < desc->HostEntriesEnd; ++cur) {
348     HostPtrToTableMap.erase(cur->addr);
349   }
350 
351   // Remove translation table for this descriptor.
352   auto tt = HostEntriesBeginToTransTable.find(desc->HostEntriesBegin);
353   if (tt != HostEntriesBeginToTransTable.end()) {
354     DP("Removing translation table for descriptor " DPxMOD "\n",
355         DPxPTR(desc->HostEntriesBegin));
356     HostEntriesBeginToTransTable.erase(tt);
357   } else {
358     DP("Translation table for descriptor " DPxMOD " cannot be found, probably "
359         "it has been already removed.\n", DPxPTR(desc->HostEntriesBegin));
360   }
361 
362   TblMapMtx.unlock();
363 
364   // TODO: Remove RTL and the devices it manages if it's not used anymore?
365   // TODO: Write some RTL->unload_image(...) function?
366 
367   DP("Done unregistering library!\n");
368 }
369