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