/
pccc
/
pccc-mlir
Обзор
Документация
Войти
/
pccc
/
pccc-mlir
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
offload/plugins-nextgen/common/src/GlobalHandler.cpp
330 строк
13 KB
obitotsky
fork mlir
19 июл 2026, 07:05
Верифицирован
19 июл 2026, 07:05
6422b87
Код
Авторство
О чём код?
//===- GlobalHandler.cpp - Target independent global & env. var handling --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Target independent global handler and environment manager. // //===----------------------------------------------------------------------===// #include "GlobalHandler.h" #include "PluginInterface.h" #include "Utils/ELF.h" #include "Shared/Utils.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/ProfileData/InstrProfData.inc" #include "llvm/Support/Error.h" #include <cstring> #include <string> using namespace llvm; using namespace omp; using namespace target; using namespace plugin; using namespace error; using namespace llvm::offload::debug; // Windows (MSVC/clang, but not MinGW) does not support __attribute__((weak)), // so provide a fallback stub via /alternatename. The linker picks compiler-rt's // strong definition when clang_rt.profile is linked; otherwise the stub is // used. #if defined(_WIN32) && !defined(__MINGW32__) extern "C" int __llvm_write_custom_profile_default( const char *, const __llvm_profile_data *, const __llvm_profile_data *, const char *, const char *, const char *, const char *, const char *, const char *, const uint64_t *) { return -1; } #pragma comment( \ linker, \ "/alternatename:__llvm_write_custom_profile=__llvm_write_custom_profile_default") #endif Expected<std::unique_ptr<ObjectFile>> GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) { assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) && "Input is not an ELF file"); auto Expected = ELFObjectFileBase::createELFObjectFile(Image.getMemoryBuffer()); if (!Expected) { return Plugin::error(ErrorCode::INVALID_BINARY, Expected.takeError(), "error parsing binary"); } return Expected; } Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost( GenericDeviceTy &Device, DeviceImageTy &Image, const GlobalTy &HostGlobal, bool Device2Host) { GlobalTy DeviceGlobal(HostGlobal.getName(), HostGlobal.getSize()); // Get the metadata from the global on the device. if (auto Err = getGlobalMetadataFromDevice(Device, Image, DeviceGlobal)) return Err; // Perform the actual transfer. return moveGlobalBetweenDeviceAndHost(Device, HostGlobal, DeviceGlobal, Device2Host); } /// Actually move memory between host and device. See readGlobalFromDevice and /// writeGlobalToDevice for the interface description. Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost( GenericDeviceTy &Device, const GlobalTy &HostGlobal, const GlobalTy &DeviceGlobal, bool Device2Host) { // Transfer the data from the source to the destination. if (Device2Host) { if (auto Err = Device.dataRetrieve(HostGlobal.getPtr(), DeviceGlobal.getPtr(), HostGlobal.getSize(), nullptr)) return Err; } else { if (auto Err = Device.dataSubmit(DeviceGlobal.getPtr(), HostGlobal.getPtr(), HostGlobal.getSize(), nullptr)) return Err; } ODBG(OLDT_DataTransfer) << "Successfully " << (Device2Host ? "read" : "write") << " " << HostGlobal.getSize() << " bytes associated with global symbol '" << HostGlobal.getName() << "' " << (Device2Host ? "from" : "to") << " the device (" << DeviceGlobal.getPtr() << " -> " << HostGlobal.getPtr() << ")."; return Plugin::success(); } bool GenericGlobalHandlerTy::isSymbolInImage(GenericDeviceTy &Device, DeviceImageTy &Image, StringRef SymName) { // Get the ELF object file for the image. Notice the ELF object may already // be created in previous calls, so we can reuse it. If this is unsuccessful // just return false as we couldn't find it. auto ELFObjOrErr = getELFObjectFile(Image); if (!ELFObjOrErr) { consumeError(ELFObjOrErr.takeError()); return false; } // Search the ELF symbol using the symbol name. auto SymOrErr = utils::elf::getSymbol(**ELFObjOrErr, SymName); if (!SymOrErr) { consumeError(SymOrErr.takeError()); return false; } return SymOrErr->has_value(); } Error GenericGlobalHandlerTy::getGlobalMetadataFromImage( GenericDeviceTy &Device, DeviceImageTy &Image, GlobalTy &ImageGlobal) { // Get the ELF object file for the image. Notice the ELF object may already // be created in previous calls, so we can reuse it. auto ELFObj = getELFObjectFile(Image); if (!ELFObj) return ELFObj.takeError(); // Search the ELF symbol using the symbol name. auto SymOrErr = utils::elf::getSymbol(**ELFObj, ImageGlobal.getName()); if (!SymOrErr) return Plugin::error( ErrorCode::NOT_FOUND, "failed ELF lookup of global '%s': %s", ImageGlobal.getName().data(), toString(SymOrErr.takeError()).data()); if (!SymOrErr->has_value()) return Plugin::error(ErrorCode::NOT_FOUND, "failed to find global symbol '%s' in the ELF image", ImageGlobal.getName().data()); auto AddrOrErr = utils::elf::getSymbolAddress(**SymOrErr); // Get the section to which the symbol belongs. if (!AddrOrErr) return Plugin::error( ErrorCode::NOT_FOUND, "failed to get ELF symbol from global '%s': %s", ImageGlobal.getName().data(), toString(AddrOrErr.takeError()).data()); // Setup the global symbol's address and size. ImageGlobal.setPtr(const_cast<void *>(*AddrOrErr)); ImageGlobal.setSize((*SymOrErr)->getSize()); return Plugin::success(); } Error GenericGlobalHandlerTy::readGlobalFromImage(GenericDeviceTy &Device, DeviceImageTy &Image, const GlobalTy &HostGlobal) { GlobalTy ImageGlobal(HostGlobal.getName(), -1); if (auto Err = getGlobalMetadataFromImage(Device, Image, ImageGlobal)) return Err; if (ImageGlobal.getSize() != HostGlobal.getSize()) return Plugin::error(ErrorCode::INVALID_BINARY, "transfer failed because global symbol '%s' has " "%u bytes in the ELF image but %u bytes on the host", HostGlobal.getName().data(), ImageGlobal.getSize(), HostGlobal.getSize()); ODBG(OLDT_DataTransfer) << "Global symbol '" << HostGlobal.getName() << "' was found in the ELF image and " << HostGlobal.getSize() << " bytes will copied from " << ImageGlobal.getPtr() << " to " << HostGlobal.getPtr() << "."; assert(Image.getStart() <= ImageGlobal.getPtr() && utils::advancePtr(ImageGlobal.getPtr(), ImageGlobal.getSize()) < utils::advancePtr(Image.getStart(), Image.getSize()) && "Attempting to read outside the image!"); // Perform the copy from the image to the host memory. std::memcpy(HostGlobal.getPtr(), ImageGlobal.getPtr(), HostGlobal.getSize()); return Plugin::success(); } Expected<GPUProfGlobals> GenericGlobalHandlerTy::readProfilingGlobals(GenericDeviceTy &Device, DeviceImageTy &Image) { const char *TableName = INSTR_PROF_QUOTE(INSTR_PROF_SECT_BOUNDS_TABLE); if (!isSymbolInImage(Device, Image, TableName)) return GPUProfGlobals{}; GPUProfGlobals ProfData; auto ObjFile = getELFObjectFile(Image); if (!ObjFile) return ObjFile.takeError(); std::unique_ptr<ELFObjectFileBase> ELFObj( static_cast<ELFObjectFileBase *>(ObjFile->release())); ProfData.TargetTriple = ELFObj->makeTriple(); __llvm_profile_gpu_sections Table = {}; GlobalTy TableGlobal(TableName, sizeof(Table), &Table); if (auto Err = readGlobalFromDevice(Device, Image, TableGlobal)) return Err; // Read the contiguous data from one of the profiling sections on the device. auto ReadSection = [&](const void *Start, const void *Stop, SmallVector<char> &Out) -> Error { uintptr_t Begin = reinterpret_cast<uintptr_t>(Start); uintptr_t End = reinterpret_cast<uintptr_t>(Stop); size_t Size = End - Begin; Out.resize_for_overwrite(Size); return Size ? Device.dataRetrieve(Out.data(), Start, Size, /*AsyncInfo=*/nullptr) : Error::success(); }; if (auto Err = ReadSection(Table.NamesStart, Table.NamesStop, ProfData.NamesSection)) return Err; if (auto Err = ReadSection(Table.CountersStart, Table.CountersStop, ProfData.CountersSection)) return Err; if (auto Err = ReadSection(Table.DataStart, Table.DataStop, ProfData.DataSection)) return Err; ProfData.DeviceCountersDelta = reinterpret_cast<intptr_t>(Table.CountersStart) - reinterpret_cast<intptr_t>(Table.DataStart); // Get the profiling version from the device. if (auto Err = Device.dataRetrieve(&ProfData.Version, Table.VersionVar, sizeof(uint64_t), /*AsyncInfo=*/nullptr)) return Err; return ProfData; } void GPUProfGlobals::dump() const { outs() << "======= GPU Profile =======\nTarget: " << TargetTriple.str() << "\n"; size_t NumCounters = CountersSection.size() / sizeof(int64_t); outs() << "======== Counters (" << NumCounters << ") =========\n"; auto *Counts = reinterpret_cast<const int64_t *>(CountersSection.data()); for (size_t i = 0; i < NumCounters; i++) { if (i > 0 && i % 10 == 0) outs() << "\n"; else if (i != 0) outs() << " "; outs() << Counts[i]; } outs() << "\n"; size_t NumDataEntries = DataSection.size() / sizeof(__llvm_profile_data); outs() << "========== Data (" << NumDataEntries << ") ===========\n"; outs() << "======== Functions ========\n"; InstrProfSymtab Symtab; if (Error Err = Symtab.create(StringRef(NamesSection.data(), NamesSection.size()))) consumeError(std::move(Err)); Symtab.dumpNames(outs()); outs() << "===========================\n"; } Error GPUProfGlobals::write() const { #if !defined(_WIN32) || defined(__MINGW32__) // On Windows (non-MinGW) the /alternatename stub above is never null. if (!__llvm_write_custom_profile) return Plugin::error(ErrorCode::INVALID_BINARY, "could not find symbol __llvm_write_custom_profile. " "The compiler-rt profiling library must be linked for " "GPU PGO to work."); #endif // Lay out as [Data][Counters][Names] to match the raw profile format order. // TODO: Move this interface to compiler-rt. SmallVector<char> Buffer(DataSection.size() + CountersSection.size() + NamesSection.size()); char *DataBegin = Buffer.data(); char *CountersBegin = DataBegin + DataSection.size(); char *NamesBegin = CountersBegin + CountersSection.size(); memcpy(DataBegin, DataSection.data(), DataSection.size()); memcpy(CountersBegin, CountersSection.data(), CountersSection.size()); memcpy(NamesBegin, NamesSection.data(), NamesSection.size()); // Adjust CounterPtr values so they are consistent with the host layout rather // than the device layout. intptr_t HostDelta = CountersBegin - DataBegin; intptr_t Adjustment = HostDelta - DeviceCountersDelta; auto *Records = reinterpret_cast<__llvm_profile_data *>(DataBegin); size_t NumRecords = DataSection.size() / sizeof(__llvm_profile_data); for (size_t I = 0; I < NumRecords; I++) Records[I].CounterPtr = reinterpret_cast<void *>( reinterpret_cast<intptr_t>(Records[I].CounterPtr) + Adjustment); int Result = __llvm_write_custom_profile( TargetTriple.str().c_str(), reinterpret_cast<const __llvm_profile_data *>(DataBegin), reinterpret_cast<const __llvm_profile_data *>(DataBegin + DataSection.size()), CountersBegin, CountersBegin + CountersSection.size(), /*UniformCountersBegin=*/nullptr, /*UniformCountersEnd=*/nullptr, NamesBegin, NamesBegin + NamesSection.size(), &Version); if (Result != 0) return Plugin::error(ErrorCode::HOST_IO, "error writing GPU PGO data to file"); return Plugin::success(); } bool GPUProfGlobals::empty() const { return CountersSection.empty() && DataSection.empty() && NamesSection.empty(); }