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