xref: /llvm-project/offload/plugins-nextgen/common/src/GlobalHandler.cpp (revision 8d1d67ec4dc957ce15a06f782c6746281e66e559)
1330d8983SJohannes Doerfert //===- GlobalHandler.cpp - Target independent global & env. var handling --===//
2330d8983SJohannes Doerfert //
3330d8983SJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4330d8983SJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
5330d8983SJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6330d8983SJohannes Doerfert //
7330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
8330d8983SJohannes Doerfert //
9330d8983SJohannes Doerfert // Target independent global handler and environment manager.
10330d8983SJohannes Doerfert //
11330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
12330d8983SJohannes Doerfert 
13330d8983SJohannes Doerfert #include "GlobalHandler.h"
14330d8983SJohannes Doerfert #include "PluginInterface.h"
15330d8983SJohannes Doerfert #include "Utils/ELF.h"
16330d8983SJohannes Doerfert 
17330d8983SJohannes Doerfert #include "Shared/Utils.h"
18330d8983SJohannes Doerfert 
19330d8983SJohannes Doerfert #include "llvm/Support/Error.h"
20330d8983SJohannes Doerfert 
21330d8983SJohannes Doerfert #include <cstring>
22fde2d23eSEthan Luis McDonough #include <string>
23330d8983SJohannes Doerfert 
24330d8983SJohannes Doerfert using namespace llvm;
25330d8983SJohannes Doerfert using namespace omp;
26330d8983SJohannes Doerfert using namespace target;
27330d8983SJohannes Doerfert using namespace plugin;
28330d8983SJohannes Doerfert 
29330d8983SJohannes Doerfert Expected<std::unique_ptr<ObjectFile>>
30330d8983SJohannes Doerfert GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) {
31330d8983SJohannes Doerfert   assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) &&
32330d8983SJohannes Doerfert          "Input is not an ELF file");
33330d8983SJohannes Doerfert 
34330d8983SJohannes Doerfert   return ELFObjectFileBase::createELFObjectFile(Image.getMemoryBuffer());
35330d8983SJohannes Doerfert }
36330d8983SJohannes Doerfert 
37330d8983SJohannes Doerfert Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
38330d8983SJohannes Doerfert     GenericDeviceTy &Device, DeviceImageTy &Image, const GlobalTy &HostGlobal,
39330d8983SJohannes Doerfert     bool Device2Host) {
40330d8983SJohannes Doerfert 
41330d8983SJohannes Doerfert   GlobalTy DeviceGlobal(HostGlobal.getName(), HostGlobal.getSize());
42330d8983SJohannes Doerfert 
43330d8983SJohannes Doerfert   // Get the metadata from the global on the device.
44330d8983SJohannes Doerfert   if (auto Err = getGlobalMetadataFromDevice(Device, Image, DeviceGlobal))
45330d8983SJohannes Doerfert     return Err;
46330d8983SJohannes Doerfert 
47330d8983SJohannes Doerfert   // Perform the actual transfer.
48330d8983SJohannes Doerfert   return moveGlobalBetweenDeviceAndHost(Device, HostGlobal, DeviceGlobal,
49330d8983SJohannes Doerfert                                         Device2Host);
50330d8983SJohannes Doerfert }
51330d8983SJohannes Doerfert 
52330d8983SJohannes Doerfert /// Actually move memory between host and device. See readGlobalFromDevice and
53330d8983SJohannes Doerfert /// writeGlobalToDevice for the interface description.
54330d8983SJohannes Doerfert Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
55330d8983SJohannes Doerfert     GenericDeviceTy &Device, const GlobalTy &HostGlobal,
56330d8983SJohannes Doerfert     const GlobalTy &DeviceGlobal, bool Device2Host) {
57330d8983SJohannes Doerfert 
58330d8983SJohannes Doerfert   // Transfer the data from the source to the destination.
59330d8983SJohannes Doerfert   if (Device2Host) {
60330d8983SJohannes Doerfert     if (auto Err =
61330d8983SJohannes Doerfert             Device.dataRetrieve(HostGlobal.getPtr(), DeviceGlobal.getPtr(),
62330d8983SJohannes Doerfert                                 HostGlobal.getSize(), nullptr))
63330d8983SJohannes Doerfert       return Err;
64330d8983SJohannes Doerfert   } else {
65330d8983SJohannes Doerfert     if (auto Err = Device.dataSubmit(DeviceGlobal.getPtr(), HostGlobal.getPtr(),
66330d8983SJohannes Doerfert                                      HostGlobal.getSize(), nullptr))
67330d8983SJohannes Doerfert       return Err;
68330d8983SJohannes Doerfert   }
69330d8983SJohannes Doerfert 
70330d8983SJohannes Doerfert   DP("Succesfully %s %u bytes associated with global symbol '%s' %s the "
71330d8983SJohannes Doerfert      "device "
72330d8983SJohannes Doerfert      "(%p -> %p).\n",
73330d8983SJohannes Doerfert      Device2Host ? "read" : "write", HostGlobal.getSize(),
74330d8983SJohannes Doerfert      HostGlobal.getName().data(), Device2Host ? "from" : "to",
75330d8983SJohannes Doerfert      DeviceGlobal.getPtr(), HostGlobal.getPtr());
76330d8983SJohannes Doerfert 
77330d8983SJohannes Doerfert   return Plugin::success();
78330d8983SJohannes Doerfert }
79330d8983SJohannes Doerfert 
80330d8983SJohannes Doerfert bool GenericGlobalHandlerTy::isSymbolInImage(GenericDeviceTy &Device,
81330d8983SJohannes Doerfert                                              DeviceImageTy &Image,
82330d8983SJohannes Doerfert                                              StringRef SymName) {
83330d8983SJohannes Doerfert   // Get the ELF object file for the image. Notice the ELF object may already
84330d8983SJohannes Doerfert   // be created in previous calls, so we can reuse it. If this is unsuccessful
85330d8983SJohannes Doerfert   // just return false as we couldn't find it.
86330d8983SJohannes Doerfert   auto ELFObjOrErr = getELFObjectFile(Image);
87330d8983SJohannes Doerfert   if (!ELFObjOrErr) {
88330d8983SJohannes Doerfert     consumeError(ELFObjOrErr.takeError());
89330d8983SJohannes Doerfert     return false;
90330d8983SJohannes Doerfert   }
91330d8983SJohannes Doerfert 
92330d8983SJohannes Doerfert   // Search the ELF symbol using the symbol name.
93330d8983SJohannes Doerfert   auto SymOrErr = utils::elf::getSymbol(**ELFObjOrErr, SymName);
94330d8983SJohannes Doerfert   if (!SymOrErr) {
95330d8983SJohannes Doerfert     consumeError(SymOrErr.takeError());
96330d8983SJohannes Doerfert     return false;
97330d8983SJohannes Doerfert   }
98330d8983SJohannes Doerfert 
99330d8983SJohannes Doerfert   return SymOrErr->has_value();
100330d8983SJohannes Doerfert }
101330d8983SJohannes Doerfert 
102330d8983SJohannes Doerfert Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
103330d8983SJohannes Doerfert     GenericDeviceTy &Device, DeviceImageTy &Image, GlobalTy &ImageGlobal) {
104330d8983SJohannes Doerfert 
105330d8983SJohannes Doerfert   // Get the ELF object file for the image. Notice the ELF object may already
106330d8983SJohannes Doerfert   // be created in previous calls, so we can reuse it.
107330d8983SJohannes Doerfert   auto ELFObj = getELFObjectFile(Image);
108330d8983SJohannes Doerfert   if (!ELFObj)
109330d8983SJohannes Doerfert     return ELFObj.takeError();
110330d8983SJohannes Doerfert 
111330d8983SJohannes Doerfert   // Search the ELF symbol using the symbol name.
112330d8983SJohannes Doerfert   auto SymOrErr = utils::elf::getSymbol(**ELFObj, ImageGlobal.getName());
113330d8983SJohannes Doerfert   if (!SymOrErr)
114330d8983SJohannes Doerfert     return Plugin::error("Failed ELF lookup of global '%s': %s",
115330d8983SJohannes Doerfert                          ImageGlobal.getName().data(),
116330d8983SJohannes Doerfert                          toString(SymOrErr.takeError()).data());
117330d8983SJohannes Doerfert 
118330d8983SJohannes Doerfert   if (!SymOrErr->has_value())
119330d8983SJohannes Doerfert     return Plugin::error("Failed to find global symbol '%s' in the ELF image",
120330d8983SJohannes Doerfert                          ImageGlobal.getName().data());
121330d8983SJohannes Doerfert 
122330d8983SJohannes Doerfert   auto AddrOrErr = utils::elf::getSymbolAddress(**SymOrErr);
123330d8983SJohannes Doerfert   // Get the section to which the symbol belongs.
124330d8983SJohannes Doerfert   if (!AddrOrErr)
125330d8983SJohannes Doerfert     return Plugin::error("Failed to get ELF symbol from global '%s': %s",
126330d8983SJohannes Doerfert                          ImageGlobal.getName().data(),
127330d8983SJohannes Doerfert                          toString(AddrOrErr.takeError()).data());
128330d8983SJohannes Doerfert 
129330d8983SJohannes Doerfert   // Setup the global symbol's address and size.
130330d8983SJohannes Doerfert   ImageGlobal.setPtr(const_cast<void *>(*AddrOrErr));
131330d8983SJohannes Doerfert   ImageGlobal.setSize((*SymOrErr)->getSize());
132330d8983SJohannes Doerfert 
133330d8983SJohannes Doerfert   return Plugin::success();
134330d8983SJohannes Doerfert }
135330d8983SJohannes Doerfert 
136330d8983SJohannes Doerfert Error GenericGlobalHandlerTy::readGlobalFromImage(GenericDeviceTy &Device,
137330d8983SJohannes Doerfert                                                   DeviceImageTy &Image,
138330d8983SJohannes Doerfert                                                   const GlobalTy &HostGlobal) {
139330d8983SJohannes Doerfert 
140330d8983SJohannes Doerfert   GlobalTy ImageGlobal(HostGlobal.getName(), -1);
141330d8983SJohannes Doerfert   if (auto Err = getGlobalMetadataFromImage(Device, Image, ImageGlobal))
142330d8983SJohannes Doerfert     return Err;
143330d8983SJohannes Doerfert 
144330d8983SJohannes Doerfert   if (ImageGlobal.getSize() != HostGlobal.getSize())
145330d8983SJohannes Doerfert     return Plugin::error("Transfer failed because global symbol '%s' has "
146330d8983SJohannes Doerfert                          "%u bytes in the ELF image but %u bytes on the host",
147330d8983SJohannes Doerfert                          HostGlobal.getName().data(), ImageGlobal.getSize(),
148330d8983SJohannes Doerfert                          HostGlobal.getSize());
149330d8983SJohannes Doerfert 
150330d8983SJohannes Doerfert   DP("Global symbol '%s' was found in the ELF image and %u bytes will copied "
151330d8983SJohannes Doerfert      "from %p to %p.\n",
152330d8983SJohannes Doerfert      HostGlobal.getName().data(), HostGlobal.getSize(), ImageGlobal.getPtr(),
153330d8983SJohannes Doerfert      HostGlobal.getPtr());
154330d8983SJohannes Doerfert 
155330d8983SJohannes Doerfert   assert(Image.getStart() <= ImageGlobal.getPtr() &&
15608533a3eSJohannes Doerfert          utils::advancePtr(ImageGlobal.getPtr(), ImageGlobal.getSize()) <
15708533a3eSJohannes Doerfert              utils::advancePtr(Image.getStart(), Image.getSize()) &&
158330d8983SJohannes Doerfert          "Attempting to read outside the image!");
159330d8983SJohannes Doerfert 
160330d8983SJohannes Doerfert   // Perform the copy from the image to the host memory.
161330d8983SJohannes Doerfert   std::memcpy(HostGlobal.getPtr(), ImageGlobal.getPtr(), HostGlobal.getSize());
162330d8983SJohannes Doerfert 
163330d8983SJohannes Doerfert   return Plugin::success();
164330d8983SJohannes Doerfert }
165fde2d23eSEthan Luis McDonough 
166fde2d23eSEthan Luis McDonough bool GenericGlobalHandlerTy::hasProfilingGlobals(GenericDeviceTy &Device,
167fde2d23eSEthan Luis McDonough                                                  DeviceImageTy &Image) {
168fde2d23eSEthan Luis McDonough   GlobalTy global(getInstrProfNamesVarName().str(), 0);
169fde2d23eSEthan Luis McDonough   if (auto Err = getGlobalMetadataFromImage(Device, Image, global)) {
170fde2d23eSEthan Luis McDonough     consumeError(std::move(Err));
171fde2d23eSEthan Luis McDonough     return false;
172fde2d23eSEthan Luis McDonough   }
173fde2d23eSEthan Luis McDonough   return true;
174fde2d23eSEthan Luis McDonough }
175fde2d23eSEthan Luis McDonough 
176fde2d23eSEthan Luis McDonough Expected<GPUProfGlobals>
177fde2d23eSEthan Luis McDonough GenericGlobalHandlerTy::readProfilingGlobals(GenericDeviceTy &Device,
178fde2d23eSEthan Luis McDonough                                              DeviceImageTy &Image) {
179fde2d23eSEthan Luis McDonough   GPUProfGlobals DeviceProfileData;
180fde2d23eSEthan Luis McDonough   auto ObjFile = getELFObjectFile(Image);
181fde2d23eSEthan Luis McDonough   if (!ObjFile)
182fde2d23eSEthan Luis McDonough     return ObjFile.takeError();
183fde2d23eSEthan Luis McDonough 
184fde2d23eSEthan Luis McDonough   std::unique_ptr<ELFObjectFileBase> ELFObj(
185fde2d23eSEthan Luis McDonough       static_cast<ELFObjectFileBase *>(ObjFile->release()));
186fde2d23eSEthan Luis McDonough   DeviceProfileData.TargetTriple = ELFObj->makeTriple();
187fde2d23eSEthan Luis McDonough 
188fde2d23eSEthan Luis McDonough   // Iterate through elf symbols
189fde2d23eSEthan Luis McDonough   for (auto &Sym : ELFObj->symbols()) {
190fde2d23eSEthan Luis McDonough     auto NameOrErr = Sym.getName();
191fde2d23eSEthan Luis McDonough     if (!NameOrErr)
192fde2d23eSEthan Luis McDonough       return NameOrErr.takeError();
193fde2d23eSEthan Luis McDonough 
194fde2d23eSEthan Luis McDonough     // Check if given current global is a profiling global based
195fde2d23eSEthan Luis McDonough     // on name
196fde2d23eSEthan Luis McDonough     if (*NameOrErr == getInstrProfNamesVarName()) {
197fde2d23eSEthan Luis McDonough       // Read in profiled function names
198fde2d23eSEthan Luis McDonough       DeviceProfileData.NamesData = SmallVector<uint8_t>(Sym.getSize(), 0);
199fde2d23eSEthan Luis McDonough       GlobalTy NamesGlobal(NameOrErr->str(), Sym.getSize(),
200fde2d23eSEthan Luis McDonough                            DeviceProfileData.NamesData.data());
201fde2d23eSEthan Luis McDonough       if (auto Err = readGlobalFromDevice(Device, Image, NamesGlobal))
202fde2d23eSEthan Luis McDonough         return Err;
203fde2d23eSEthan Luis McDonough     } else if (NameOrErr->starts_with(getInstrProfCountersVarPrefix())) {
204fde2d23eSEthan Luis McDonough       // Read global variable profiling counts
205fde2d23eSEthan Luis McDonough       SmallVector<int64_t> Counts(Sym.getSize() / sizeof(int64_t), 0);
206fde2d23eSEthan Luis McDonough       GlobalTy CountGlobal(NameOrErr->str(), Sym.getSize(), Counts.data());
207fde2d23eSEthan Luis McDonough       if (auto Err = readGlobalFromDevice(Device, Image, CountGlobal))
208fde2d23eSEthan Luis McDonough         return Err;
209fde2d23eSEthan Luis McDonough       DeviceProfileData.Counts.push_back(std::move(Counts));
210fde2d23eSEthan Luis McDonough     } else if (NameOrErr->starts_with(getInstrProfDataVarPrefix())) {
211fde2d23eSEthan Luis McDonough       // Read profiling data for this global variable
212fde2d23eSEthan Luis McDonough       __llvm_profile_data Data{};
213fde2d23eSEthan Luis McDonough       GlobalTy DataGlobal(NameOrErr->str(), Sym.getSize(), &Data);
214fde2d23eSEthan Luis McDonough       if (auto Err = readGlobalFromDevice(Device, Image, DataGlobal))
215fde2d23eSEthan Luis McDonough         return Err;
216fde2d23eSEthan Luis McDonough       DeviceProfileData.Data.push_back(std::move(Data));
217fde2d23eSEthan Luis McDonough     }
218fde2d23eSEthan Luis McDonough   }
219fde2d23eSEthan Luis McDonough   return DeviceProfileData;
220fde2d23eSEthan Luis McDonough }
221fde2d23eSEthan Luis McDonough 
222fde2d23eSEthan Luis McDonough void GPUProfGlobals::dump() const {
223fde2d23eSEthan Luis McDonough   outs() << "======= GPU Profile =======\nTarget: " << TargetTriple.str()
224fde2d23eSEthan Luis McDonough          << "\n";
225fde2d23eSEthan Luis McDonough 
226fde2d23eSEthan Luis McDonough   outs() << "======== Counters =========\n";
227fde2d23eSEthan Luis McDonough   for (const auto &Count : Counts) {
228fde2d23eSEthan Luis McDonough     outs() << "[";
229fde2d23eSEthan Luis McDonough     for (size_t i = 0; i < Count.size(); i++) {
230fde2d23eSEthan Luis McDonough       if (i == 0)
231fde2d23eSEthan Luis McDonough         outs() << " ";
232fde2d23eSEthan Luis McDonough       outs() << Count[i] << " ";
233fde2d23eSEthan Luis McDonough     }
234fde2d23eSEthan Luis McDonough     outs() << "]\n";
235fde2d23eSEthan Luis McDonough   }
236fde2d23eSEthan Luis McDonough 
237fde2d23eSEthan Luis McDonough   outs() << "========== Data ===========\n";
238fde2d23eSEthan Luis McDonough   for (const auto &ProfData : Data) {
239fde2d23eSEthan Luis McDonough     outs() << "{ ";
240*8d1d67ecSJinsong Ji // The ProfData.Name maybe array, eg: NumValueSites[IPVK_Last+1] .
241*8d1d67ecSJinsong Ji // If we print out it directly, we are accessing out of bound data.
242*8d1d67ecSJinsong Ji // Skip dumping the array for now.
243fde2d23eSEthan Luis McDonough #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer)                     \
244*8d1d67ecSJinsong Ji   if (sizeof(#Name) > 2 && #Name[sizeof(#Name) - 2] == ']') {                  \
245*8d1d67ecSJinsong Ji     outs() << "[...] ";                                                        \
246*8d1d67ecSJinsong Ji   } else {                                                                     \
247*8d1d67ecSJinsong Ji     outs() << ProfData.Name << " ";                                            \
248*8d1d67ecSJinsong Ji   }
249fde2d23eSEthan Luis McDonough #include "llvm/ProfileData/InstrProfData.inc"
250fde2d23eSEthan Luis McDonough     outs() << "}\n";
251fde2d23eSEthan Luis McDonough   }
252fde2d23eSEthan Luis McDonough 
253fde2d23eSEthan Luis McDonough   outs() << "======== Functions ========\n";
254fde2d23eSEthan Luis McDonough   std::string s;
255fde2d23eSEthan Luis McDonough   s.reserve(NamesData.size());
256fde2d23eSEthan Luis McDonough   for (uint8_t Name : NamesData) {
257fde2d23eSEthan Luis McDonough     s.push_back((char)Name);
258fde2d23eSEthan Luis McDonough   }
259fde2d23eSEthan Luis McDonough 
260fde2d23eSEthan Luis McDonough   InstrProfSymtab Symtab;
261fde2d23eSEthan Luis McDonough   if (Error Err = Symtab.create(StringRef(s))) {
262fde2d23eSEthan Luis McDonough     consumeError(std::move(Err));
263fde2d23eSEthan Luis McDonough   }
264fde2d23eSEthan Luis McDonough   Symtab.dumpNames(outs());
265fde2d23eSEthan Luis McDonough   outs() << "===========================\n";
266fde2d23eSEthan Luis McDonough }
267