1*0b57cec5SDimitry Andric //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file contains support for reading profiling data for clang's 10*0b57cec5SDimitry Andric // instrumentation based PGO and coverage. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h" 15*0b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 17*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 185ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 19*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 20*0b57cec5SDimitry Andric #include "llvm/IR/ProfileSummary.h" 21*0b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 22*0b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 23*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 24*0b57cec5SDimitry Andric #include "llvm/Support/Error.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/SymbolRemappingReader.h" 28*0b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h" 29*0b57cec5SDimitry Andric #include <algorithm> 30*0b57cec5SDimitry Andric #include <cctype> 31*0b57cec5SDimitry Andric #include <cstddef> 32*0b57cec5SDimitry Andric #include <cstdint> 33*0b57cec5SDimitry Andric #include <limits> 34*0b57cec5SDimitry Andric #include <memory> 35*0b57cec5SDimitry Andric #include <system_error> 36*0b57cec5SDimitry Andric #include <utility> 37*0b57cec5SDimitry Andric #include <vector> 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric using namespace llvm; 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>> 42*0b57cec5SDimitry Andric setupMemoryBuffer(const Twine &Path) { 43*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 44*0b57cec5SDimitry Andric MemoryBuffer::getFileOrSTDIN(Path); 45*0b57cec5SDimitry Andric if (std::error_code EC = BufferOrErr.getError()) 46*0b57cec5SDimitry Andric return errorCodeToError(EC); 47*0b57cec5SDimitry Andric return std::move(BufferOrErr.get()); 48*0b57cec5SDimitry Andric } 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric static Error initializeReader(InstrProfReader &Reader) { 51*0b57cec5SDimitry Andric return Reader.readHeader(); 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>> 55*0b57cec5SDimitry Andric InstrProfReader::create(const Twine &Path) { 56*0b57cec5SDimitry Andric // Set up the buffer to read. 57*0b57cec5SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path); 58*0b57cec5SDimitry Andric if (Error E = BufferOrError.takeError()) 59*0b57cec5SDimitry Andric return std::move(E); 60*0b57cec5SDimitry Andric return InstrProfReader::create(std::move(BufferOrError.get())); 61*0b57cec5SDimitry Andric } 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>> 64*0b57cec5SDimitry Andric InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) { 65*0b57cec5SDimitry Andric // Sanity check the buffer. 66*0b57cec5SDimitry Andric if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max()) 67*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::too_large); 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric if (Buffer->getBufferSize() == 0) 70*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::empty_raw_profile); 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric std::unique_ptr<InstrProfReader> Result; 73*0b57cec5SDimitry Andric // Create the reader. 74*0b57cec5SDimitry Andric if (IndexedInstrProfReader::hasFormat(*Buffer)) 75*0b57cec5SDimitry Andric Result.reset(new IndexedInstrProfReader(std::move(Buffer))); 76*0b57cec5SDimitry Andric else if (RawInstrProfReader64::hasFormat(*Buffer)) 77*0b57cec5SDimitry Andric Result.reset(new RawInstrProfReader64(std::move(Buffer))); 78*0b57cec5SDimitry Andric else if (RawInstrProfReader32::hasFormat(*Buffer)) 79*0b57cec5SDimitry Andric Result.reset(new RawInstrProfReader32(std::move(Buffer))); 80*0b57cec5SDimitry Andric else if (TextInstrProfReader::hasFormat(*Buffer)) 81*0b57cec5SDimitry Andric Result.reset(new TextInstrProfReader(std::move(Buffer))); 82*0b57cec5SDimitry Andric else 83*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unrecognized_format); 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric // Initialize the reader and return the result. 86*0b57cec5SDimitry Andric if (Error E = initializeReader(*Result)) 87*0b57cec5SDimitry Andric return std::move(E); 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric return std::move(Result); 90*0b57cec5SDimitry Andric } 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>> 93*0b57cec5SDimitry Andric IndexedInstrProfReader::create(const Twine &Path, const Twine &RemappingPath) { 94*0b57cec5SDimitry Andric // Set up the buffer to read. 95*0b57cec5SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path); 96*0b57cec5SDimitry Andric if (Error E = BufferOrError.takeError()) 97*0b57cec5SDimitry Andric return std::move(E); 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric // Set up the remapping buffer if requested. 100*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer; 101*0b57cec5SDimitry Andric std::string RemappingPathStr = RemappingPath.str(); 102*0b57cec5SDimitry Andric if (!RemappingPathStr.empty()) { 103*0b57cec5SDimitry Andric auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr); 104*0b57cec5SDimitry Andric if (Error E = RemappingBufferOrError.takeError()) 105*0b57cec5SDimitry Andric return std::move(E); 106*0b57cec5SDimitry Andric RemappingBuffer = std::move(RemappingBufferOrError.get()); 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric return IndexedInstrProfReader::create(std::move(BufferOrError.get()), 110*0b57cec5SDimitry Andric std::move(RemappingBuffer)); 111*0b57cec5SDimitry Andric } 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>> 114*0b57cec5SDimitry Andric IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer, 115*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer) { 116*0b57cec5SDimitry Andric // Sanity check the buffer. 117*0b57cec5SDimitry Andric if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max()) 118*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::too_large); 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric // Create the reader. 121*0b57cec5SDimitry Andric if (!IndexedInstrProfReader::hasFormat(*Buffer)) 122*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic); 1238bcb0991SDimitry Andric auto Result = std::make_unique<IndexedInstrProfReader>( 124*0b57cec5SDimitry Andric std::move(Buffer), std::move(RemappingBuffer)); 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric // Initialize the reader and return the result. 127*0b57cec5SDimitry Andric if (Error E = initializeReader(*Result)) 128*0b57cec5SDimitry Andric return std::move(E); 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric return std::move(Result); 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric void InstrProfIterator::Increment() { 134*0b57cec5SDimitry Andric if (auto E = Reader->readNextRecord(Record)) { 135*0b57cec5SDimitry Andric // Handle errors in the reader. 136*0b57cec5SDimitry Andric InstrProfError::take(std::move(E)); 137*0b57cec5SDimitry Andric *this = InstrProfIterator(); 138*0b57cec5SDimitry Andric } 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { 142*0b57cec5SDimitry Andric // Verify that this really looks like plain ASCII text by checking a 143*0b57cec5SDimitry Andric // 'reasonable' number of characters (up to profile magic size). 144*0b57cec5SDimitry Andric size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t)); 145*0b57cec5SDimitry Andric StringRef buffer = Buffer.getBufferStart(); 146*0b57cec5SDimitry Andric return count == 0 || 147*0b57cec5SDimitry Andric std::all_of(buffer.begin(), buffer.begin() + count, 1485ffd83dbSDimitry Andric [](char c) { return isPrint(c) || isSpace(c); }); 149*0b57cec5SDimitry Andric } 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric // Read the profile variant flag from the header: ":FE" means this is a FE 152*0b57cec5SDimitry Andric // generated profile. ":IR" means this is an IR level profile. Other strings 153*0b57cec5SDimitry Andric // with a leading ':' will be reported an error format. 154*0b57cec5SDimitry Andric Error TextInstrProfReader::readHeader() { 155*0b57cec5SDimitry Andric Symtab.reset(new InstrProfSymtab()); 156*0b57cec5SDimitry Andric bool IsIRInstr = false; 157*0b57cec5SDimitry Andric if (!Line->startswith(":")) { 158*0b57cec5SDimitry Andric IsIRLevelProfile = false; 159*0b57cec5SDimitry Andric return success(); 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric StringRef Str = (Line)->substr(1); 162*0b57cec5SDimitry Andric if (Str.equals_lower("ir")) 163*0b57cec5SDimitry Andric IsIRInstr = true; 164*0b57cec5SDimitry Andric else if (Str.equals_lower("fe")) 165*0b57cec5SDimitry Andric IsIRInstr = false; 166*0b57cec5SDimitry Andric else if (Str.equals_lower("csir")) { 167*0b57cec5SDimitry Andric IsIRInstr = true; 168*0b57cec5SDimitry Andric HasCSIRLevelProfile = true; 169*0b57cec5SDimitry Andric } else 170*0b57cec5SDimitry Andric return error(instrprof_error::bad_header); 171*0b57cec5SDimitry Andric 172*0b57cec5SDimitry Andric ++Line; 173*0b57cec5SDimitry Andric IsIRLevelProfile = IsIRInstr; 174*0b57cec5SDimitry Andric return success(); 175*0b57cec5SDimitry Andric } 176*0b57cec5SDimitry Andric 177*0b57cec5SDimitry Andric Error 178*0b57cec5SDimitry Andric TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric #define CHECK_LINE_END(Line) \ 181*0b57cec5SDimitry Andric if (Line.is_at_end()) \ 182*0b57cec5SDimitry Andric return error(instrprof_error::truncated); 183*0b57cec5SDimitry Andric #define READ_NUM(Str, Dst) \ 184*0b57cec5SDimitry Andric if ((Str).getAsInteger(10, (Dst))) \ 185*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 186*0b57cec5SDimitry Andric #define VP_READ_ADVANCE(Val) \ 187*0b57cec5SDimitry Andric CHECK_LINE_END(Line); \ 188*0b57cec5SDimitry Andric uint32_t Val; \ 189*0b57cec5SDimitry Andric READ_NUM((*Line), (Val)); \ 190*0b57cec5SDimitry Andric Line++; 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric if (Line.is_at_end()) 193*0b57cec5SDimitry Andric return success(); 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric uint32_t NumValueKinds; 196*0b57cec5SDimitry Andric if (Line->getAsInteger(10, NumValueKinds)) { 197*0b57cec5SDimitry Andric // No value profile data 198*0b57cec5SDimitry Andric return success(); 199*0b57cec5SDimitry Andric } 200*0b57cec5SDimitry Andric if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1) 201*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 202*0b57cec5SDimitry Andric Line++; 203*0b57cec5SDimitry Andric 204*0b57cec5SDimitry Andric for (uint32_t VK = 0; VK < NumValueKinds; VK++) { 205*0b57cec5SDimitry Andric VP_READ_ADVANCE(ValueKind); 206*0b57cec5SDimitry Andric if (ValueKind > IPVK_Last) 207*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 208*0b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueSites); 209*0b57cec5SDimitry Andric if (!NumValueSites) 210*0b57cec5SDimitry Andric continue; 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric Record.reserveSites(VK, NumValueSites); 213*0b57cec5SDimitry Andric for (uint32_t S = 0; S < NumValueSites; S++) { 214*0b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueData); 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric std::vector<InstrProfValueData> CurrentValues; 217*0b57cec5SDimitry Andric for (uint32_t V = 0; V < NumValueData; V++) { 218*0b57cec5SDimitry Andric CHECK_LINE_END(Line); 219*0b57cec5SDimitry Andric std::pair<StringRef, StringRef> VD = Line->rsplit(':'); 220*0b57cec5SDimitry Andric uint64_t TakenCount, Value; 221*0b57cec5SDimitry Andric if (ValueKind == IPVK_IndirectCallTarget) { 222*0b57cec5SDimitry Andric if (InstrProfSymtab::isExternalSymbol(VD.first)) { 223*0b57cec5SDimitry Andric Value = 0; 224*0b57cec5SDimitry Andric } else { 225*0b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(VD.first)) 226*0b57cec5SDimitry Andric return E; 227*0b57cec5SDimitry Andric Value = IndexedInstrProf::ComputeHash(VD.first); 228*0b57cec5SDimitry Andric } 229*0b57cec5SDimitry Andric } else { 230*0b57cec5SDimitry Andric READ_NUM(VD.first, Value); 231*0b57cec5SDimitry Andric } 232*0b57cec5SDimitry Andric READ_NUM(VD.second, TakenCount); 233*0b57cec5SDimitry Andric CurrentValues.push_back({Value, TakenCount}); 234*0b57cec5SDimitry Andric Line++; 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData, 237*0b57cec5SDimitry Andric nullptr); 238*0b57cec5SDimitry Andric } 239*0b57cec5SDimitry Andric } 240*0b57cec5SDimitry Andric return success(); 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric #undef CHECK_LINE_END 243*0b57cec5SDimitry Andric #undef READ_NUM 244*0b57cec5SDimitry Andric #undef VP_READ_ADVANCE 245*0b57cec5SDimitry Andric } 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { 248*0b57cec5SDimitry Andric // Skip empty lines and comments. 249*0b57cec5SDimitry Andric while (!Line.is_at_end() && (Line->empty() || Line->startswith("#"))) 250*0b57cec5SDimitry Andric ++Line; 251*0b57cec5SDimitry Andric // If we hit EOF while looking for a name, we're done. 252*0b57cec5SDimitry Andric if (Line.is_at_end()) { 253*0b57cec5SDimitry Andric return error(instrprof_error::eof); 254*0b57cec5SDimitry Andric } 255*0b57cec5SDimitry Andric 256*0b57cec5SDimitry Andric // Read the function name. 257*0b57cec5SDimitry Andric Record.Name = *Line++; 258*0b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(Record.Name)) 259*0b57cec5SDimitry Andric return error(std::move(E)); 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric // Read the function hash. 262*0b57cec5SDimitry Andric if (Line.is_at_end()) 263*0b57cec5SDimitry Andric return error(instrprof_error::truncated); 264*0b57cec5SDimitry Andric if ((Line++)->getAsInteger(0, Record.Hash)) 265*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric // Read the number of counters. 268*0b57cec5SDimitry Andric uint64_t NumCounters; 269*0b57cec5SDimitry Andric if (Line.is_at_end()) 270*0b57cec5SDimitry Andric return error(instrprof_error::truncated); 271*0b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, NumCounters)) 272*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 273*0b57cec5SDimitry Andric if (NumCounters == 0) 274*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 275*0b57cec5SDimitry Andric 276*0b57cec5SDimitry Andric // Read each counter and fill our internal storage with the values. 277*0b57cec5SDimitry Andric Record.Clear(); 278*0b57cec5SDimitry Andric Record.Counts.reserve(NumCounters); 279*0b57cec5SDimitry Andric for (uint64_t I = 0; I < NumCounters; ++I) { 280*0b57cec5SDimitry Andric if (Line.is_at_end()) 281*0b57cec5SDimitry Andric return error(instrprof_error::truncated); 282*0b57cec5SDimitry Andric uint64_t Count; 283*0b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, Count)) 284*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 285*0b57cec5SDimitry Andric Record.Counts.push_back(Count); 286*0b57cec5SDimitry Andric } 287*0b57cec5SDimitry Andric 288*0b57cec5SDimitry Andric // Check if value profile data exists and read it if so. 289*0b57cec5SDimitry Andric if (Error E = readValueProfileData(Record)) 290*0b57cec5SDimitry Andric return error(std::move(E)); 291*0b57cec5SDimitry Andric 292*0b57cec5SDimitry Andric return success(); 293*0b57cec5SDimitry Andric } 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric template <class IntPtrT> 296*0b57cec5SDimitry Andric bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { 297*0b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < sizeof(uint64_t)) 298*0b57cec5SDimitry Andric return false; 299*0b57cec5SDimitry Andric uint64_t Magic = 300*0b57cec5SDimitry Andric *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); 301*0b57cec5SDimitry Andric return RawInstrProf::getMagic<IntPtrT>() == Magic || 302*0b57cec5SDimitry Andric sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic; 303*0b57cec5SDimitry Andric } 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric template <class IntPtrT> 306*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader() { 307*0b57cec5SDimitry Andric if (!hasFormat(*DataBuffer)) 308*0b57cec5SDimitry Andric return error(instrprof_error::bad_magic); 309*0b57cec5SDimitry Andric if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header)) 310*0b57cec5SDimitry Andric return error(instrprof_error::bad_header); 311*0b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>( 312*0b57cec5SDimitry Andric DataBuffer->getBufferStart()); 313*0b57cec5SDimitry Andric ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>(); 314*0b57cec5SDimitry Andric return readHeader(*Header); 315*0b57cec5SDimitry Andric } 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric template <class IntPtrT> 318*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) { 319*0b57cec5SDimitry Andric const char *End = DataBuffer->getBufferEnd(); 320*0b57cec5SDimitry Andric // Skip zero padding between profiles. 321*0b57cec5SDimitry Andric while (CurrentPos != End && *CurrentPos == 0) 322*0b57cec5SDimitry Andric ++CurrentPos; 323*0b57cec5SDimitry Andric // If there's nothing left, we're done. 324*0b57cec5SDimitry Andric if (CurrentPos == End) 325*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof); 326*0b57cec5SDimitry Andric // If there isn't enough space for another header, this is probably just 327*0b57cec5SDimitry Andric // garbage at the end of the file. 328*0b57cec5SDimitry Andric if (CurrentPos + sizeof(RawInstrProf::Header) > End) 329*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 330*0b57cec5SDimitry Andric // The writer ensures each profile is padded to start at an aligned address. 331*0b57cec5SDimitry Andric if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t)) 332*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 333*0b57cec5SDimitry Andric // The magic should have the same byte order as in the previous header. 334*0b57cec5SDimitry Andric uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos); 335*0b57cec5SDimitry Andric if (Magic != swap(RawInstrProf::getMagic<IntPtrT>())) 336*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic); 337*0b57cec5SDimitry Andric 338*0b57cec5SDimitry Andric // There's another profile to read, so we need to process the header. 339*0b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos); 340*0b57cec5SDimitry Andric return readHeader(*Header); 341*0b57cec5SDimitry Andric } 342*0b57cec5SDimitry Andric 343*0b57cec5SDimitry Andric template <class IntPtrT> 344*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { 345*0b57cec5SDimitry Andric if (Error E = Symtab.create(StringRef(NamesStart, NamesSize))) 346*0b57cec5SDimitry Andric return error(std::move(E)); 347*0b57cec5SDimitry Andric for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) { 348*0b57cec5SDimitry Andric const IntPtrT FPtr = swap(I->FunctionPointer); 349*0b57cec5SDimitry Andric if (!FPtr) 350*0b57cec5SDimitry Andric continue; 351*0b57cec5SDimitry Andric Symtab.mapAddress(FPtr, I->NameRef); 352*0b57cec5SDimitry Andric } 353*0b57cec5SDimitry Andric return success(); 354*0b57cec5SDimitry Andric } 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric template <class IntPtrT> 357*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader( 358*0b57cec5SDimitry Andric const RawInstrProf::Header &Header) { 359*0b57cec5SDimitry Andric Version = swap(Header.Version); 360*0b57cec5SDimitry Andric if (GET_VERSION(Version) != RawInstrProf::Version) 361*0b57cec5SDimitry Andric return error(instrprof_error::unsupported_version); 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric CountersDelta = swap(Header.CountersDelta); 364*0b57cec5SDimitry Andric NamesDelta = swap(Header.NamesDelta); 365*0b57cec5SDimitry Andric auto DataSize = swap(Header.DataSize); 366480093f4SDimitry Andric auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters); 367*0b57cec5SDimitry Andric auto CountersSize = swap(Header.CountersSize); 368480093f4SDimitry Andric auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters); 369*0b57cec5SDimitry Andric NamesSize = swap(Header.NamesSize); 370*0b57cec5SDimitry Andric ValueKindLast = swap(Header.ValueKindLast); 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>); 373*0b57cec5SDimitry Andric auto PaddingSize = getNumPaddingBytes(NamesSize); 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric ptrdiff_t DataOffset = sizeof(RawInstrProf::Header); 376480093f4SDimitry Andric ptrdiff_t CountersOffset = 377480093f4SDimitry Andric DataOffset + DataSizeInBytes + PaddingBytesBeforeCounters; 378480093f4SDimitry Andric ptrdiff_t NamesOffset = CountersOffset + (sizeof(uint64_t) * CountersSize) + 379480093f4SDimitry Andric PaddingBytesAfterCounters; 380*0b57cec5SDimitry Andric ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize; 381*0b57cec5SDimitry Andric 382*0b57cec5SDimitry Andric auto *Start = reinterpret_cast<const char *>(&Header); 383*0b57cec5SDimitry Andric if (Start + ValueDataOffset > DataBuffer->getBufferEnd()) 384*0b57cec5SDimitry Andric return error(instrprof_error::bad_header); 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>( 387*0b57cec5SDimitry Andric Start + DataOffset); 388*0b57cec5SDimitry Andric DataEnd = Data + DataSize; 389*0b57cec5SDimitry Andric CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset); 390*0b57cec5SDimitry Andric NamesStart = Start + NamesOffset; 391*0b57cec5SDimitry Andric ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset); 392*0b57cec5SDimitry Andric 3938bcb0991SDimitry Andric std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>(); 394*0b57cec5SDimitry Andric if (Error E = createSymtab(*NewSymtab.get())) 395*0b57cec5SDimitry Andric return E; 396*0b57cec5SDimitry Andric 397*0b57cec5SDimitry Andric Symtab = std::move(NewSymtab); 398*0b57cec5SDimitry Andric return success(); 399*0b57cec5SDimitry Andric } 400*0b57cec5SDimitry Andric 401*0b57cec5SDimitry Andric template <class IntPtrT> 402*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) { 403*0b57cec5SDimitry Andric Record.Name = getName(Data->NameRef); 404*0b57cec5SDimitry Andric return success(); 405*0b57cec5SDimitry Andric } 406*0b57cec5SDimitry Andric 407*0b57cec5SDimitry Andric template <class IntPtrT> 408*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) { 409*0b57cec5SDimitry Andric Record.Hash = swap(Data->FuncHash); 410*0b57cec5SDimitry Andric return success(); 411*0b57cec5SDimitry Andric } 412*0b57cec5SDimitry Andric 413*0b57cec5SDimitry Andric template <class IntPtrT> 414*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawCounts( 415*0b57cec5SDimitry Andric InstrProfRecord &Record) { 416*0b57cec5SDimitry Andric uint32_t NumCounters = swap(Data->NumCounters); 417*0b57cec5SDimitry Andric IntPtrT CounterPtr = Data->CounterPtr; 418*0b57cec5SDimitry Andric if (NumCounters == 0) 419*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 420*0b57cec5SDimitry Andric 421*0b57cec5SDimitry Andric auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); 4228bcb0991SDimitry Andric ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart; 423*0b57cec5SDimitry Andric 4248bcb0991SDimitry Andric // Check bounds. Note that the counter pointer embedded in the data record 4258bcb0991SDimitry Andric // may itself be corrupt. 4265ffd83dbSDimitry Andric if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters) 427*0b57cec5SDimitry Andric return error(instrprof_error::malformed); 4288bcb0991SDimitry Andric ptrdiff_t CounterOffset = getCounterOffset(CounterPtr); 4298bcb0991SDimitry Andric if (CounterOffset < 0 || CounterOffset > MaxNumCounters || 4305ffd83dbSDimitry Andric ((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters) 4318bcb0991SDimitry Andric return error(instrprof_error::malformed); 4328bcb0991SDimitry Andric 4338bcb0991SDimitry Andric auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters); 434*0b57cec5SDimitry Andric 435*0b57cec5SDimitry Andric if (ShouldSwapBytes) { 436*0b57cec5SDimitry Andric Record.Counts.clear(); 437*0b57cec5SDimitry Andric Record.Counts.reserve(RawCounts.size()); 438*0b57cec5SDimitry Andric for (uint64_t Count : RawCounts) 439*0b57cec5SDimitry Andric Record.Counts.push_back(swap(Count)); 440*0b57cec5SDimitry Andric } else 441*0b57cec5SDimitry Andric Record.Counts = RawCounts; 442*0b57cec5SDimitry Andric 443*0b57cec5SDimitry Andric return success(); 444*0b57cec5SDimitry Andric } 445*0b57cec5SDimitry Andric 446*0b57cec5SDimitry Andric template <class IntPtrT> 447*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readValueProfilingData( 448*0b57cec5SDimitry Andric InstrProfRecord &Record) { 449*0b57cec5SDimitry Andric Record.clearValueData(); 450*0b57cec5SDimitry Andric CurValueDataSize = 0; 451*0b57cec5SDimitry Andric // Need to match the logic in value profile dumper code in compiler-rt: 452*0b57cec5SDimitry Andric uint32_t NumValueKinds = 0; 453*0b57cec5SDimitry Andric for (uint32_t I = 0; I < IPVK_Last + 1; I++) 454*0b57cec5SDimitry Andric NumValueKinds += (Data->NumValueSites[I] != 0); 455*0b57cec5SDimitry Andric 456*0b57cec5SDimitry Andric if (!NumValueKinds) 457*0b57cec5SDimitry Andric return success(); 458*0b57cec5SDimitry Andric 459*0b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 460*0b57cec5SDimitry Andric ValueProfData::getValueProfData( 461*0b57cec5SDimitry Andric ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(), 462*0b57cec5SDimitry Andric getDataEndianness()); 463*0b57cec5SDimitry Andric 464*0b57cec5SDimitry Andric if (Error E = VDataPtrOrErr.takeError()) 465*0b57cec5SDimitry Andric return E; 466*0b57cec5SDimitry Andric 467*0b57cec5SDimitry Andric // Note that besides deserialization, this also performs the conversion for 468*0b57cec5SDimitry Andric // indirect call targets. The function pointers from the raw profile are 469*0b57cec5SDimitry Andric // remapped into function name hashes. 470*0b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get()); 471*0b57cec5SDimitry Andric CurValueDataSize = VDataPtrOrErr.get()->getSize(); 472*0b57cec5SDimitry Andric return success(); 473*0b57cec5SDimitry Andric } 474*0b57cec5SDimitry Andric 475*0b57cec5SDimitry Andric template <class IntPtrT> 476*0b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) { 477*0b57cec5SDimitry Andric if (atEnd()) 478*0b57cec5SDimitry Andric // At this point, ValueDataStart field points to the next header. 479*0b57cec5SDimitry Andric if (Error E = readNextHeader(getNextHeaderPos())) 480*0b57cec5SDimitry Andric return error(std::move(E)); 481*0b57cec5SDimitry Andric 482*0b57cec5SDimitry Andric // Read name ad set it in Record. 483*0b57cec5SDimitry Andric if (Error E = readName(Record)) 484*0b57cec5SDimitry Andric return error(std::move(E)); 485*0b57cec5SDimitry Andric 486*0b57cec5SDimitry Andric // Read FuncHash and set it in Record. 487*0b57cec5SDimitry Andric if (Error E = readFuncHash(Record)) 488*0b57cec5SDimitry Andric return error(std::move(E)); 489*0b57cec5SDimitry Andric 490*0b57cec5SDimitry Andric // Read raw counts and set Record. 491*0b57cec5SDimitry Andric if (Error E = readRawCounts(Record)) 492*0b57cec5SDimitry Andric return error(std::move(E)); 493*0b57cec5SDimitry Andric 494*0b57cec5SDimitry Andric // Read value data and set Record. 495*0b57cec5SDimitry Andric if (Error E = readValueProfilingData(Record)) 496*0b57cec5SDimitry Andric return error(std::move(E)); 497*0b57cec5SDimitry Andric 498*0b57cec5SDimitry Andric // Iterate. 499*0b57cec5SDimitry Andric advanceData(); 500*0b57cec5SDimitry Andric return success(); 501*0b57cec5SDimitry Andric } 502*0b57cec5SDimitry Andric 503*0b57cec5SDimitry Andric namespace llvm { 504*0b57cec5SDimitry Andric 505*0b57cec5SDimitry Andric template class RawInstrProfReader<uint32_t>; 506*0b57cec5SDimitry Andric template class RawInstrProfReader<uint64_t>; 507*0b57cec5SDimitry Andric 508*0b57cec5SDimitry Andric } // end namespace llvm 509*0b57cec5SDimitry Andric 510*0b57cec5SDimitry Andric InstrProfLookupTrait::hash_value_type 511*0b57cec5SDimitry Andric InstrProfLookupTrait::ComputeHash(StringRef K) { 512*0b57cec5SDimitry Andric return IndexedInstrProf::ComputeHash(HashType, K); 513*0b57cec5SDimitry Andric } 514*0b57cec5SDimitry Andric 515*0b57cec5SDimitry Andric using data_type = InstrProfLookupTrait::data_type; 516*0b57cec5SDimitry Andric using offset_type = InstrProfLookupTrait::offset_type; 517*0b57cec5SDimitry Andric 518*0b57cec5SDimitry Andric bool InstrProfLookupTrait::readValueProfilingData( 519*0b57cec5SDimitry Andric const unsigned char *&D, const unsigned char *const End) { 520*0b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 521*0b57cec5SDimitry Andric ValueProfData::getValueProfData(D, End, ValueProfDataEndianness); 522*0b57cec5SDimitry Andric 523*0b57cec5SDimitry Andric if (VDataPtrOrErr.takeError()) 524*0b57cec5SDimitry Andric return false; 525*0b57cec5SDimitry Andric 526*0b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr); 527*0b57cec5SDimitry Andric D += VDataPtrOrErr.get()->TotalSize; 528*0b57cec5SDimitry Andric 529*0b57cec5SDimitry Andric return true; 530*0b57cec5SDimitry Andric } 531*0b57cec5SDimitry Andric 532*0b57cec5SDimitry Andric data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, 533*0b57cec5SDimitry Andric offset_type N) { 534*0b57cec5SDimitry Andric using namespace support; 535*0b57cec5SDimitry Andric 536*0b57cec5SDimitry Andric // Check if the data is corrupt. If so, don't try to read it. 537*0b57cec5SDimitry Andric if (N % sizeof(uint64_t)) 538*0b57cec5SDimitry Andric return data_type(); 539*0b57cec5SDimitry Andric 540*0b57cec5SDimitry Andric DataBuffer.clear(); 541*0b57cec5SDimitry Andric std::vector<uint64_t> CounterBuffer; 542*0b57cec5SDimitry Andric 543*0b57cec5SDimitry Andric const unsigned char *End = D + N; 544*0b57cec5SDimitry Andric while (D < End) { 545*0b57cec5SDimitry Andric // Read hash. 546*0b57cec5SDimitry Andric if (D + sizeof(uint64_t) >= End) 547*0b57cec5SDimitry Andric return data_type(); 548*0b57cec5SDimitry Andric uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D); 549*0b57cec5SDimitry Andric 550*0b57cec5SDimitry Andric // Initialize number of counters for GET_VERSION(FormatVersion) == 1. 551*0b57cec5SDimitry Andric uint64_t CountsSize = N / sizeof(uint64_t) - 1; 552*0b57cec5SDimitry Andric // If format version is different then read the number of counters. 553*0b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) { 554*0b57cec5SDimitry Andric if (D + sizeof(uint64_t) > End) 555*0b57cec5SDimitry Andric return data_type(); 556*0b57cec5SDimitry Andric CountsSize = endian::readNext<uint64_t, little, unaligned>(D); 557*0b57cec5SDimitry Andric } 558*0b57cec5SDimitry Andric // Read counter values. 559*0b57cec5SDimitry Andric if (D + CountsSize * sizeof(uint64_t) > End) 560*0b57cec5SDimitry Andric return data_type(); 561*0b57cec5SDimitry Andric 562*0b57cec5SDimitry Andric CounterBuffer.clear(); 563*0b57cec5SDimitry Andric CounterBuffer.reserve(CountsSize); 564*0b57cec5SDimitry Andric for (uint64_t J = 0; J < CountsSize; ++J) 565*0b57cec5SDimitry Andric CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D)); 566*0b57cec5SDimitry Andric 567*0b57cec5SDimitry Andric DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer)); 568*0b57cec5SDimitry Andric 569*0b57cec5SDimitry Andric // Read value profiling data. 570*0b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 && 571*0b57cec5SDimitry Andric !readValueProfilingData(D, End)) { 572*0b57cec5SDimitry Andric DataBuffer.clear(); 573*0b57cec5SDimitry Andric return data_type(); 574*0b57cec5SDimitry Andric } 575*0b57cec5SDimitry Andric } 576*0b57cec5SDimitry Andric return DataBuffer; 577*0b57cec5SDimitry Andric } 578*0b57cec5SDimitry Andric 579*0b57cec5SDimitry Andric template <typename HashTableImpl> 580*0b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords( 581*0b57cec5SDimitry Andric StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) { 582*0b57cec5SDimitry Andric auto Iter = HashTable->find(FuncName); 583*0b57cec5SDimitry Andric if (Iter == HashTable->end()) 584*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unknown_function); 585*0b57cec5SDimitry Andric 586*0b57cec5SDimitry Andric Data = (*Iter); 587*0b57cec5SDimitry Andric if (Data.empty()) 588*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 589*0b57cec5SDimitry Andric 590*0b57cec5SDimitry Andric return Error::success(); 591*0b57cec5SDimitry Andric } 592*0b57cec5SDimitry Andric 593*0b57cec5SDimitry Andric template <typename HashTableImpl> 594*0b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords( 595*0b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) { 596*0b57cec5SDimitry Andric if (atEnd()) 597*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof); 598*0b57cec5SDimitry Andric 599*0b57cec5SDimitry Andric Data = *RecordIterator; 600*0b57cec5SDimitry Andric 601*0b57cec5SDimitry Andric if (Data.empty()) 602*0b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 603*0b57cec5SDimitry Andric 604*0b57cec5SDimitry Andric return Error::success(); 605*0b57cec5SDimitry Andric } 606*0b57cec5SDimitry Andric 607*0b57cec5SDimitry Andric template <typename HashTableImpl> 608*0b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex( 609*0b57cec5SDimitry Andric const unsigned char *Buckets, const unsigned char *const Payload, 610*0b57cec5SDimitry Andric const unsigned char *const Base, IndexedInstrProf::HashT HashType, 611*0b57cec5SDimitry Andric uint64_t Version) { 612*0b57cec5SDimitry Andric FormatVersion = Version; 613*0b57cec5SDimitry Andric HashTable.reset(HashTableImpl::Create( 614*0b57cec5SDimitry Andric Buckets, Payload, Base, 615*0b57cec5SDimitry Andric typename HashTableImpl::InfoType(HashType, Version))); 616*0b57cec5SDimitry Andric RecordIterator = HashTable->data_begin(); 617*0b57cec5SDimitry Andric } 618*0b57cec5SDimitry Andric 619*0b57cec5SDimitry Andric namespace { 620*0b57cec5SDimitry Andric /// A remapper that does not apply any remappings. 621*0b57cec5SDimitry Andric class InstrProfReaderNullRemapper : public InstrProfReaderRemapper { 622*0b57cec5SDimitry Andric InstrProfReaderIndexBase &Underlying; 623*0b57cec5SDimitry Andric 624*0b57cec5SDimitry Andric public: 625*0b57cec5SDimitry Andric InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying) 626*0b57cec5SDimitry Andric : Underlying(Underlying) {} 627*0b57cec5SDimitry Andric 628*0b57cec5SDimitry Andric Error getRecords(StringRef FuncName, 629*0b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override { 630*0b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data); 631*0b57cec5SDimitry Andric } 632*0b57cec5SDimitry Andric }; 633*0b57cec5SDimitry Andric } 634*0b57cec5SDimitry Andric 635*0b57cec5SDimitry Andric /// A remapper that applies remappings based on a symbol remapping file. 636*0b57cec5SDimitry Andric template <typename HashTableImpl> 637*0b57cec5SDimitry Andric class llvm::InstrProfReaderItaniumRemapper 638*0b57cec5SDimitry Andric : public InstrProfReaderRemapper { 639*0b57cec5SDimitry Andric public: 640*0b57cec5SDimitry Andric InstrProfReaderItaniumRemapper( 641*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer, 642*0b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying) 643*0b57cec5SDimitry Andric : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) { 644*0b57cec5SDimitry Andric } 645*0b57cec5SDimitry Andric 646*0b57cec5SDimitry Andric /// Extract the original function name from a PGO function name. 647*0b57cec5SDimitry Andric static StringRef extractName(StringRef Name) { 648*0b57cec5SDimitry Andric // We can have multiple :-separated pieces; there can be pieces both 649*0b57cec5SDimitry Andric // before and after the mangled name. Find the first part that starts 650*0b57cec5SDimitry Andric // with '_Z'; we'll assume that's the mangled name we want. 651*0b57cec5SDimitry Andric std::pair<StringRef, StringRef> Parts = {StringRef(), Name}; 652*0b57cec5SDimitry Andric while (true) { 653*0b57cec5SDimitry Andric Parts = Parts.second.split(':'); 654*0b57cec5SDimitry Andric if (Parts.first.startswith("_Z")) 655*0b57cec5SDimitry Andric return Parts.first; 656*0b57cec5SDimitry Andric if (Parts.second.empty()) 657*0b57cec5SDimitry Andric return Name; 658*0b57cec5SDimitry Andric } 659*0b57cec5SDimitry Andric } 660*0b57cec5SDimitry Andric 661*0b57cec5SDimitry Andric /// Given a mangled name extracted from a PGO function name, and a new 662*0b57cec5SDimitry Andric /// form for that mangled name, reconstitute the name. 663*0b57cec5SDimitry Andric static void reconstituteName(StringRef OrigName, StringRef ExtractedName, 664*0b57cec5SDimitry Andric StringRef Replacement, 665*0b57cec5SDimitry Andric SmallVectorImpl<char> &Out) { 666*0b57cec5SDimitry Andric Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size()); 667*0b57cec5SDimitry Andric Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin()); 668*0b57cec5SDimitry Andric Out.insert(Out.end(), Replacement.begin(), Replacement.end()); 669*0b57cec5SDimitry Andric Out.insert(Out.end(), ExtractedName.end(), OrigName.end()); 670*0b57cec5SDimitry Andric } 671*0b57cec5SDimitry Andric 672*0b57cec5SDimitry Andric Error populateRemappings() override { 673*0b57cec5SDimitry Andric if (Error E = Remappings.read(*RemapBuffer)) 674*0b57cec5SDimitry Andric return E; 675*0b57cec5SDimitry Andric for (StringRef Name : Underlying.HashTable->keys()) { 676*0b57cec5SDimitry Andric StringRef RealName = extractName(Name); 677*0b57cec5SDimitry Andric if (auto Key = Remappings.insert(RealName)) { 678*0b57cec5SDimitry Andric // FIXME: We could theoretically map the same equivalence class to 679*0b57cec5SDimitry Andric // multiple names in the profile data. If that happens, we should 680*0b57cec5SDimitry Andric // return NamedInstrProfRecords from all of them. 681*0b57cec5SDimitry Andric MappedNames.insert({Key, RealName}); 682*0b57cec5SDimitry Andric } 683*0b57cec5SDimitry Andric } 684*0b57cec5SDimitry Andric return Error::success(); 685*0b57cec5SDimitry Andric } 686*0b57cec5SDimitry Andric 687*0b57cec5SDimitry Andric Error getRecords(StringRef FuncName, 688*0b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override { 689*0b57cec5SDimitry Andric StringRef RealName = extractName(FuncName); 690*0b57cec5SDimitry Andric if (auto Key = Remappings.lookup(RealName)) { 691*0b57cec5SDimitry Andric StringRef Remapped = MappedNames.lookup(Key); 692*0b57cec5SDimitry Andric if (!Remapped.empty()) { 693*0b57cec5SDimitry Andric if (RealName.begin() == FuncName.begin() && 694*0b57cec5SDimitry Andric RealName.end() == FuncName.end()) 695*0b57cec5SDimitry Andric FuncName = Remapped; 696*0b57cec5SDimitry Andric else { 697*0b57cec5SDimitry Andric // Try rebuilding the name from the given remapping. 698*0b57cec5SDimitry Andric SmallString<256> Reconstituted; 699*0b57cec5SDimitry Andric reconstituteName(FuncName, RealName, Remapped, Reconstituted); 700*0b57cec5SDimitry Andric Error E = Underlying.getRecords(Reconstituted, Data); 701*0b57cec5SDimitry Andric if (!E) 702*0b57cec5SDimitry Andric return E; 703*0b57cec5SDimitry Andric 704*0b57cec5SDimitry Andric // If we failed because the name doesn't exist, fall back to asking 705*0b57cec5SDimitry Andric // about the original name. 706*0b57cec5SDimitry Andric if (Error Unhandled = handleErrors( 707*0b57cec5SDimitry Andric std::move(E), [](std::unique_ptr<InstrProfError> Err) { 708*0b57cec5SDimitry Andric return Err->get() == instrprof_error::unknown_function 709*0b57cec5SDimitry Andric ? Error::success() 710*0b57cec5SDimitry Andric : Error(std::move(Err)); 711*0b57cec5SDimitry Andric })) 712*0b57cec5SDimitry Andric return Unhandled; 713*0b57cec5SDimitry Andric } 714*0b57cec5SDimitry Andric } 715*0b57cec5SDimitry Andric } 716*0b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data); 717*0b57cec5SDimitry Andric } 718*0b57cec5SDimitry Andric 719*0b57cec5SDimitry Andric private: 720*0b57cec5SDimitry Andric /// The memory buffer containing the remapping configuration. Remappings 721*0b57cec5SDimitry Andric /// holds pointers into this buffer. 722*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer; 723*0b57cec5SDimitry Andric 724*0b57cec5SDimitry Andric /// The mangling remapper. 725*0b57cec5SDimitry Andric SymbolRemappingReader Remappings; 726*0b57cec5SDimitry Andric 727*0b57cec5SDimitry Andric /// Mapping from mangled name keys to the name used for the key in the 728*0b57cec5SDimitry Andric /// profile data. 729*0b57cec5SDimitry Andric /// FIXME: Can we store a location within the on-disk hash table instead of 730*0b57cec5SDimitry Andric /// redoing lookup? 731*0b57cec5SDimitry Andric DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames; 732*0b57cec5SDimitry Andric 733*0b57cec5SDimitry Andric /// The real profile data reader. 734*0b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying; 735*0b57cec5SDimitry Andric }; 736*0b57cec5SDimitry Andric 737*0b57cec5SDimitry Andric bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { 738*0b57cec5SDimitry Andric using namespace support; 739*0b57cec5SDimitry Andric 740*0b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < 8) 741*0b57cec5SDimitry Andric return false; 742*0b57cec5SDimitry Andric uint64_t Magic = 743*0b57cec5SDimitry Andric endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart()); 744*0b57cec5SDimitry Andric // Verify that it's magical. 745*0b57cec5SDimitry Andric return Magic == IndexedInstrProf::Magic; 746*0b57cec5SDimitry Andric } 747*0b57cec5SDimitry Andric 748*0b57cec5SDimitry Andric const unsigned char * 749*0b57cec5SDimitry Andric IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, 750*0b57cec5SDimitry Andric const unsigned char *Cur, bool UseCS) { 751*0b57cec5SDimitry Andric using namespace IndexedInstrProf; 752*0b57cec5SDimitry Andric using namespace support; 753*0b57cec5SDimitry Andric 754*0b57cec5SDimitry Andric if (Version >= IndexedInstrProf::Version4) { 755*0b57cec5SDimitry Andric const IndexedInstrProf::Summary *SummaryInLE = 756*0b57cec5SDimitry Andric reinterpret_cast<const IndexedInstrProf::Summary *>(Cur); 757*0b57cec5SDimitry Andric uint64_t NFields = 758*0b57cec5SDimitry Andric endian::byte_swap<uint64_t, little>(SummaryInLE->NumSummaryFields); 759*0b57cec5SDimitry Andric uint64_t NEntries = 760*0b57cec5SDimitry Andric endian::byte_swap<uint64_t, little>(SummaryInLE->NumCutoffEntries); 761*0b57cec5SDimitry Andric uint32_t SummarySize = 762*0b57cec5SDimitry Andric IndexedInstrProf::Summary::getSize(NFields, NEntries); 763*0b57cec5SDimitry Andric std::unique_ptr<IndexedInstrProf::Summary> SummaryData = 764*0b57cec5SDimitry Andric IndexedInstrProf::allocSummary(SummarySize); 765*0b57cec5SDimitry Andric 766*0b57cec5SDimitry Andric const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE); 767*0b57cec5SDimitry Andric uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get()); 768*0b57cec5SDimitry Andric for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) 769*0b57cec5SDimitry Andric Dst[I] = endian::byte_swap<uint64_t, little>(Src[I]); 770*0b57cec5SDimitry Andric 771*0b57cec5SDimitry Andric SummaryEntryVector DetailedSummary; 772*0b57cec5SDimitry Andric for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) { 773*0b57cec5SDimitry Andric const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I); 774*0b57cec5SDimitry Andric DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount, 775*0b57cec5SDimitry Andric Ent.NumBlocks); 776*0b57cec5SDimitry Andric } 777*0b57cec5SDimitry Andric std::unique_ptr<llvm::ProfileSummary> &Summary = 778*0b57cec5SDimitry Andric UseCS ? this->CS_Summary : this->Summary; 779*0b57cec5SDimitry Andric 780*0b57cec5SDimitry Andric // initialize InstrProfSummary using the SummaryData from disk. 7818bcb0991SDimitry Andric Summary = std::make_unique<ProfileSummary>( 782*0b57cec5SDimitry Andric UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr, 783*0b57cec5SDimitry Andric DetailedSummary, SummaryData->get(Summary::TotalBlockCount), 784*0b57cec5SDimitry Andric SummaryData->get(Summary::MaxBlockCount), 785*0b57cec5SDimitry Andric SummaryData->get(Summary::MaxInternalBlockCount), 786*0b57cec5SDimitry Andric SummaryData->get(Summary::MaxFunctionCount), 787*0b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumBlocks), 788*0b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumFunctions)); 789*0b57cec5SDimitry Andric return Cur + SummarySize; 790*0b57cec5SDimitry Andric } else { 7918bcb0991SDimitry Andric // The older versions do not support a profile summary. This just computes 7928bcb0991SDimitry Andric // an empty summary, which will not result in accurate hot/cold detection. 7938bcb0991SDimitry Andric // We would need to call addRecord for all NamedInstrProfRecords to get the 7948bcb0991SDimitry Andric // correct summary. However, this version is old (prior to early 2016) and 7958bcb0991SDimitry Andric // has not been supporting an accurate summary for several years. 796*0b57cec5SDimitry Andric InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 7978bcb0991SDimitry Andric Summary = Builder.getSummary(); 798*0b57cec5SDimitry Andric return Cur; 799*0b57cec5SDimitry Andric } 800*0b57cec5SDimitry Andric } 801*0b57cec5SDimitry Andric 802*0b57cec5SDimitry Andric Error IndexedInstrProfReader::readHeader() { 803*0b57cec5SDimitry Andric using namespace support; 804*0b57cec5SDimitry Andric 805*0b57cec5SDimitry Andric const unsigned char *Start = 806*0b57cec5SDimitry Andric (const unsigned char *)DataBuffer->getBufferStart(); 807*0b57cec5SDimitry Andric const unsigned char *Cur = Start; 808*0b57cec5SDimitry Andric if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24) 809*0b57cec5SDimitry Andric return error(instrprof_error::truncated); 810*0b57cec5SDimitry Andric 811*0b57cec5SDimitry Andric auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur); 812*0b57cec5SDimitry Andric Cur += sizeof(IndexedInstrProf::Header); 813*0b57cec5SDimitry Andric 814*0b57cec5SDimitry Andric // Check the magic number. 815*0b57cec5SDimitry Andric uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic); 816*0b57cec5SDimitry Andric if (Magic != IndexedInstrProf::Magic) 817*0b57cec5SDimitry Andric return error(instrprof_error::bad_magic); 818*0b57cec5SDimitry Andric 819*0b57cec5SDimitry Andric // Read the version. 820*0b57cec5SDimitry Andric uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version); 821*0b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) > 822*0b57cec5SDimitry Andric IndexedInstrProf::ProfVersion::CurrentVersion) 823*0b57cec5SDimitry Andric return error(instrprof_error::unsupported_version); 824*0b57cec5SDimitry Andric 825*0b57cec5SDimitry Andric Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, 826*0b57cec5SDimitry Andric /* UseCS */ false); 827*0b57cec5SDimitry Andric if (FormatVersion & VARIANT_MASK_CSIR_PROF) 828*0b57cec5SDimitry Andric Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, 829*0b57cec5SDimitry Andric /* UseCS */ true); 830*0b57cec5SDimitry Andric 831*0b57cec5SDimitry Andric // Read the hash type and start offset. 832*0b57cec5SDimitry Andric IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>( 833*0b57cec5SDimitry Andric endian::byte_swap<uint64_t, little>(Header->HashType)); 834*0b57cec5SDimitry Andric if (HashType > IndexedInstrProf::HashT::Last) 835*0b57cec5SDimitry Andric return error(instrprof_error::unsupported_hash_type); 836*0b57cec5SDimitry Andric 837*0b57cec5SDimitry Andric uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset); 838*0b57cec5SDimitry Andric 839*0b57cec5SDimitry Andric // The rest of the file is an on disk hash table. 840*0b57cec5SDimitry Andric auto IndexPtr = 8418bcb0991SDimitry Andric std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>( 842*0b57cec5SDimitry Andric Start + HashOffset, Cur, Start, HashType, FormatVersion); 843*0b57cec5SDimitry Andric 844*0b57cec5SDimitry Andric // Load the remapping table now if requested. 845*0b57cec5SDimitry Andric if (RemappingBuffer) { 8468bcb0991SDimitry Andric Remapper = std::make_unique< 847*0b57cec5SDimitry Andric InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>( 848*0b57cec5SDimitry Andric std::move(RemappingBuffer), *IndexPtr); 849*0b57cec5SDimitry Andric if (Error E = Remapper->populateRemappings()) 850*0b57cec5SDimitry Andric return E; 851*0b57cec5SDimitry Andric } else { 8528bcb0991SDimitry Andric Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr); 853*0b57cec5SDimitry Andric } 854*0b57cec5SDimitry Andric Index = std::move(IndexPtr); 855*0b57cec5SDimitry Andric 856*0b57cec5SDimitry Andric return success(); 857*0b57cec5SDimitry Andric } 858*0b57cec5SDimitry Andric 859*0b57cec5SDimitry Andric InstrProfSymtab &IndexedInstrProfReader::getSymtab() { 860*0b57cec5SDimitry Andric if (Symtab.get()) 861*0b57cec5SDimitry Andric return *Symtab.get(); 862*0b57cec5SDimitry Andric 8638bcb0991SDimitry Andric std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>(); 864*0b57cec5SDimitry Andric if (Error E = Index->populateSymtab(*NewSymtab.get())) { 865*0b57cec5SDimitry Andric consumeError(error(InstrProfError::take(std::move(E)))); 866*0b57cec5SDimitry Andric } 867*0b57cec5SDimitry Andric 868*0b57cec5SDimitry Andric Symtab = std::move(NewSymtab); 869*0b57cec5SDimitry Andric return *Symtab.get(); 870*0b57cec5SDimitry Andric } 871*0b57cec5SDimitry Andric 872*0b57cec5SDimitry Andric Expected<InstrProfRecord> 873*0b57cec5SDimitry Andric IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, 874*0b57cec5SDimitry Andric uint64_t FuncHash) { 875*0b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data; 876*0b57cec5SDimitry Andric Error Err = Remapper->getRecords(FuncName, Data); 877*0b57cec5SDimitry Andric if (Err) 878*0b57cec5SDimitry Andric return std::move(Err); 879*0b57cec5SDimitry Andric // Found it. Look for counters with the right hash. 880*0b57cec5SDimitry Andric for (unsigned I = 0, E = Data.size(); I < E; ++I) { 881*0b57cec5SDimitry Andric // Check for a match and fill the vector if there is one. 882*0b57cec5SDimitry Andric if (Data[I].Hash == FuncHash) { 883*0b57cec5SDimitry Andric return std::move(Data[I]); 884*0b57cec5SDimitry Andric } 885*0b57cec5SDimitry Andric } 886*0b57cec5SDimitry Andric return error(instrprof_error::hash_mismatch); 887*0b57cec5SDimitry Andric } 888*0b57cec5SDimitry Andric 889*0b57cec5SDimitry Andric Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, 890*0b57cec5SDimitry Andric uint64_t FuncHash, 891*0b57cec5SDimitry Andric std::vector<uint64_t> &Counts) { 892*0b57cec5SDimitry Andric Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash); 893*0b57cec5SDimitry Andric if (Error E = Record.takeError()) 894*0b57cec5SDimitry Andric return error(std::move(E)); 895*0b57cec5SDimitry Andric 896*0b57cec5SDimitry Andric Counts = Record.get().Counts; 897*0b57cec5SDimitry Andric return success(); 898*0b57cec5SDimitry Andric } 899*0b57cec5SDimitry Andric 900*0b57cec5SDimitry Andric Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { 901*0b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data; 902*0b57cec5SDimitry Andric 903*0b57cec5SDimitry Andric Error E = Index->getRecords(Data); 904*0b57cec5SDimitry Andric if (E) 905*0b57cec5SDimitry Andric return error(std::move(E)); 906*0b57cec5SDimitry Andric 907*0b57cec5SDimitry Andric Record = Data[RecordIndex++]; 908*0b57cec5SDimitry Andric if (RecordIndex >= Data.size()) { 909*0b57cec5SDimitry Andric Index->advanceToNextKey(); 910*0b57cec5SDimitry Andric RecordIndex = 0; 911*0b57cec5SDimitry Andric } 912*0b57cec5SDimitry Andric return success(); 913*0b57cec5SDimitry Andric } 914*0b57cec5SDimitry Andric 9158bcb0991SDimitry Andric void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) { 916*0b57cec5SDimitry Andric uint64_t NumFuncs = 0; 917*0b57cec5SDimitry Andric for (const auto &Func : *this) { 918*0b57cec5SDimitry Andric if (isIRLevelProfile()) { 919*0b57cec5SDimitry Andric bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash); 920*0b57cec5SDimitry Andric if (FuncIsCS != IsCS) 921*0b57cec5SDimitry Andric continue; 922*0b57cec5SDimitry Andric } 9238bcb0991SDimitry Andric Func.accumulateCounts(Sum); 924*0b57cec5SDimitry Andric ++NumFuncs; 925*0b57cec5SDimitry Andric } 926*0b57cec5SDimitry Andric Sum.NumEntries = NumFuncs; 927*0b57cec5SDimitry Andric } 928