xref: /llvm-project/offload/plugins-nextgen/common/src/GlobalHandler.cpp (revision 8d1d67ec4dc957ce15a06f782c6746281e66e559)
1 //===- GlobalHandler.cpp - Target independent global & env. var handling --===//
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 // Target independent global handler and environment manager.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "GlobalHandler.h"
14 #include "PluginInterface.h"
15 #include "Utils/ELF.h"
16 
17 #include "Shared/Utils.h"
18 
19 #include "llvm/Support/Error.h"
20 
21 #include <cstring>
22 #include <string>
23 
24 using namespace llvm;
25 using namespace omp;
26 using namespace target;
27 using namespace plugin;
28 
29 Expected<std::unique_ptr<ObjectFile>>
30 GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) {
31   assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) &&
32          "Input is not an ELF file");
33 
34   return ELFObjectFileBase::createELFObjectFile(Image.getMemoryBuffer());
35 }
36 
37 Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
38     GenericDeviceTy &Device, DeviceImageTy &Image, const GlobalTy &HostGlobal,
39     bool Device2Host) {
40 
41   GlobalTy DeviceGlobal(HostGlobal.getName(), HostGlobal.getSize());
42 
43   // Get the metadata from the global on the device.
44   if (auto Err = getGlobalMetadataFromDevice(Device, Image, DeviceGlobal))
45     return Err;
46 
47   // Perform the actual transfer.
48   return moveGlobalBetweenDeviceAndHost(Device, HostGlobal, DeviceGlobal,
49                                         Device2Host);
50 }
51 
52 /// Actually move memory between host and device. See readGlobalFromDevice and
53 /// writeGlobalToDevice for the interface description.
54 Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
55     GenericDeviceTy &Device, const GlobalTy &HostGlobal,
56     const GlobalTy &DeviceGlobal, bool Device2Host) {
57 
58   // Transfer the data from the source to the destination.
59   if (Device2Host) {
60     if (auto Err =
61             Device.dataRetrieve(HostGlobal.getPtr(), DeviceGlobal.getPtr(),
62                                 HostGlobal.getSize(), nullptr))
63       return Err;
64   } else {
65     if (auto Err = Device.dataSubmit(DeviceGlobal.getPtr(), HostGlobal.getPtr(),
66                                      HostGlobal.getSize(), nullptr))
67       return Err;
68   }
69 
70   DP("Succesfully %s %u bytes associated with global symbol '%s' %s the "
71      "device "
72      "(%p -> %p).\n",
73      Device2Host ? "read" : "write", HostGlobal.getSize(),
74      HostGlobal.getName().data(), Device2Host ? "from" : "to",
75      DeviceGlobal.getPtr(), HostGlobal.getPtr());
76 
77   return Plugin::success();
78 }
79 
80 bool GenericGlobalHandlerTy::isSymbolInImage(GenericDeviceTy &Device,
81                                              DeviceImageTy &Image,
82                                              StringRef SymName) {
83   // Get the ELF object file for the image. Notice the ELF object may already
84   // be created in previous calls, so we can reuse it. If this is unsuccessful
85   // just return false as we couldn't find it.
86   auto ELFObjOrErr = getELFObjectFile(Image);
87   if (!ELFObjOrErr) {
88     consumeError(ELFObjOrErr.takeError());
89     return false;
90   }
91 
92   // Search the ELF symbol using the symbol name.
93   auto SymOrErr = utils::elf::getSymbol(**ELFObjOrErr, SymName);
94   if (!SymOrErr) {
95     consumeError(SymOrErr.takeError());
96     return false;
97   }
98 
99   return SymOrErr->has_value();
100 }
101 
102 Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
103     GenericDeviceTy &Device, DeviceImageTy &Image, GlobalTy &ImageGlobal) {
104 
105   // Get the ELF object file for the image. Notice the ELF object may already
106   // be created in previous calls, so we can reuse it.
107   auto ELFObj = getELFObjectFile(Image);
108   if (!ELFObj)
109     return ELFObj.takeError();
110 
111   // Search the ELF symbol using the symbol name.
112   auto SymOrErr = utils::elf::getSymbol(**ELFObj, ImageGlobal.getName());
113   if (!SymOrErr)
114     return Plugin::error("Failed ELF lookup of global '%s': %s",
115                          ImageGlobal.getName().data(),
116                          toString(SymOrErr.takeError()).data());
117 
118   if (!SymOrErr->has_value())
119     return Plugin::error("Failed to find global symbol '%s' in the ELF image",
120                          ImageGlobal.getName().data());
121 
122   auto AddrOrErr = utils::elf::getSymbolAddress(**SymOrErr);
123   // Get the section to which the symbol belongs.
124   if (!AddrOrErr)
125     return Plugin::error("Failed to get ELF symbol from global '%s': %s",
126                          ImageGlobal.getName().data(),
127                          toString(AddrOrErr.takeError()).data());
128 
129   // Setup the global symbol's address and size.
130   ImageGlobal.setPtr(const_cast<void *>(*AddrOrErr));
131   ImageGlobal.setSize((*SymOrErr)->getSize());
132 
133   return Plugin::success();
134 }
135 
136 Error GenericGlobalHandlerTy::readGlobalFromImage(GenericDeviceTy &Device,
137                                                   DeviceImageTy &Image,
138                                                   const GlobalTy &HostGlobal) {
139 
140   GlobalTy ImageGlobal(HostGlobal.getName(), -1);
141   if (auto Err = getGlobalMetadataFromImage(Device, Image, ImageGlobal))
142     return Err;
143 
144   if (ImageGlobal.getSize() != HostGlobal.getSize())
145     return Plugin::error("Transfer failed because global symbol '%s' has "
146                          "%u bytes in the ELF image but %u bytes on the host",
147                          HostGlobal.getName().data(), ImageGlobal.getSize(),
148                          HostGlobal.getSize());
149 
150   DP("Global symbol '%s' was found in the ELF image and %u bytes will copied "
151      "from %p to %p.\n",
152      HostGlobal.getName().data(), HostGlobal.getSize(), ImageGlobal.getPtr(),
153      HostGlobal.getPtr());
154 
155   assert(Image.getStart() <= ImageGlobal.getPtr() &&
156          utils::advancePtr(ImageGlobal.getPtr(), ImageGlobal.getSize()) <
157              utils::advancePtr(Image.getStart(), Image.getSize()) &&
158          "Attempting to read outside the image!");
159 
160   // Perform the copy from the image to the host memory.
161   std::memcpy(HostGlobal.getPtr(), ImageGlobal.getPtr(), HostGlobal.getSize());
162 
163   return Plugin::success();
164 }
165 
166 bool GenericGlobalHandlerTy::hasProfilingGlobals(GenericDeviceTy &Device,
167                                                  DeviceImageTy &Image) {
168   GlobalTy global(getInstrProfNamesVarName().str(), 0);
169   if (auto Err = getGlobalMetadataFromImage(Device, Image, global)) {
170     consumeError(std::move(Err));
171     return false;
172   }
173   return true;
174 }
175 
176 Expected<GPUProfGlobals>
177 GenericGlobalHandlerTy::readProfilingGlobals(GenericDeviceTy &Device,
178                                              DeviceImageTy &Image) {
179   GPUProfGlobals DeviceProfileData;
180   auto ObjFile = getELFObjectFile(Image);
181   if (!ObjFile)
182     return ObjFile.takeError();
183 
184   std::unique_ptr<ELFObjectFileBase> ELFObj(
185       static_cast<ELFObjectFileBase *>(ObjFile->release()));
186   DeviceProfileData.TargetTriple = ELFObj->makeTriple();
187 
188   // Iterate through elf symbols
189   for (auto &Sym : ELFObj->symbols()) {
190     auto NameOrErr = Sym.getName();
191     if (!NameOrErr)
192       return NameOrErr.takeError();
193 
194     // Check if given current global is a profiling global based
195     // on name
196     if (*NameOrErr == getInstrProfNamesVarName()) {
197       // Read in profiled function names
198       DeviceProfileData.NamesData = SmallVector<uint8_t>(Sym.getSize(), 0);
199       GlobalTy NamesGlobal(NameOrErr->str(), Sym.getSize(),
200                            DeviceProfileData.NamesData.data());
201       if (auto Err = readGlobalFromDevice(Device, Image, NamesGlobal))
202         return Err;
203     } else if (NameOrErr->starts_with(getInstrProfCountersVarPrefix())) {
204       // Read global variable profiling counts
205       SmallVector<int64_t> Counts(Sym.getSize() / sizeof(int64_t), 0);
206       GlobalTy CountGlobal(NameOrErr->str(), Sym.getSize(), Counts.data());
207       if (auto Err = readGlobalFromDevice(Device, Image, CountGlobal))
208         return Err;
209       DeviceProfileData.Counts.push_back(std::move(Counts));
210     } else if (NameOrErr->starts_with(getInstrProfDataVarPrefix())) {
211       // Read profiling data for this global variable
212       __llvm_profile_data Data{};
213       GlobalTy DataGlobal(NameOrErr->str(), Sym.getSize(), &Data);
214       if (auto Err = readGlobalFromDevice(Device, Image, DataGlobal))
215         return Err;
216       DeviceProfileData.Data.push_back(std::move(Data));
217     }
218   }
219   return DeviceProfileData;
220 }
221 
222 void GPUProfGlobals::dump() const {
223   outs() << "======= GPU Profile =======\nTarget: " << TargetTriple.str()
224          << "\n";
225 
226   outs() << "======== Counters =========\n";
227   for (const auto &Count : Counts) {
228     outs() << "[";
229     for (size_t i = 0; i < Count.size(); i++) {
230       if (i == 0)
231         outs() << " ";
232       outs() << Count[i] << " ";
233     }
234     outs() << "]\n";
235   }
236 
237   outs() << "========== Data ===========\n";
238   for (const auto &ProfData : Data) {
239     outs() << "{ ";
240 // The ProfData.Name maybe array, eg: NumValueSites[IPVK_Last+1] .
241 // If we print out it directly, we are accessing out of bound data.
242 // Skip dumping the array for now.
243 #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer)                     \
244   if (sizeof(#Name) > 2 && #Name[sizeof(#Name) - 2] == ']') {                  \
245     outs() << "[...] ";                                                        \
246   } else {                                                                     \
247     outs() << ProfData.Name << " ";                                            \
248   }
249 #include "llvm/ProfileData/InstrProfData.inc"
250     outs() << "}\n";
251   }
252 
253   outs() << "======== Functions ========\n";
254   std::string s;
255   s.reserve(NamesData.size());
256   for (uint8_t Name : NamesData) {
257     s.push_back((char)Name);
258   }
259 
260   InstrProfSymtab Symtab;
261   if (Error Err = Symtab.create(StringRef(s))) {
262     consumeError(std::move(Err));
263   }
264   Symtab.dumpNames(outs());
265   outs() << "===========================\n";
266 }
267