10b57cec5SDimitry Andric //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains support for reading profiling data for clang's 100b57cec5SDimitry Andric // instrumentation based PGO and coverage. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h" 150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 160b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 175ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 190b57cec5SDimitry Andric #include "llvm/IR/ProfileSummary.h" 200b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 2181ad6265SDimitry Andric #include "llvm/ProfileData/MemProf.h" 220b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 2306c3fb27SDimitry Andric #include "llvm/ProfileData/SymbolRemappingReader.h" 240b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 250b57cec5SDimitry Andric #include "llvm/Support/Error.h" 260b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 27*0fca6ea1SDimitry Andric #include "llvm/Support/FormatVariadic.h" 280b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 290b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h" 3006c3fb27SDimitry Andric #include "llvm/Support/VirtualFileSystem.h" 310b57cec5SDimitry Andric #include <algorithm> 320b57cec5SDimitry Andric #include <cstddef> 330b57cec5SDimitry Andric #include <cstdint> 340b57cec5SDimitry Andric #include <limits> 350b57cec5SDimitry Andric #include <memory> 36*0fca6ea1SDimitry Andric #include <optional> 370b57cec5SDimitry Andric #include <system_error> 380b57cec5SDimitry Andric #include <utility> 390b57cec5SDimitry Andric #include <vector> 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric using namespace llvm; 420b57cec5SDimitry Andric 435f757f3fSDimitry Andric // Extracts the variant information from the top 32 bits in the version and 441fd87a68SDimitry Andric // returns an enum specifying the variants present. 451fd87a68SDimitry Andric static InstrProfKind getProfileKindFromVersion(uint64_t Version) { 461fd87a68SDimitry Andric InstrProfKind ProfileKind = InstrProfKind::Unknown; 471fd87a68SDimitry Andric if (Version & VARIANT_MASK_IR_PROF) { 4881ad6265SDimitry Andric ProfileKind |= InstrProfKind::IRInstrumentation; 491fd87a68SDimitry Andric } 501fd87a68SDimitry Andric if (Version & VARIANT_MASK_CSIR_PROF) { 5181ad6265SDimitry Andric ProfileKind |= InstrProfKind::ContextSensitive; 521fd87a68SDimitry Andric } 531fd87a68SDimitry Andric if (Version & VARIANT_MASK_INSTR_ENTRY) { 5481ad6265SDimitry Andric ProfileKind |= InstrProfKind::FunctionEntryInstrumentation; 551fd87a68SDimitry Andric } 561fd87a68SDimitry Andric if (Version & VARIANT_MASK_BYTE_COVERAGE) { 571fd87a68SDimitry Andric ProfileKind |= InstrProfKind::SingleByteCoverage; 581fd87a68SDimitry Andric } 591fd87a68SDimitry Andric if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) { 601fd87a68SDimitry Andric ProfileKind |= InstrProfKind::FunctionEntryOnly; 611fd87a68SDimitry Andric } 6281ad6265SDimitry Andric if (Version & VARIANT_MASK_MEMPROF) { 6381ad6265SDimitry Andric ProfileKind |= InstrProfKind::MemProf; 6481ad6265SDimitry Andric } 6506c3fb27SDimitry Andric if (Version & VARIANT_MASK_TEMPORAL_PROF) { 6606c3fb27SDimitry Andric ProfileKind |= InstrProfKind::TemporalProfile; 6706c3fb27SDimitry Andric } 681fd87a68SDimitry Andric return ProfileKind; 691fd87a68SDimitry Andric } 701fd87a68SDimitry Andric 710b57cec5SDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>> 7206c3fb27SDimitry Andric setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) { 7306c3fb27SDimitry Andric auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN() 7406c3fb27SDimitry Andric : FS.getBufferForFile(Filename); 750b57cec5SDimitry Andric if (std::error_code EC = BufferOrErr.getError()) 760b57cec5SDimitry Andric return errorCodeToError(EC); 770b57cec5SDimitry Andric return std::move(BufferOrErr.get()); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric static Error initializeReader(InstrProfReader &Reader) { 810b57cec5SDimitry Andric return Reader.readHeader(); 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 84bdd1243dSDimitry Andric /// Read a list of binary ids from a profile that consist of 85bdd1243dSDimitry Andric /// a. uint64_t binary id length 86bdd1243dSDimitry Andric /// b. uint8_t binary id data 87bdd1243dSDimitry Andric /// c. uint8_t padding (if necessary) 88bdd1243dSDimitry Andric /// This function is shared between raw and indexed profiles. 89bdd1243dSDimitry Andric /// Raw profiles are in host-endian format, and indexed profiles are in 90bdd1243dSDimitry Andric /// little-endian format. So, this function takes an argument indicating the 91bdd1243dSDimitry Andric /// associated endian format to read the binary ids correctly. 92bdd1243dSDimitry Andric static Error 93bdd1243dSDimitry Andric readBinaryIdsInternal(const MemoryBuffer &DataBuffer, 94*0fca6ea1SDimitry Andric ArrayRef<uint8_t> BinaryIdsBuffer, 95bdd1243dSDimitry Andric std::vector<llvm::object::BuildID> &BinaryIds, 965f757f3fSDimitry Andric const llvm::endianness Endian) { 97bdd1243dSDimitry Andric using namespace support; 98bdd1243dSDimitry Andric 99*0fca6ea1SDimitry Andric const uint64_t BinaryIdsSize = BinaryIdsBuffer.size(); 100*0fca6ea1SDimitry Andric const uint8_t *BinaryIdsStart = BinaryIdsBuffer.data(); 101*0fca6ea1SDimitry Andric 102bdd1243dSDimitry Andric if (BinaryIdsSize == 0) 103bdd1243dSDimitry Andric return Error::success(); 104bdd1243dSDimitry Andric 105bdd1243dSDimitry Andric const uint8_t *BI = BinaryIdsStart; 106bdd1243dSDimitry Andric const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize; 107bdd1243dSDimitry Andric const uint8_t *End = 108bdd1243dSDimitry Andric reinterpret_cast<const uint8_t *>(DataBuffer.getBufferEnd()); 109bdd1243dSDimitry Andric 110bdd1243dSDimitry Andric while (BI < BIEnd) { 111bdd1243dSDimitry Andric size_t Remaining = BIEnd - BI; 112bdd1243dSDimitry Andric // There should be enough left to read the binary id length. 113bdd1243dSDimitry Andric if (Remaining < sizeof(uint64_t)) 114bdd1243dSDimitry Andric return make_error<InstrProfError>( 115bdd1243dSDimitry Andric instrprof_error::malformed, 116bdd1243dSDimitry Andric "not enough data to read binary id length"); 117bdd1243dSDimitry Andric 118*0fca6ea1SDimitry Andric uint64_t BILen = endian::readNext<uint64_t>(BI, Endian); 119bdd1243dSDimitry Andric if (BILen == 0) 120bdd1243dSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed, 121bdd1243dSDimitry Andric "binary id length is 0"); 122bdd1243dSDimitry Andric 123bdd1243dSDimitry Andric Remaining = BIEnd - BI; 124bdd1243dSDimitry Andric // There should be enough left to read the binary id data. 125bdd1243dSDimitry Andric if (Remaining < alignToPowerOf2(BILen, sizeof(uint64_t))) 126bdd1243dSDimitry Andric return make_error<InstrProfError>( 127bdd1243dSDimitry Andric instrprof_error::malformed, "not enough data to read binary id data"); 128bdd1243dSDimitry Andric 129bdd1243dSDimitry Andric // Add binary id to the binary ids list. 130bdd1243dSDimitry Andric BinaryIds.push_back(object::BuildID(BI, BI + BILen)); 131bdd1243dSDimitry Andric 132bdd1243dSDimitry Andric // Increment by binary id data length, which aligned to the size of uint64. 133bdd1243dSDimitry Andric BI += alignToPowerOf2(BILen, sizeof(uint64_t)); 134bdd1243dSDimitry Andric if (BI > End) 135bdd1243dSDimitry Andric return make_error<InstrProfError>( 136bdd1243dSDimitry Andric instrprof_error::malformed, 137bdd1243dSDimitry Andric "binary id section is greater than buffer size"); 138bdd1243dSDimitry Andric } 139bdd1243dSDimitry Andric 140bdd1243dSDimitry Andric return Error::success(); 141bdd1243dSDimitry Andric } 142bdd1243dSDimitry Andric 143*0fca6ea1SDimitry Andric static void printBinaryIdsInternal(raw_ostream &OS, 144*0fca6ea1SDimitry Andric ArrayRef<llvm::object::BuildID> BinaryIds) { 145bdd1243dSDimitry Andric OS << "Binary IDs: \n"; 146*0fca6ea1SDimitry Andric for (const auto &BI : BinaryIds) { 147*0fca6ea1SDimitry Andric for (auto I : BI) 148*0fca6ea1SDimitry Andric OS << format("%02x", I); 149bdd1243dSDimitry Andric OS << "\n"; 150bdd1243dSDimitry Andric } 151bdd1243dSDimitry Andric } 152bdd1243dSDimitry Andric 1530b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>> 15406c3fb27SDimitry Andric InstrProfReader::create(const Twine &Path, vfs::FileSystem &FS, 1555f757f3fSDimitry Andric const InstrProfCorrelator *Correlator, 1565f757f3fSDimitry Andric std::function<void(Error)> Warn) { 1570b57cec5SDimitry Andric // Set up the buffer to read. 15806c3fb27SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path, FS); 1590b57cec5SDimitry Andric if (Error E = BufferOrError.takeError()) 1600b57cec5SDimitry Andric return std::move(E); 1615f757f3fSDimitry Andric return InstrProfReader::create(std::move(BufferOrError.get()), Correlator, 1625f757f3fSDimitry Andric Warn); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>> 1660eae32dcSDimitry Andric InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer, 1675f757f3fSDimitry Andric const InstrProfCorrelator *Correlator, 1685f757f3fSDimitry Andric std::function<void(Error)> Warn) { 1690b57cec5SDimitry Andric if (Buffer->getBufferSize() == 0) 1700b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::empty_raw_profile); 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric std::unique_ptr<InstrProfReader> Result; 1730b57cec5SDimitry Andric // Create the reader. 1740b57cec5SDimitry Andric if (IndexedInstrProfReader::hasFormat(*Buffer)) 1750b57cec5SDimitry Andric Result.reset(new IndexedInstrProfReader(std::move(Buffer))); 1760b57cec5SDimitry Andric else if (RawInstrProfReader64::hasFormat(*Buffer)) 1775f757f3fSDimitry Andric Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn)); 1780b57cec5SDimitry Andric else if (RawInstrProfReader32::hasFormat(*Buffer)) 1795f757f3fSDimitry Andric Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn)); 1800b57cec5SDimitry Andric else if (TextInstrProfReader::hasFormat(*Buffer)) 1810b57cec5SDimitry Andric Result.reset(new TextInstrProfReader(std::move(Buffer))); 1820b57cec5SDimitry Andric else 1830b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unrecognized_format); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric // Initialize the reader and return the result. 1860b57cec5SDimitry Andric if (Error E = initializeReader(*Result)) 1870b57cec5SDimitry Andric return std::move(E); 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric return std::move(Result); 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>> 19306c3fb27SDimitry Andric IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS, 19406c3fb27SDimitry Andric const Twine &RemappingPath) { 1950b57cec5SDimitry Andric // Set up the buffer to read. 19606c3fb27SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path, FS); 1970b57cec5SDimitry Andric if (Error E = BufferOrError.takeError()) 1980b57cec5SDimitry Andric return std::move(E); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric // Set up the remapping buffer if requested. 2010b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer; 2020b57cec5SDimitry Andric std::string RemappingPathStr = RemappingPath.str(); 2030b57cec5SDimitry Andric if (!RemappingPathStr.empty()) { 20406c3fb27SDimitry Andric auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS); 2050b57cec5SDimitry Andric if (Error E = RemappingBufferOrError.takeError()) 2060b57cec5SDimitry Andric return std::move(E); 2070b57cec5SDimitry Andric RemappingBuffer = std::move(RemappingBufferOrError.get()); 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric return IndexedInstrProfReader::create(std::move(BufferOrError.get()), 2110b57cec5SDimitry Andric std::move(RemappingBuffer)); 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>> 2150b57cec5SDimitry Andric IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer, 2160b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer) { 2170b57cec5SDimitry Andric // Create the reader. 2180b57cec5SDimitry Andric if (!IndexedInstrProfReader::hasFormat(*Buffer)) 2190b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic); 2208bcb0991SDimitry Andric auto Result = std::make_unique<IndexedInstrProfReader>( 2210b57cec5SDimitry Andric std::move(Buffer), std::move(RemappingBuffer)); 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric // Initialize the reader and return the result. 2240b57cec5SDimitry Andric if (Error E = initializeReader(*Result)) 2250b57cec5SDimitry Andric return std::move(E); 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric return std::move(Result); 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { 2310b57cec5SDimitry Andric // Verify that this really looks like plain ASCII text by checking a 2320b57cec5SDimitry Andric // 'reasonable' number of characters (up to profile magic size). 2330b57cec5SDimitry Andric size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t)); 2340b57cec5SDimitry Andric StringRef buffer = Buffer.getBufferStart(); 2350b57cec5SDimitry Andric return count == 0 || 2360b57cec5SDimitry Andric std::all_of(buffer.begin(), buffer.begin() + count, 2375ffd83dbSDimitry Andric [](char c) { return isPrint(c) || isSpace(c); }); 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric // Read the profile variant flag from the header: ":FE" means this is a FE 2410b57cec5SDimitry Andric // generated profile. ":IR" means this is an IR level profile. Other strings 2420b57cec5SDimitry Andric // with a leading ':' will be reported an error format. 2430b57cec5SDimitry Andric Error TextInstrProfReader::readHeader() { 2440b57cec5SDimitry Andric Symtab.reset(new InstrProfSymtab()); 245e8d8bef9SDimitry Andric 2465f757f3fSDimitry Andric while (Line->starts_with(":")) { 247e8d8bef9SDimitry Andric StringRef Str = Line->substr(1); 248fe6060f1SDimitry Andric if (Str.equals_insensitive("ir")) 24981ad6265SDimitry Andric ProfileKind |= InstrProfKind::IRInstrumentation; 250fe6060f1SDimitry Andric else if (Str.equals_insensitive("fe")) 25181ad6265SDimitry Andric ProfileKind |= InstrProfKind::FrontendInstrumentation; 252fe6060f1SDimitry Andric else if (Str.equals_insensitive("csir")) { 25381ad6265SDimitry Andric ProfileKind |= InstrProfKind::IRInstrumentation; 25481ad6265SDimitry Andric ProfileKind |= InstrProfKind::ContextSensitive; 255fe6060f1SDimitry Andric } else if (Str.equals_insensitive("entry_first")) 25681ad6265SDimitry Andric ProfileKind |= InstrProfKind::FunctionEntryInstrumentation; 257fe6060f1SDimitry Andric else if (Str.equals_insensitive("not_entry_first")) 25881ad6265SDimitry Andric ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation; 2595f757f3fSDimitry Andric else if (Str.equals_insensitive("single_byte_coverage")) 2605f757f3fSDimitry Andric ProfileKind |= InstrProfKind::SingleByteCoverage; 26106c3fb27SDimitry Andric else if (Str.equals_insensitive("temporal_prof_traces")) { 26206c3fb27SDimitry Andric ProfileKind |= InstrProfKind::TemporalProfile; 26306c3fb27SDimitry Andric if (auto Err = readTemporalProfTraceData()) 26406c3fb27SDimitry Andric return error(std::move(Err)); 26506c3fb27SDimitry Andric } else 2660b57cec5SDimitry Andric return error(instrprof_error::bad_header); 2670b57cec5SDimitry Andric ++Line; 268e8d8bef9SDimitry Andric } 2690b57cec5SDimitry Andric return success(); 2700b57cec5SDimitry Andric } 2710b57cec5SDimitry Andric 27206c3fb27SDimitry Andric /// Temporal profile trace data is stored in the header immediately after 27306c3fb27SDimitry Andric /// ":temporal_prof_traces". The first integer is the number of traces, the 27406c3fb27SDimitry Andric /// second integer is the stream size, then the following lines are the actual 27506c3fb27SDimitry Andric /// traces which consist of a weight and a comma separated list of function 27606c3fb27SDimitry Andric /// names. 27706c3fb27SDimitry Andric Error TextInstrProfReader::readTemporalProfTraceData() { 27806c3fb27SDimitry Andric if ((++Line).is_at_end()) 27906c3fb27SDimitry Andric return error(instrprof_error::eof); 28006c3fb27SDimitry Andric 28106c3fb27SDimitry Andric uint32_t NumTraces; 28206c3fb27SDimitry Andric if (Line->getAsInteger(0, NumTraces)) 28306c3fb27SDimitry Andric return error(instrprof_error::malformed); 28406c3fb27SDimitry Andric 28506c3fb27SDimitry Andric if ((++Line).is_at_end()) 28606c3fb27SDimitry Andric return error(instrprof_error::eof); 28706c3fb27SDimitry Andric 28806c3fb27SDimitry Andric if (Line->getAsInteger(0, TemporalProfTraceStreamSize)) 28906c3fb27SDimitry Andric return error(instrprof_error::malformed); 29006c3fb27SDimitry Andric 29106c3fb27SDimitry Andric for (uint32_t i = 0; i < NumTraces; i++) { 29206c3fb27SDimitry Andric if ((++Line).is_at_end()) 29306c3fb27SDimitry Andric return error(instrprof_error::eof); 29406c3fb27SDimitry Andric 29506c3fb27SDimitry Andric TemporalProfTraceTy Trace; 29606c3fb27SDimitry Andric if (Line->getAsInteger(0, Trace.Weight)) 29706c3fb27SDimitry Andric return error(instrprof_error::malformed); 29806c3fb27SDimitry Andric 29906c3fb27SDimitry Andric if ((++Line).is_at_end()) 30006c3fb27SDimitry Andric return error(instrprof_error::eof); 30106c3fb27SDimitry Andric 30206c3fb27SDimitry Andric SmallVector<StringRef> FuncNames; 30306c3fb27SDimitry Andric Line->split(FuncNames, ",", /*MaxSplit=*/-1, /*KeepEmpty=*/false); 30406c3fb27SDimitry Andric for (auto &FuncName : FuncNames) 30506c3fb27SDimitry Andric Trace.FunctionNameRefs.push_back( 30606c3fb27SDimitry Andric IndexedInstrProf::ComputeHash(FuncName.trim())); 30706c3fb27SDimitry Andric TemporalProfTraces.push_back(std::move(Trace)); 30806c3fb27SDimitry Andric } 30906c3fb27SDimitry Andric return success(); 31006c3fb27SDimitry Andric } 31106c3fb27SDimitry Andric 3120b57cec5SDimitry Andric Error 3130b57cec5SDimitry Andric TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric #define CHECK_LINE_END(Line) \ 3160b57cec5SDimitry Andric if (Line.is_at_end()) \ 3170b57cec5SDimitry Andric return error(instrprof_error::truncated); 3180b57cec5SDimitry Andric #define READ_NUM(Str, Dst) \ 3190b57cec5SDimitry Andric if ((Str).getAsInteger(10, (Dst))) \ 3200b57cec5SDimitry Andric return error(instrprof_error::malformed); 3210b57cec5SDimitry Andric #define VP_READ_ADVANCE(Val) \ 3220b57cec5SDimitry Andric CHECK_LINE_END(Line); \ 3230b57cec5SDimitry Andric uint32_t Val; \ 3240b57cec5SDimitry Andric READ_NUM((*Line), (Val)); \ 3250b57cec5SDimitry Andric Line++; 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric if (Line.is_at_end()) 3280b57cec5SDimitry Andric return success(); 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric uint32_t NumValueKinds; 3310b57cec5SDimitry Andric if (Line->getAsInteger(10, NumValueKinds)) { 3320b57cec5SDimitry Andric // No value profile data 3330b57cec5SDimitry Andric return success(); 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1) 336349cc55cSDimitry Andric return error(instrprof_error::malformed, 337349cc55cSDimitry Andric "number of value kinds is invalid"); 3380b57cec5SDimitry Andric Line++; 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric for (uint32_t VK = 0; VK < NumValueKinds; VK++) { 3410b57cec5SDimitry Andric VP_READ_ADVANCE(ValueKind); 3420b57cec5SDimitry Andric if (ValueKind > IPVK_Last) 343349cc55cSDimitry Andric return error(instrprof_error::malformed, "value kind is invalid"); 344349cc55cSDimitry Andric ; 3450b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueSites); 3460b57cec5SDimitry Andric if (!NumValueSites) 3470b57cec5SDimitry Andric continue; 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric Record.reserveSites(VK, NumValueSites); 3500b57cec5SDimitry Andric for (uint32_t S = 0; S < NumValueSites; S++) { 3510b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueData); 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric std::vector<InstrProfValueData> CurrentValues; 3540b57cec5SDimitry Andric for (uint32_t V = 0; V < NumValueData; V++) { 3550b57cec5SDimitry Andric CHECK_LINE_END(Line); 3560b57cec5SDimitry Andric std::pair<StringRef, StringRef> VD = Line->rsplit(':'); 3570b57cec5SDimitry Andric uint64_t TakenCount, Value; 3580b57cec5SDimitry Andric if (ValueKind == IPVK_IndirectCallTarget) { 3590b57cec5SDimitry Andric if (InstrProfSymtab::isExternalSymbol(VD.first)) { 3600b57cec5SDimitry Andric Value = 0; 3610b57cec5SDimitry Andric } else { 3620b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(VD.first)) 3630b57cec5SDimitry Andric return E; 3640b57cec5SDimitry Andric Value = IndexedInstrProf::ComputeHash(VD.first); 3650b57cec5SDimitry Andric } 366*0fca6ea1SDimitry Andric } else if (ValueKind == IPVK_VTableTarget) { 367*0fca6ea1SDimitry Andric if (InstrProfSymtab::isExternalSymbol(VD.first)) 368*0fca6ea1SDimitry Andric Value = 0; 369*0fca6ea1SDimitry Andric else { 370*0fca6ea1SDimitry Andric if (Error E = Symtab->addVTableName(VD.first)) 371*0fca6ea1SDimitry Andric return E; 372*0fca6ea1SDimitry Andric Value = IndexedInstrProf::ComputeHash(VD.first); 373*0fca6ea1SDimitry Andric } 3740b57cec5SDimitry Andric } else { 3750b57cec5SDimitry Andric READ_NUM(VD.first, Value); 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric READ_NUM(VD.second, TakenCount); 3780b57cec5SDimitry Andric CurrentValues.push_back({Value, TakenCount}); 3790b57cec5SDimitry Andric Line++; 3800b57cec5SDimitry Andric } 381*0fca6ea1SDimitry Andric assert(CurrentValues.size() == NumValueData); 382*0fca6ea1SDimitry Andric Record.addValueData(ValueKind, S, CurrentValues, nullptr); 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric return success(); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric #undef CHECK_LINE_END 3880b57cec5SDimitry Andric #undef READ_NUM 3890b57cec5SDimitry Andric #undef VP_READ_ADVANCE 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { 3930b57cec5SDimitry Andric // Skip empty lines and comments. 3945f757f3fSDimitry Andric while (!Line.is_at_end() && (Line->empty() || Line->starts_with("#"))) 3950b57cec5SDimitry Andric ++Line; 3960b57cec5SDimitry Andric // If we hit EOF while looking for a name, we're done. 3970b57cec5SDimitry Andric if (Line.is_at_end()) { 3980b57cec5SDimitry Andric return error(instrprof_error::eof); 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric // Read the function name. 4020b57cec5SDimitry Andric Record.Name = *Line++; 4030b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(Record.Name)) 4040b57cec5SDimitry Andric return error(std::move(E)); 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric // Read the function hash. 4070b57cec5SDimitry Andric if (Line.is_at_end()) 4080b57cec5SDimitry Andric return error(instrprof_error::truncated); 4090b57cec5SDimitry Andric if ((Line++)->getAsInteger(0, Record.Hash)) 410349cc55cSDimitry Andric return error(instrprof_error::malformed, 411349cc55cSDimitry Andric "function hash is not a valid integer"); 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric // Read the number of counters. 4140b57cec5SDimitry Andric uint64_t NumCounters; 4150b57cec5SDimitry Andric if (Line.is_at_end()) 4160b57cec5SDimitry Andric return error(instrprof_error::truncated); 4170b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, NumCounters)) 418349cc55cSDimitry Andric return error(instrprof_error::malformed, 419349cc55cSDimitry Andric "number of counters is not a valid integer"); 4200b57cec5SDimitry Andric if (NumCounters == 0) 421349cc55cSDimitry Andric return error(instrprof_error::malformed, "number of counters is zero"); 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric // Read each counter and fill our internal storage with the values. 4240b57cec5SDimitry Andric Record.Clear(); 4250b57cec5SDimitry Andric Record.Counts.reserve(NumCounters); 4260b57cec5SDimitry Andric for (uint64_t I = 0; I < NumCounters; ++I) { 4270b57cec5SDimitry Andric if (Line.is_at_end()) 4280b57cec5SDimitry Andric return error(instrprof_error::truncated); 4290b57cec5SDimitry Andric uint64_t Count; 4300b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, Count)) 431349cc55cSDimitry Andric return error(instrprof_error::malformed, "count is invalid"); 4320b57cec5SDimitry Andric Record.Counts.push_back(Count); 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric 4355f757f3fSDimitry Andric // Bitmap byte information is indicated with special character. 4365f757f3fSDimitry Andric if (Line->starts_with("$")) { 4375f757f3fSDimitry Andric Record.BitmapBytes.clear(); 4385f757f3fSDimitry Andric // Read the number of bitmap bytes. 4395f757f3fSDimitry Andric uint64_t NumBitmapBytes; 4405f757f3fSDimitry Andric if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes)) 4415f757f3fSDimitry Andric return error(instrprof_error::malformed, 4425f757f3fSDimitry Andric "number of bitmap bytes is not a valid integer"); 4435f757f3fSDimitry Andric if (NumBitmapBytes != 0) { 4445f757f3fSDimitry Andric // Read each bitmap and fill our internal storage with the values. 4455f757f3fSDimitry Andric Record.BitmapBytes.reserve(NumBitmapBytes); 4465f757f3fSDimitry Andric for (uint8_t I = 0; I < NumBitmapBytes; ++I) { 4475f757f3fSDimitry Andric if (Line.is_at_end()) 4485f757f3fSDimitry Andric return error(instrprof_error::truncated); 4495f757f3fSDimitry Andric uint8_t BitmapByte; 4505f757f3fSDimitry Andric if ((Line++)->getAsInteger(0, BitmapByte)) 4515f757f3fSDimitry Andric return error(instrprof_error::malformed, 4525f757f3fSDimitry Andric "bitmap byte is not a valid integer"); 4535f757f3fSDimitry Andric Record.BitmapBytes.push_back(BitmapByte); 4545f757f3fSDimitry Andric } 4555f757f3fSDimitry Andric } 4565f757f3fSDimitry Andric } 4575f757f3fSDimitry Andric 4580b57cec5SDimitry Andric // Check if value profile data exists and read it if so. 4590b57cec5SDimitry Andric if (Error E = readValueProfileData(Record)) 4600b57cec5SDimitry Andric return error(std::move(E)); 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric return success(); 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric template <class IntPtrT> 4661fd87a68SDimitry Andric InstrProfKind RawInstrProfReader<IntPtrT>::getProfileKind() const { 4671fd87a68SDimitry Andric return getProfileKindFromVersion(Version); 4681fd87a68SDimitry Andric } 4691fd87a68SDimitry Andric 4701fd87a68SDimitry Andric template <class IntPtrT> 47106c3fb27SDimitry Andric SmallVector<TemporalProfTraceTy> & 47206c3fb27SDimitry Andric RawInstrProfReader<IntPtrT>::getTemporalProfTraces( 47306c3fb27SDimitry Andric std::optional<uint64_t> Weight) { 47406c3fb27SDimitry Andric if (TemporalProfTimestamps.empty()) { 47506c3fb27SDimitry Andric assert(TemporalProfTraces.empty()); 47606c3fb27SDimitry Andric return TemporalProfTraces; 47706c3fb27SDimitry Andric } 47806c3fb27SDimitry Andric // Sort functions by their timestamps to build the trace. 47906c3fb27SDimitry Andric std::sort(TemporalProfTimestamps.begin(), TemporalProfTimestamps.end()); 48006c3fb27SDimitry Andric TemporalProfTraceTy Trace; 48106c3fb27SDimitry Andric if (Weight) 48206c3fb27SDimitry Andric Trace.Weight = *Weight; 48306c3fb27SDimitry Andric for (auto &[TimestampValue, NameRef] : TemporalProfTimestamps) 48406c3fb27SDimitry Andric Trace.FunctionNameRefs.push_back(NameRef); 48506c3fb27SDimitry Andric TemporalProfTraces = {std::move(Trace)}; 48606c3fb27SDimitry Andric return TemporalProfTraces; 48706c3fb27SDimitry Andric } 48806c3fb27SDimitry Andric 48906c3fb27SDimitry Andric template <class IntPtrT> 4900b57cec5SDimitry Andric bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { 4910b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < sizeof(uint64_t)) 4920b57cec5SDimitry Andric return false; 4930b57cec5SDimitry Andric uint64_t Magic = 4940b57cec5SDimitry Andric *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); 4950b57cec5SDimitry Andric return RawInstrProf::getMagic<IntPtrT>() == Magic || 4965f757f3fSDimitry Andric llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic; 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric template <class IntPtrT> 5000b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader() { 5010b57cec5SDimitry Andric if (!hasFormat(*DataBuffer)) 5020b57cec5SDimitry Andric return error(instrprof_error::bad_magic); 5030b57cec5SDimitry Andric if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header)) 5040b57cec5SDimitry Andric return error(instrprof_error::bad_header); 5050b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>( 5060b57cec5SDimitry Andric DataBuffer->getBufferStart()); 5070b57cec5SDimitry Andric ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>(); 5080b57cec5SDimitry Andric return readHeader(*Header); 5090b57cec5SDimitry Andric } 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric template <class IntPtrT> 5120b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) { 5130b57cec5SDimitry Andric const char *End = DataBuffer->getBufferEnd(); 5140b57cec5SDimitry Andric // Skip zero padding between profiles. 5150b57cec5SDimitry Andric while (CurrentPos != End && *CurrentPos == 0) 5160b57cec5SDimitry Andric ++CurrentPos; 5170b57cec5SDimitry Andric // If there's nothing left, we're done. 5180b57cec5SDimitry Andric if (CurrentPos == End) 5190b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof); 5200b57cec5SDimitry Andric // If there isn't enough space for another header, this is probably just 5210b57cec5SDimitry Andric // garbage at the end of the file. 5220b57cec5SDimitry Andric if (CurrentPos + sizeof(RawInstrProf::Header) > End) 523349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed, 524349cc55cSDimitry Andric "not enough space for another header"); 5250b57cec5SDimitry Andric // The writer ensures each profile is padded to start at an aligned address. 5260b57cec5SDimitry Andric if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t)) 527349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed, 528349cc55cSDimitry Andric "insufficient padding"); 5290b57cec5SDimitry Andric // The magic should have the same byte order as in the previous header. 5300b57cec5SDimitry Andric uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos); 5310b57cec5SDimitry Andric if (Magic != swap(RawInstrProf::getMagic<IntPtrT>())) 5320b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric // There's another profile to read, so we need to process the header. 5350b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos); 5360b57cec5SDimitry Andric return readHeader(*Header); 5370b57cec5SDimitry Andric } 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric template <class IntPtrT> 5400b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { 541*0fca6ea1SDimitry Andric if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart), 542*0fca6ea1SDimitry Andric StringRef(VNamesStart, VNamesEnd - VNamesStart))) 5430b57cec5SDimitry Andric return error(std::move(E)); 5440b57cec5SDimitry Andric for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) { 5450b57cec5SDimitry Andric const IntPtrT FPtr = swap(I->FunctionPointer); 5460b57cec5SDimitry Andric if (!FPtr) 5470b57cec5SDimitry Andric continue; 548647cbc5dSDimitry Andric Symtab.mapAddress(FPtr, swap(I->NameRef)); 5490b57cec5SDimitry Andric } 550*0fca6ea1SDimitry Andric 551*0fca6ea1SDimitry Andric if (VTableBegin != nullptr && VTableEnd != nullptr) { 552*0fca6ea1SDimitry Andric for (const RawInstrProf::VTableProfileData<IntPtrT> *I = VTableBegin; 553*0fca6ea1SDimitry Andric I != VTableEnd; ++I) { 554*0fca6ea1SDimitry Andric const IntPtrT VPtr = swap(I->VTablePointer); 555*0fca6ea1SDimitry Andric if (!VPtr) 556*0fca6ea1SDimitry Andric continue; 557*0fca6ea1SDimitry Andric // Map both begin and end address to the name hash, since the instrumented 558*0fca6ea1SDimitry Andric // address could be somewhere in the middle. 559*0fca6ea1SDimitry Andric // VPtr is of type uint32_t or uint64_t so 'VPtr + I->VTableSize' marks 560*0fca6ea1SDimitry Andric // the end of vtable address. 561*0fca6ea1SDimitry Andric Symtab.mapVTableAddress(VPtr, VPtr + swap(I->VTableSize), 562*0fca6ea1SDimitry Andric swap(I->VTableNameHash)); 563*0fca6ea1SDimitry Andric } 564*0fca6ea1SDimitry Andric } 5650b57cec5SDimitry Andric return success(); 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric template <class IntPtrT> 5690b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader( 5700b57cec5SDimitry Andric const RawInstrProf::Header &Header) { 5710b57cec5SDimitry Andric Version = swap(Header.Version); 5720b57cec5SDimitry Andric if (GET_VERSION(Version) != RawInstrProf::Version) 57306c3fb27SDimitry Andric return error(instrprof_error::raw_profile_version_mismatch, 57406c3fb27SDimitry Andric ("Profile uses raw profile format version = " + 57506c3fb27SDimitry Andric Twine(GET_VERSION(Version)) + 57606c3fb27SDimitry Andric "; expected version = " + Twine(RawInstrProf::Version) + 57706c3fb27SDimitry Andric "\nPLEASE update this tool to version in the raw profile, or " 57806c3fb27SDimitry Andric "regenerate raw profile with expected version.") 57906c3fb27SDimitry Andric .str()); 5800b57cec5SDimitry Andric 5815f757f3fSDimitry Andric uint64_t BinaryIdSize = swap(Header.BinaryIdsSize); 5825f757f3fSDimitry Andric // Binary id start just after the header if exists. 5835f757f3fSDimitry Andric const uint8_t *BinaryIdStart = 5845f757f3fSDimitry Andric reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header); 5855f757f3fSDimitry Andric const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize; 5865f757f3fSDimitry Andric const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd(); 5875f757f3fSDimitry Andric if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd) 588349cc55cSDimitry Andric return error(instrprof_error::bad_header); 589*0fca6ea1SDimitry Andric ArrayRef<uint8_t> BinaryIdsBuffer(BinaryIdStart, BinaryIdSize); 590*0fca6ea1SDimitry Andric if (!BinaryIdsBuffer.empty()) { 591*0fca6ea1SDimitry Andric if (Error Err = readBinaryIdsInternal(*DataBuffer, BinaryIdsBuffer, 5925f757f3fSDimitry Andric BinaryIds, getDataEndianness())) 5935f757f3fSDimitry Andric return Err; 5945f757f3fSDimitry Andric } 595349cc55cSDimitry Andric 5960b57cec5SDimitry Andric CountersDelta = swap(Header.CountersDelta); 5975f757f3fSDimitry Andric BitmapDelta = swap(Header.BitmapDelta); 5980b57cec5SDimitry Andric NamesDelta = swap(Header.NamesDelta); 5995f757f3fSDimitry Andric auto NumData = swap(Header.NumData); 600480093f4SDimitry Andric auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters); 6015f757f3fSDimitry Andric auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize(); 602480093f4SDimitry Andric auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters); 6035f757f3fSDimitry Andric auto NumBitmapBytes = swap(Header.NumBitmapBytes); 6045f757f3fSDimitry Andric auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes); 6050eae32dcSDimitry Andric auto NamesSize = swap(Header.NamesSize); 606*0fca6ea1SDimitry Andric auto VTableNameSize = swap(Header.VNamesSize); 607*0fca6ea1SDimitry Andric auto NumVTables = swap(Header.NumVTables); 6080b57cec5SDimitry Andric ValueKindLast = swap(Header.ValueKindLast); 6090b57cec5SDimitry Andric 61004eeddc0SDimitry Andric auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>); 611*0fca6ea1SDimitry Andric auto PaddingBytesAfterNames = getNumPaddingBytes(NamesSize); 612*0fca6ea1SDimitry Andric auto PaddingBytesAfterVTableNames = getNumPaddingBytes(VTableNameSize); 613*0fca6ea1SDimitry Andric 614*0fca6ea1SDimitry Andric auto VTableSectionSize = 615*0fca6ea1SDimitry Andric NumVTables * sizeof(RawInstrProf::VTableProfileData<IntPtrT>); 616*0fca6ea1SDimitry Andric auto PaddingBytesAfterVTableProfData = getNumPaddingBytes(VTableSectionSize); 6170b57cec5SDimitry Andric 618fe6060f1SDimitry Andric // Profile data starts after profile header and binary ids if exist. 6195f757f3fSDimitry Andric ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdSize; 62004eeddc0SDimitry Andric ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters; 6215f757f3fSDimitry Andric ptrdiff_t BitmapOffset = 62204eeddc0SDimitry Andric CountersOffset + CountersSize + PaddingBytesAfterCounters; 6235f757f3fSDimitry Andric ptrdiff_t NamesOffset = 6245f757f3fSDimitry Andric BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes; 625*0fca6ea1SDimitry Andric ptrdiff_t VTableProfDataOffset = 626*0fca6ea1SDimitry Andric NamesOffset + NamesSize + PaddingBytesAfterNames; 627*0fca6ea1SDimitry Andric ptrdiff_t VTableNameOffset = VTableProfDataOffset + VTableSectionSize + 628*0fca6ea1SDimitry Andric PaddingBytesAfterVTableProfData; 629*0fca6ea1SDimitry Andric ptrdiff_t ValueDataOffset = 630*0fca6ea1SDimitry Andric VTableNameOffset + VTableNameSize + PaddingBytesAfterVTableNames; 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric auto *Start = reinterpret_cast<const char *>(&Header); 6330b57cec5SDimitry Andric if (Start + ValueDataOffset > DataBuffer->getBufferEnd()) 6340b57cec5SDimitry Andric return error(instrprof_error::bad_header); 6350b57cec5SDimitry Andric 6360eae32dcSDimitry Andric if (Correlator) { 6370eae32dcSDimitry Andric // These sizes in the raw file are zero because we constructed them in the 6380eae32dcSDimitry Andric // Correlator. 6395f757f3fSDimitry Andric if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 && 6405f757f3fSDimitry Andric NamesDelta == 0)) 6415f757f3fSDimitry Andric return error(instrprof_error::unexpected_correlation_info); 6420eae32dcSDimitry Andric Data = Correlator->getDataPointer(); 6430eae32dcSDimitry Andric DataEnd = Data + Correlator->getDataSize(); 64404eeddc0SDimitry Andric NamesStart = Correlator->getNamesPointer(); 64504eeddc0SDimitry Andric NamesEnd = NamesStart + Correlator->getNamesSize(); 6460eae32dcSDimitry Andric } else { 6470b57cec5SDimitry Andric Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>( 6480b57cec5SDimitry Andric Start + DataOffset); 64904eeddc0SDimitry Andric DataEnd = Data + NumData; 650*0fca6ea1SDimitry Andric VTableBegin = 651*0fca6ea1SDimitry Andric reinterpret_cast<const RawInstrProf::VTableProfileData<IntPtrT> *>( 652*0fca6ea1SDimitry Andric Start + VTableProfDataOffset); 653*0fca6ea1SDimitry Andric VTableEnd = VTableBegin + NumVTables; 6540eae32dcSDimitry Andric NamesStart = Start + NamesOffset; 6550eae32dcSDimitry Andric NamesEnd = NamesStart + NamesSize; 656*0fca6ea1SDimitry Andric VNamesStart = Start + VTableNameOffset; 657*0fca6ea1SDimitry Andric VNamesEnd = VNamesStart + VTableNameSize; 6580eae32dcSDimitry Andric } 659fe6060f1SDimitry Andric 66004eeddc0SDimitry Andric CountersStart = Start + CountersOffset; 66104eeddc0SDimitry Andric CountersEnd = CountersStart + CountersSize; 6625f757f3fSDimitry Andric BitmapStart = Start + BitmapOffset; 6635f757f3fSDimitry Andric BitmapEnd = BitmapStart + NumBitmapBytes; 6640b57cec5SDimitry Andric ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset); 6650b57cec5SDimitry Andric 6668bcb0991SDimitry Andric std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>(); 66781ad6265SDimitry Andric if (Error E = createSymtab(*NewSymtab)) 6680b57cec5SDimitry Andric return E; 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric Symtab = std::move(NewSymtab); 6710b57cec5SDimitry Andric return success(); 6720b57cec5SDimitry Andric } 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric template <class IntPtrT> 6750b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) { 6760b57cec5SDimitry Andric Record.Name = getName(Data->NameRef); 6770b57cec5SDimitry Andric return success(); 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric template <class IntPtrT> 6810b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) { 6820b57cec5SDimitry Andric Record.Hash = swap(Data->FuncHash); 6830b57cec5SDimitry Andric return success(); 6840b57cec5SDimitry Andric } 6850b57cec5SDimitry Andric 6860b57cec5SDimitry Andric template <class IntPtrT> 6870b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawCounts( 6880b57cec5SDimitry Andric InstrProfRecord &Record) { 6890b57cec5SDimitry Andric uint32_t NumCounters = swap(Data->NumCounters); 6900b57cec5SDimitry Andric if (NumCounters == 0) 691349cc55cSDimitry Andric return error(instrprof_error::malformed, "number of counters is zero"); 6920b57cec5SDimitry Andric 69304eeddc0SDimitry Andric ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta; 69404eeddc0SDimitry Andric if (CounterBaseOffset < 0) 695349cc55cSDimitry Andric return error( 696349cc55cSDimitry Andric instrprof_error::malformed, 69704eeddc0SDimitry Andric ("counter offset " + Twine(CounterBaseOffset) + " is negative").str()); 698349cc55cSDimitry Andric 69904eeddc0SDimitry Andric if (CounterBaseOffset >= CountersEnd - CountersStart) 7000eae32dcSDimitry Andric return error(instrprof_error::malformed, 70104eeddc0SDimitry Andric ("counter offset " + Twine(CounterBaseOffset) + 70204eeddc0SDimitry Andric " is greater than the maximum counter offset " + 70304eeddc0SDimitry Andric Twine(CountersEnd - CountersStart - 1)) 704349cc55cSDimitry Andric .str()); 705349cc55cSDimitry Andric 70604eeddc0SDimitry Andric uint64_t MaxNumCounters = 70704eeddc0SDimitry Andric (CountersEnd - (CountersStart + CounterBaseOffset)) / 70804eeddc0SDimitry Andric getCounterTypeSize(); 70904eeddc0SDimitry Andric if (NumCounters > MaxNumCounters) 710349cc55cSDimitry Andric return error(instrprof_error::malformed, 71104eeddc0SDimitry Andric ("number of counters " + Twine(NumCounters) + 712349cc55cSDimitry Andric " is greater than the maximum number of counters " + 71304eeddc0SDimitry Andric Twine(MaxNumCounters)) 714349cc55cSDimitry Andric .str()); 7158bcb0991SDimitry Andric 7160b57cec5SDimitry Andric Record.Counts.clear(); 71704eeddc0SDimitry Andric Record.Counts.reserve(NumCounters); 71804eeddc0SDimitry Andric for (uint32_t I = 0; I < NumCounters; I++) { 7191fd87a68SDimitry Andric const char *Ptr = 7201fd87a68SDimitry Andric CountersStart + CounterBaseOffset + I * getCounterTypeSize(); 72106c3fb27SDimitry Andric if (I == 0 && hasTemporalProfile()) { 72206c3fb27SDimitry Andric uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr)); 72306c3fb27SDimitry Andric if (TimestampValue != 0 && 72406c3fb27SDimitry Andric TimestampValue != std::numeric_limits<uint64_t>::max()) { 72506c3fb27SDimitry Andric TemporalProfTimestamps.emplace_back(TimestampValue, 72606c3fb27SDimitry Andric swap(Data->NameRef)); 72706c3fb27SDimitry Andric TemporalProfTraceStreamSize = 1; 72806c3fb27SDimitry Andric } 72906c3fb27SDimitry Andric if (hasSingleByteCoverage()) { 73006c3fb27SDimitry Andric // In coverage mode, getCounterTypeSize() returns 1 byte but our 73106c3fb27SDimitry Andric // timestamp field has size uint64_t. Increment I so that the next 73206c3fb27SDimitry Andric // iteration of this for loop points to the byte after the timestamp 73306c3fb27SDimitry Andric // field, i.e., I += 8. 73406c3fb27SDimitry Andric I += 7; 73506c3fb27SDimitry Andric } 73606c3fb27SDimitry Andric continue; 73706c3fb27SDimitry Andric } 7381fd87a68SDimitry Andric if (hasSingleByteCoverage()) { 7391fd87a68SDimitry Andric // A value of zero signifies the block is covered. 7401fd87a68SDimitry Andric Record.Counts.push_back(*Ptr == 0 ? 1 : 0); 7411fd87a68SDimitry Andric } else { 7425f757f3fSDimitry Andric uint64_t CounterValue = swap(*reinterpret_cast<const uint64_t *>(Ptr)); 7435f757f3fSDimitry Andric if (CounterValue > MaxCounterValue && Warn) 7445f757f3fSDimitry Andric Warn(make_error<InstrProfError>( 7455f757f3fSDimitry Andric instrprof_error::counter_value_too_large, Twine(CounterValue))); 7465f757f3fSDimitry Andric 7475f757f3fSDimitry Andric Record.Counts.push_back(CounterValue); 74804eeddc0SDimitry Andric } 7491fd87a68SDimitry Andric } 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric return success(); 7520b57cec5SDimitry Andric } 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric template <class IntPtrT> 7555f757f3fSDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) { 7565f757f3fSDimitry Andric uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes); 7575f757f3fSDimitry Andric 7585f757f3fSDimitry Andric Record.BitmapBytes.clear(); 7595f757f3fSDimitry Andric Record.BitmapBytes.reserve(NumBitmapBytes); 7605f757f3fSDimitry Andric 7615f757f3fSDimitry Andric // It's possible MCDC is either not enabled or only used for some functions 7625f757f3fSDimitry Andric // and not others. So if we record 0 bytes, just move on. 7635f757f3fSDimitry Andric if (NumBitmapBytes == 0) 7645f757f3fSDimitry Andric return success(); 7655f757f3fSDimitry Andric 7665f757f3fSDimitry Andric // BitmapDelta decreases as we advance to the next data record. 7675f757f3fSDimitry Andric ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta; 7685f757f3fSDimitry Andric if (BitmapOffset < 0) 7695f757f3fSDimitry Andric return error( 7705f757f3fSDimitry Andric instrprof_error::malformed, 7715f757f3fSDimitry Andric ("bitmap offset " + Twine(BitmapOffset) + " is negative").str()); 7725f757f3fSDimitry Andric 7735f757f3fSDimitry Andric if (BitmapOffset >= BitmapEnd - BitmapStart) 7745f757f3fSDimitry Andric return error(instrprof_error::malformed, 7755f757f3fSDimitry Andric ("bitmap offset " + Twine(BitmapOffset) + 7765f757f3fSDimitry Andric " is greater than the maximum bitmap offset " + 7775f757f3fSDimitry Andric Twine(BitmapEnd - BitmapStart - 1)) 7785f757f3fSDimitry Andric .str()); 7795f757f3fSDimitry Andric 7805f757f3fSDimitry Andric uint64_t MaxNumBitmapBytes = 7815f757f3fSDimitry Andric (BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t); 7825f757f3fSDimitry Andric if (NumBitmapBytes > MaxNumBitmapBytes) 7835f757f3fSDimitry Andric return error(instrprof_error::malformed, 7845f757f3fSDimitry Andric ("number of bitmap bytes " + Twine(NumBitmapBytes) + 7855f757f3fSDimitry Andric " is greater than the maximum number of bitmap bytes " + 7865f757f3fSDimitry Andric Twine(MaxNumBitmapBytes)) 7875f757f3fSDimitry Andric .str()); 7885f757f3fSDimitry Andric 7895f757f3fSDimitry Andric for (uint32_t I = 0; I < NumBitmapBytes; I++) { 7905f757f3fSDimitry Andric const char *Ptr = BitmapStart + BitmapOffset + I; 7915f757f3fSDimitry Andric Record.BitmapBytes.push_back(swap(*Ptr)); 7925f757f3fSDimitry Andric } 7935f757f3fSDimitry Andric 7945f757f3fSDimitry Andric return success(); 7955f757f3fSDimitry Andric } 7965f757f3fSDimitry Andric 7975f757f3fSDimitry Andric template <class IntPtrT> 7980b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readValueProfilingData( 7990b57cec5SDimitry Andric InstrProfRecord &Record) { 8000b57cec5SDimitry Andric Record.clearValueData(); 8010b57cec5SDimitry Andric CurValueDataSize = 0; 8020b57cec5SDimitry Andric // Need to match the logic in value profile dumper code in compiler-rt: 8030b57cec5SDimitry Andric uint32_t NumValueKinds = 0; 8040b57cec5SDimitry Andric for (uint32_t I = 0; I < IPVK_Last + 1; I++) 8050b57cec5SDimitry Andric NumValueKinds += (Data->NumValueSites[I] != 0); 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric if (!NumValueKinds) 8080b57cec5SDimitry Andric return success(); 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 8110b57cec5SDimitry Andric ValueProfData::getValueProfData( 8120b57cec5SDimitry Andric ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(), 8130b57cec5SDimitry Andric getDataEndianness()); 8140b57cec5SDimitry Andric 8150b57cec5SDimitry Andric if (Error E = VDataPtrOrErr.takeError()) 8160b57cec5SDimitry Andric return E; 8170b57cec5SDimitry Andric 8180b57cec5SDimitry Andric // Note that besides deserialization, this also performs the conversion for 8190b57cec5SDimitry Andric // indirect call targets. The function pointers from the raw profile are 8200b57cec5SDimitry Andric // remapped into function name hashes. 8210b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get()); 8220b57cec5SDimitry Andric CurValueDataSize = VDataPtrOrErr.get()->getSize(); 8230b57cec5SDimitry Andric return success(); 8240b57cec5SDimitry Andric } 8250b57cec5SDimitry Andric 8260b57cec5SDimitry Andric template <class IntPtrT> 8270b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) { 828bdd1243dSDimitry Andric // Keep reading profiles that consist of only headers and no profile data and 829bdd1243dSDimitry Andric // counters. 830bdd1243dSDimitry Andric while (atEnd()) 8310b57cec5SDimitry Andric // At this point, ValueDataStart field points to the next header. 8320b57cec5SDimitry Andric if (Error E = readNextHeader(getNextHeaderPos())) 8330b57cec5SDimitry Andric return error(std::move(E)); 8340b57cec5SDimitry Andric 83506c3fb27SDimitry Andric // Read name and set it in Record. 8360b57cec5SDimitry Andric if (Error E = readName(Record)) 8370b57cec5SDimitry Andric return error(std::move(E)); 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric // Read FuncHash and set it in Record. 8400b57cec5SDimitry Andric if (Error E = readFuncHash(Record)) 8410b57cec5SDimitry Andric return error(std::move(E)); 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric // Read raw counts and set Record. 8440b57cec5SDimitry Andric if (Error E = readRawCounts(Record)) 8450b57cec5SDimitry Andric return error(std::move(E)); 8460b57cec5SDimitry Andric 8475f757f3fSDimitry Andric // Read raw bitmap bytes and set Record. 8485f757f3fSDimitry Andric if (Error E = readRawBitmapBytes(Record)) 8495f757f3fSDimitry Andric return error(std::move(E)); 8505f757f3fSDimitry Andric 8510b57cec5SDimitry Andric // Read value data and set Record. 8520b57cec5SDimitry Andric if (Error E = readValueProfilingData(Record)) 8530b57cec5SDimitry Andric return error(std::move(E)); 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric // Iterate. 8560b57cec5SDimitry Andric advanceData(); 8570b57cec5SDimitry Andric return success(); 8580b57cec5SDimitry Andric } 8590b57cec5SDimitry Andric 860bdd1243dSDimitry Andric template <class IntPtrT> 861bdd1243dSDimitry Andric Error RawInstrProfReader<IntPtrT>::readBinaryIds( 862bdd1243dSDimitry Andric std::vector<llvm::object::BuildID> &BinaryIds) { 8635f757f3fSDimitry Andric BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(), 8645f757f3fSDimitry Andric this->BinaryIds.end()); 8655f757f3fSDimitry Andric return Error::success(); 866349cc55cSDimitry Andric } 867349cc55cSDimitry Andric 868fe6060f1SDimitry Andric template <class IntPtrT> 869fe6060f1SDimitry Andric Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) { 8705f757f3fSDimitry Andric if (!BinaryIds.empty()) 8715f757f3fSDimitry Andric printBinaryIdsInternal(OS, BinaryIds); 8725f757f3fSDimitry Andric return Error::success(); 873fe6060f1SDimitry Andric } 874fe6060f1SDimitry Andric 8750b57cec5SDimitry Andric namespace llvm { 8760b57cec5SDimitry Andric 8770b57cec5SDimitry Andric template class RawInstrProfReader<uint32_t>; 8780b57cec5SDimitry Andric template class RawInstrProfReader<uint64_t>; 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric } // end namespace llvm 8810b57cec5SDimitry Andric 8820b57cec5SDimitry Andric InstrProfLookupTrait::hash_value_type 8830b57cec5SDimitry Andric InstrProfLookupTrait::ComputeHash(StringRef K) { 8840b57cec5SDimitry Andric return IndexedInstrProf::ComputeHash(HashType, K); 8850b57cec5SDimitry Andric } 8860b57cec5SDimitry Andric 8870b57cec5SDimitry Andric using data_type = InstrProfLookupTrait::data_type; 8880b57cec5SDimitry Andric using offset_type = InstrProfLookupTrait::offset_type; 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric bool InstrProfLookupTrait::readValueProfilingData( 8910b57cec5SDimitry Andric const unsigned char *&D, const unsigned char *const End) { 8920b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 8930b57cec5SDimitry Andric ValueProfData::getValueProfData(D, End, ValueProfDataEndianness); 8940b57cec5SDimitry Andric 8950b57cec5SDimitry Andric if (VDataPtrOrErr.takeError()) 8960b57cec5SDimitry Andric return false; 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr); 8990b57cec5SDimitry Andric D += VDataPtrOrErr.get()->TotalSize; 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric return true; 9020b57cec5SDimitry Andric } 9030b57cec5SDimitry Andric 9040b57cec5SDimitry Andric data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, 9050b57cec5SDimitry Andric offset_type N) { 9060b57cec5SDimitry Andric using namespace support; 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric // Check if the data is corrupt. If so, don't try to read it. 9090b57cec5SDimitry Andric if (N % sizeof(uint64_t)) 9100b57cec5SDimitry Andric return data_type(); 9110b57cec5SDimitry Andric 9120b57cec5SDimitry Andric DataBuffer.clear(); 9130b57cec5SDimitry Andric std::vector<uint64_t> CounterBuffer; 9145f757f3fSDimitry Andric std::vector<uint8_t> BitmapByteBuffer; 9150b57cec5SDimitry Andric 9160b57cec5SDimitry Andric const unsigned char *End = D + N; 9170b57cec5SDimitry Andric while (D < End) { 9180b57cec5SDimitry Andric // Read hash. 9190b57cec5SDimitry Andric if (D + sizeof(uint64_t) >= End) 9200b57cec5SDimitry Andric return data_type(); 921*0fca6ea1SDimitry Andric uint64_t Hash = endian::readNext<uint64_t, llvm::endianness::little>(D); 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric // Initialize number of counters for GET_VERSION(FormatVersion) == 1. 9240b57cec5SDimitry Andric uint64_t CountsSize = N / sizeof(uint64_t) - 1; 9250b57cec5SDimitry Andric // If format version is different then read the number of counters. 9260b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) { 9270b57cec5SDimitry Andric if (D + sizeof(uint64_t) > End) 9280b57cec5SDimitry Andric return data_type(); 929*0fca6ea1SDimitry Andric CountsSize = endian::readNext<uint64_t, llvm::endianness::little>(D); 9300b57cec5SDimitry Andric } 9310b57cec5SDimitry Andric // Read counter values. 9320b57cec5SDimitry Andric if (D + CountsSize * sizeof(uint64_t) > End) 9330b57cec5SDimitry Andric return data_type(); 9340b57cec5SDimitry Andric 9350b57cec5SDimitry Andric CounterBuffer.clear(); 9360b57cec5SDimitry Andric CounterBuffer.reserve(CountsSize); 9370b57cec5SDimitry Andric for (uint64_t J = 0; J < CountsSize; ++J) 9385f757f3fSDimitry Andric CounterBuffer.push_back( 939*0fca6ea1SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little>(D)); 9400b57cec5SDimitry Andric 9415f757f3fSDimitry Andric // Read bitmap bytes for GET_VERSION(FormatVersion) > 10. 9425f757f3fSDimitry Andric if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) { 9435f757f3fSDimitry Andric uint64_t BitmapBytes = 0; 9445f757f3fSDimitry Andric if (D + sizeof(uint64_t) > End) 9455f757f3fSDimitry Andric return data_type(); 946*0fca6ea1SDimitry Andric BitmapBytes = endian::readNext<uint64_t, llvm::endianness::little>(D); 9475f757f3fSDimitry Andric // Read bitmap byte values. 9485f757f3fSDimitry Andric if (D + BitmapBytes * sizeof(uint8_t) > End) 9495f757f3fSDimitry Andric return data_type(); 9505f757f3fSDimitry Andric BitmapByteBuffer.clear(); 9515f757f3fSDimitry Andric BitmapByteBuffer.reserve(BitmapBytes); 9525f757f3fSDimitry Andric for (uint64_t J = 0; J < BitmapBytes; ++J) 9535f757f3fSDimitry Andric BitmapByteBuffer.push_back(static_cast<uint8_t>( 954*0fca6ea1SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little>(D))); 9555f757f3fSDimitry Andric } 9565f757f3fSDimitry Andric 9575f757f3fSDimitry Andric DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer), 9585f757f3fSDimitry Andric std::move(BitmapByteBuffer)); 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric // Read value profiling data. 9610b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 && 9620b57cec5SDimitry Andric !readValueProfilingData(D, End)) { 9630b57cec5SDimitry Andric DataBuffer.clear(); 9640b57cec5SDimitry Andric return data_type(); 9650b57cec5SDimitry Andric } 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric return DataBuffer; 9680b57cec5SDimitry Andric } 9690b57cec5SDimitry Andric 9700b57cec5SDimitry Andric template <typename HashTableImpl> 9710b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords( 9720b57cec5SDimitry Andric StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) { 9730b57cec5SDimitry Andric auto Iter = HashTable->find(FuncName); 9740b57cec5SDimitry Andric if (Iter == HashTable->end()) 9750b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unknown_function); 9760b57cec5SDimitry Andric 9770b57cec5SDimitry Andric Data = (*Iter); 9780b57cec5SDimitry Andric if (Data.empty()) 979349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed, 980349cc55cSDimitry Andric "profile data is empty"); 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric return Error::success(); 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric template <typename HashTableImpl> 9860b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords( 9870b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) { 9880b57cec5SDimitry Andric if (atEnd()) 9890b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof); 9900b57cec5SDimitry Andric 9910b57cec5SDimitry Andric Data = *RecordIterator; 9920b57cec5SDimitry Andric 9930b57cec5SDimitry Andric if (Data.empty()) 994349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed, 995349cc55cSDimitry Andric "profile data is empty"); 9960b57cec5SDimitry Andric 9970b57cec5SDimitry Andric return Error::success(); 9980b57cec5SDimitry Andric } 9990b57cec5SDimitry Andric 10000b57cec5SDimitry Andric template <typename HashTableImpl> 10010b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex( 10020b57cec5SDimitry Andric const unsigned char *Buckets, const unsigned char *const Payload, 10030b57cec5SDimitry Andric const unsigned char *const Base, IndexedInstrProf::HashT HashType, 10040b57cec5SDimitry Andric uint64_t Version) { 10050b57cec5SDimitry Andric FormatVersion = Version; 10060b57cec5SDimitry Andric HashTable.reset(HashTableImpl::Create( 10070b57cec5SDimitry Andric Buckets, Payload, Base, 10080b57cec5SDimitry Andric typename HashTableImpl::InfoType(HashType, Version))); 10090b57cec5SDimitry Andric RecordIterator = HashTable->data_begin(); 10100b57cec5SDimitry Andric } 10110b57cec5SDimitry Andric 10121fd87a68SDimitry Andric template <typename HashTableImpl> 10131fd87a68SDimitry Andric InstrProfKind InstrProfReaderIndex<HashTableImpl>::getProfileKind() const { 10141fd87a68SDimitry Andric return getProfileKindFromVersion(FormatVersion); 10151fd87a68SDimitry Andric } 10161fd87a68SDimitry Andric 10170b57cec5SDimitry Andric namespace { 10180b57cec5SDimitry Andric /// A remapper that does not apply any remappings. 10190b57cec5SDimitry Andric class InstrProfReaderNullRemapper : public InstrProfReaderRemapper { 10200b57cec5SDimitry Andric InstrProfReaderIndexBase &Underlying; 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric public: 10230b57cec5SDimitry Andric InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying) 10240b57cec5SDimitry Andric : Underlying(Underlying) {} 10250b57cec5SDimitry Andric 10260b57cec5SDimitry Andric Error getRecords(StringRef FuncName, 10270b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override { 10280b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data); 10290b57cec5SDimitry Andric } 10300b57cec5SDimitry Andric }; 1031349cc55cSDimitry Andric } // namespace 10320b57cec5SDimitry Andric 10330b57cec5SDimitry Andric /// A remapper that applies remappings based on a symbol remapping file. 10340b57cec5SDimitry Andric template <typename HashTableImpl> 10350b57cec5SDimitry Andric class llvm::InstrProfReaderItaniumRemapper 10360b57cec5SDimitry Andric : public InstrProfReaderRemapper { 10370b57cec5SDimitry Andric public: 10380b57cec5SDimitry Andric InstrProfReaderItaniumRemapper( 10390b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer, 10400b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying) 10410b57cec5SDimitry Andric : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) { 10420b57cec5SDimitry Andric } 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric /// Extract the original function name from a PGO function name. 10450b57cec5SDimitry Andric static StringRef extractName(StringRef Name) { 1046cb14a3feSDimitry Andric // We can have multiple pieces separated by kGlobalIdentifierDelimiter ( 1047cb14a3feSDimitry Andric // semicolon now and colon in older profiles); there can be pieces both 1048cb14a3feSDimitry Andric // before and after the mangled name. Find the first part that starts with 1049cb14a3feSDimitry Andric // '_Z'; we'll assume that's the mangled name we want. 10500b57cec5SDimitry Andric std::pair<StringRef, StringRef> Parts = {StringRef(), Name}; 10510b57cec5SDimitry Andric while (true) { 1052*0fca6ea1SDimitry Andric Parts = Parts.second.split(GlobalIdentifierDelimiter); 10535f757f3fSDimitry Andric if (Parts.first.starts_with("_Z")) 10540b57cec5SDimitry Andric return Parts.first; 10550b57cec5SDimitry Andric if (Parts.second.empty()) 10560b57cec5SDimitry Andric return Name; 10570b57cec5SDimitry Andric } 10580b57cec5SDimitry Andric } 10590b57cec5SDimitry Andric 10600b57cec5SDimitry Andric /// Given a mangled name extracted from a PGO function name, and a new 10610b57cec5SDimitry Andric /// form for that mangled name, reconstitute the name. 10620b57cec5SDimitry Andric static void reconstituteName(StringRef OrigName, StringRef ExtractedName, 10630b57cec5SDimitry Andric StringRef Replacement, 10640b57cec5SDimitry Andric SmallVectorImpl<char> &Out) { 10650b57cec5SDimitry Andric Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size()); 10660b57cec5SDimitry Andric Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin()); 10670b57cec5SDimitry Andric Out.insert(Out.end(), Replacement.begin(), Replacement.end()); 10680b57cec5SDimitry Andric Out.insert(Out.end(), ExtractedName.end(), OrigName.end()); 10690b57cec5SDimitry Andric } 10700b57cec5SDimitry Andric 10710b57cec5SDimitry Andric Error populateRemappings() override { 10720b57cec5SDimitry Andric if (Error E = Remappings.read(*RemapBuffer)) 10730b57cec5SDimitry Andric return E; 10740b57cec5SDimitry Andric for (StringRef Name : Underlying.HashTable->keys()) { 10750b57cec5SDimitry Andric StringRef RealName = extractName(Name); 10760b57cec5SDimitry Andric if (auto Key = Remappings.insert(RealName)) { 10770b57cec5SDimitry Andric // FIXME: We could theoretically map the same equivalence class to 10780b57cec5SDimitry Andric // multiple names in the profile data. If that happens, we should 10790b57cec5SDimitry Andric // return NamedInstrProfRecords from all of them. 10800b57cec5SDimitry Andric MappedNames.insert({Key, RealName}); 10810b57cec5SDimitry Andric } 10820b57cec5SDimitry Andric } 10830b57cec5SDimitry Andric return Error::success(); 10840b57cec5SDimitry Andric } 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric Error getRecords(StringRef FuncName, 10870b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override { 10880b57cec5SDimitry Andric StringRef RealName = extractName(FuncName); 10890b57cec5SDimitry Andric if (auto Key = Remappings.lookup(RealName)) { 10900b57cec5SDimitry Andric StringRef Remapped = MappedNames.lookup(Key); 10910b57cec5SDimitry Andric if (!Remapped.empty()) { 10920b57cec5SDimitry Andric if (RealName.begin() == FuncName.begin() && 10930b57cec5SDimitry Andric RealName.end() == FuncName.end()) 10940b57cec5SDimitry Andric FuncName = Remapped; 10950b57cec5SDimitry Andric else { 10960b57cec5SDimitry Andric // Try rebuilding the name from the given remapping. 10970b57cec5SDimitry Andric SmallString<256> Reconstituted; 10980b57cec5SDimitry Andric reconstituteName(FuncName, RealName, Remapped, Reconstituted); 10990b57cec5SDimitry Andric Error E = Underlying.getRecords(Reconstituted, Data); 11000b57cec5SDimitry Andric if (!E) 11010b57cec5SDimitry Andric return E; 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric // If we failed because the name doesn't exist, fall back to asking 11040b57cec5SDimitry Andric // about the original name. 11050b57cec5SDimitry Andric if (Error Unhandled = handleErrors( 11060b57cec5SDimitry Andric std::move(E), [](std::unique_ptr<InstrProfError> Err) { 11070b57cec5SDimitry Andric return Err->get() == instrprof_error::unknown_function 11080b57cec5SDimitry Andric ? Error::success() 11090b57cec5SDimitry Andric : Error(std::move(Err)); 11100b57cec5SDimitry Andric })) 11110b57cec5SDimitry Andric return Unhandled; 11120b57cec5SDimitry Andric } 11130b57cec5SDimitry Andric } 11140b57cec5SDimitry Andric } 11150b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data); 11160b57cec5SDimitry Andric } 11170b57cec5SDimitry Andric 11180b57cec5SDimitry Andric private: 11190b57cec5SDimitry Andric /// The memory buffer containing the remapping configuration. Remappings 11200b57cec5SDimitry Andric /// holds pointers into this buffer. 11210b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer; 11220b57cec5SDimitry Andric 11230b57cec5SDimitry Andric /// The mangling remapper. 11240b57cec5SDimitry Andric SymbolRemappingReader Remappings; 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric /// Mapping from mangled name keys to the name used for the key in the 11270b57cec5SDimitry Andric /// profile data. 11280b57cec5SDimitry Andric /// FIXME: Can we store a location within the on-disk hash table instead of 11290b57cec5SDimitry Andric /// redoing lookup? 11300b57cec5SDimitry Andric DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames; 11310b57cec5SDimitry Andric 11320b57cec5SDimitry Andric /// The real profile data reader. 11330b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying; 11340b57cec5SDimitry Andric }; 11350b57cec5SDimitry Andric 11360b57cec5SDimitry Andric bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { 11370b57cec5SDimitry Andric using namespace support; 11380b57cec5SDimitry Andric 11390b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < 8) 11400b57cec5SDimitry Andric return false; 11415f757f3fSDimitry Andric uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>( 11425f757f3fSDimitry Andric DataBuffer.getBufferStart()); 11430b57cec5SDimitry Andric // Verify that it's magical. 11440b57cec5SDimitry Andric return Magic == IndexedInstrProf::Magic; 11450b57cec5SDimitry Andric } 11460b57cec5SDimitry Andric 11470b57cec5SDimitry Andric const unsigned char * 11480b57cec5SDimitry Andric IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, 11490b57cec5SDimitry Andric const unsigned char *Cur, bool UseCS) { 11500b57cec5SDimitry Andric using namespace IndexedInstrProf; 11510b57cec5SDimitry Andric using namespace support; 11520b57cec5SDimitry Andric 11530b57cec5SDimitry Andric if (Version >= IndexedInstrProf::Version4) { 11540b57cec5SDimitry Andric const IndexedInstrProf::Summary *SummaryInLE = 11550b57cec5SDimitry Andric reinterpret_cast<const IndexedInstrProf::Summary *>(Cur); 11565f757f3fSDimitry Andric uint64_t NFields = endian::byte_swap<uint64_t, llvm::endianness::little>( 11575f757f3fSDimitry Andric SummaryInLE->NumSummaryFields); 11585f757f3fSDimitry Andric uint64_t NEntries = endian::byte_swap<uint64_t, llvm::endianness::little>( 11595f757f3fSDimitry Andric SummaryInLE->NumCutoffEntries); 11600b57cec5SDimitry Andric uint32_t SummarySize = 11610b57cec5SDimitry Andric IndexedInstrProf::Summary::getSize(NFields, NEntries); 11620b57cec5SDimitry Andric std::unique_ptr<IndexedInstrProf::Summary> SummaryData = 11630b57cec5SDimitry Andric IndexedInstrProf::allocSummary(SummarySize); 11640b57cec5SDimitry Andric 11650b57cec5SDimitry Andric const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE); 11660b57cec5SDimitry Andric uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get()); 11670b57cec5SDimitry Andric for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) 11685f757f3fSDimitry Andric Dst[I] = endian::byte_swap<uint64_t, llvm::endianness::little>(Src[I]); 11690b57cec5SDimitry Andric 11700b57cec5SDimitry Andric SummaryEntryVector DetailedSummary; 11710b57cec5SDimitry Andric for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) { 11720b57cec5SDimitry Andric const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I); 11730b57cec5SDimitry Andric DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount, 11740b57cec5SDimitry Andric Ent.NumBlocks); 11750b57cec5SDimitry Andric } 11760b57cec5SDimitry Andric std::unique_ptr<llvm::ProfileSummary> &Summary = 11770b57cec5SDimitry Andric UseCS ? this->CS_Summary : this->Summary; 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric // initialize InstrProfSummary using the SummaryData from disk. 11808bcb0991SDimitry Andric Summary = std::make_unique<ProfileSummary>( 11810b57cec5SDimitry Andric UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr, 11820b57cec5SDimitry Andric DetailedSummary, SummaryData->get(Summary::TotalBlockCount), 11830b57cec5SDimitry Andric SummaryData->get(Summary::MaxBlockCount), 11840b57cec5SDimitry Andric SummaryData->get(Summary::MaxInternalBlockCount), 11850b57cec5SDimitry Andric SummaryData->get(Summary::MaxFunctionCount), 11860b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumBlocks), 11870b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumFunctions)); 11880b57cec5SDimitry Andric return Cur + SummarySize; 11890b57cec5SDimitry Andric } else { 11908bcb0991SDimitry Andric // The older versions do not support a profile summary. This just computes 11918bcb0991SDimitry Andric // an empty summary, which will not result in accurate hot/cold detection. 11928bcb0991SDimitry Andric // We would need to call addRecord for all NamedInstrProfRecords to get the 11938bcb0991SDimitry Andric // correct summary. However, this version is old (prior to early 2016) and 11948bcb0991SDimitry Andric // has not been supporting an accurate summary for several years. 11950b57cec5SDimitry Andric InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 11968bcb0991SDimitry Andric Summary = Builder.getSummary(); 11970b57cec5SDimitry Andric return Cur; 11980b57cec5SDimitry Andric } 11990b57cec5SDimitry Andric } 12000b57cec5SDimitry Andric 1201*0fca6ea1SDimitry Andric Error IndexedMemProfReader::deserializeV012(const unsigned char *Start, 1202*0fca6ea1SDimitry Andric const unsigned char *Ptr, 1203*0fca6ea1SDimitry Andric uint64_t FirstWord) { 1204*0fca6ea1SDimitry Andric // The value returned from RecordTableGenerator.Emit. 1205*0fca6ea1SDimitry Andric const uint64_t RecordTableOffset = 1206*0fca6ea1SDimitry Andric Version == memprof::Version0 1207*0fca6ea1SDimitry Andric ? FirstWord 1208*0fca6ea1SDimitry Andric : support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1209*0fca6ea1SDimitry Andric // The offset in the stream right before invoking 1210*0fca6ea1SDimitry Andric // FrameTableGenerator.Emit. 1211*0fca6ea1SDimitry Andric const uint64_t FramePayloadOffset = 1212*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1213*0fca6ea1SDimitry Andric // The value returned from FrameTableGenerator.Emit. 1214*0fca6ea1SDimitry Andric const uint64_t FrameTableOffset = 1215*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1216*0fca6ea1SDimitry Andric 1217*0fca6ea1SDimitry Andric // The offset in the stream right before invoking 1218*0fca6ea1SDimitry Andric // CallStackTableGenerator.Emit. 1219*0fca6ea1SDimitry Andric uint64_t CallStackPayloadOffset = 0; 1220*0fca6ea1SDimitry Andric // The value returned from CallStackTableGenerator.Emit. 1221*0fca6ea1SDimitry Andric uint64_t CallStackTableOffset = 0; 1222*0fca6ea1SDimitry Andric if (Version >= memprof::Version2) { 1223*0fca6ea1SDimitry Andric CallStackPayloadOffset = 1224*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1225*0fca6ea1SDimitry Andric CallStackTableOffset = 1226*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1227*0fca6ea1SDimitry Andric } 1228*0fca6ea1SDimitry Andric 1229*0fca6ea1SDimitry Andric // Read the schema. 1230*0fca6ea1SDimitry Andric auto SchemaOr = memprof::readMemProfSchema(Ptr); 1231*0fca6ea1SDimitry Andric if (!SchemaOr) 1232*0fca6ea1SDimitry Andric return SchemaOr.takeError(); 1233*0fca6ea1SDimitry Andric Schema = SchemaOr.get(); 1234*0fca6ea1SDimitry Andric 1235*0fca6ea1SDimitry Andric // Now initialize the table reader with a pointer into data buffer. 1236*0fca6ea1SDimitry Andric MemProfRecordTable.reset(MemProfRecordHashTable::Create( 1237*0fca6ea1SDimitry Andric /*Buckets=*/Start + RecordTableOffset, 1238*0fca6ea1SDimitry Andric /*Payload=*/Ptr, 1239*0fca6ea1SDimitry Andric /*Base=*/Start, memprof::RecordLookupTrait(Version, Schema))); 1240*0fca6ea1SDimitry Andric 1241*0fca6ea1SDimitry Andric // Initialize the frame table reader with the payload and bucket offsets. 1242*0fca6ea1SDimitry Andric MemProfFrameTable.reset(MemProfFrameHashTable::Create( 1243*0fca6ea1SDimitry Andric /*Buckets=*/Start + FrameTableOffset, 1244*0fca6ea1SDimitry Andric /*Payload=*/Start + FramePayloadOffset, 1245*0fca6ea1SDimitry Andric /*Base=*/Start)); 1246*0fca6ea1SDimitry Andric 1247*0fca6ea1SDimitry Andric if (Version >= memprof::Version2) 1248*0fca6ea1SDimitry Andric MemProfCallStackTable.reset(MemProfCallStackHashTable::Create( 1249*0fca6ea1SDimitry Andric /*Buckets=*/Start + CallStackTableOffset, 1250*0fca6ea1SDimitry Andric /*Payload=*/Start + CallStackPayloadOffset, 1251*0fca6ea1SDimitry Andric /*Base=*/Start)); 1252*0fca6ea1SDimitry Andric 1253*0fca6ea1SDimitry Andric return Error::success(); 1254*0fca6ea1SDimitry Andric } 1255*0fca6ea1SDimitry Andric 1256*0fca6ea1SDimitry Andric Error IndexedMemProfReader::deserializeV3(const unsigned char *Start, 1257*0fca6ea1SDimitry Andric const unsigned char *Ptr) { 1258*0fca6ea1SDimitry Andric // The offset in the stream right before invoking 1259*0fca6ea1SDimitry Andric // CallStackTableGenerator.Emit. 1260*0fca6ea1SDimitry Andric const uint64_t CallStackPayloadOffset = 1261*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1262*0fca6ea1SDimitry Andric // The offset in the stream right before invoking RecordTableGenerator.Emit. 1263*0fca6ea1SDimitry Andric const uint64_t RecordPayloadOffset = 1264*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1265*0fca6ea1SDimitry Andric // The value returned from RecordTableGenerator.Emit. 1266*0fca6ea1SDimitry Andric const uint64_t RecordTableOffset = 1267*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1268*0fca6ea1SDimitry Andric 1269*0fca6ea1SDimitry Andric // Read the schema. 1270*0fca6ea1SDimitry Andric auto SchemaOr = memprof::readMemProfSchema(Ptr); 1271*0fca6ea1SDimitry Andric if (!SchemaOr) 1272*0fca6ea1SDimitry Andric return SchemaOr.takeError(); 1273*0fca6ea1SDimitry Andric Schema = SchemaOr.get(); 1274*0fca6ea1SDimitry Andric 1275*0fca6ea1SDimitry Andric FrameBase = Ptr; 1276*0fca6ea1SDimitry Andric CallStackBase = Start + CallStackPayloadOffset; 1277*0fca6ea1SDimitry Andric 1278*0fca6ea1SDimitry Andric // Now initialize the table reader with a pointer into data buffer. 1279*0fca6ea1SDimitry Andric MemProfRecordTable.reset(MemProfRecordHashTable::Create( 1280*0fca6ea1SDimitry Andric /*Buckets=*/Start + RecordTableOffset, 1281*0fca6ea1SDimitry Andric /*Payload=*/Start + RecordPayloadOffset, 1282*0fca6ea1SDimitry Andric /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version3, Schema))); 1283*0fca6ea1SDimitry Andric 1284*0fca6ea1SDimitry Andric return Error::success(); 1285*0fca6ea1SDimitry Andric } 1286*0fca6ea1SDimitry Andric 1287*0fca6ea1SDimitry Andric Error IndexedMemProfReader::deserialize(const unsigned char *Start, 1288*0fca6ea1SDimitry Andric uint64_t MemProfOffset) { 1289*0fca6ea1SDimitry Andric const unsigned char *Ptr = Start + MemProfOffset; 1290*0fca6ea1SDimitry Andric 1291*0fca6ea1SDimitry Andric // Read the first 64-bit word, which may be RecordTableOffset in 1292*0fca6ea1SDimitry Andric // memprof::MemProfVersion0 or the MemProf version number in 1293*0fca6ea1SDimitry Andric // memprof::MemProfVersion1 and above. 1294*0fca6ea1SDimitry Andric const uint64_t FirstWord = 1295*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1296*0fca6ea1SDimitry Andric 1297*0fca6ea1SDimitry Andric if (FirstWord == memprof::Version1 || FirstWord == memprof::Version2 || 1298*0fca6ea1SDimitry Andric FirstWord == memprof::Version3) { 1299*0fca6ea1SDimitry Andric // Everything is good. We can proceed to deserialize the rest. 1300*0fca6ea1SDimitry Andric Version = static_cast<memprof::IndexedVersion>(FirstWord); 1301*0fca6ea1SDimitry Andric } else if (FirstWord >= 24) { 1302*0fca6ea1SDimitry Andric // This is a heuristic/hack to detect memprof::MemProfVersion0, 1303*0fca6ea1SDimitry Andric // which does not have a version field in the header. 1304*0fca6ea1SDimitry Andric // In memprof::MemProfVersion0, FirstWord will be RecordTableOffset, 1305*0fca6ea1SDimitry Andric // which should be at least 24 because of the MemProf header size. 1306*0fca6ea1SDimitry Andric Version = memprof::Version0; 1307*0fca6ea1SDimitry Andric } else { 1308*0fca6ea1SDimitry Andric return make_error<InstrProfError>( 1309*0fca6ea1SDimitry Andric instrprof_error::unsupported_version, 1310*0fca6ea1SDimitry Andric formatv("MemProf version {} not supported; " 1311*0fca6ea1SDimitry Andric "requires version between {} and {}, inclusive", 1312*0fca6ea1SDimitry Andric FirstWord, memprof::MinimumSupportedVersion, 1313*0fca6ea1SDimitry Andric memprof::MaximumSupportedVersion)); 1314*0fca6ea1SDimitry Andric } 1315*0fca6ea1SDimitry Andric 1316*0fca6ea1SDimitry Andric switch (Version) { 1317*0fca6ea1SDimitry Andric case memprof::Version0: 1318*0fca6ea1SDimitry Andric case memprof::Version1: 1319*0fca6ea1SDimitry Andric case memprof::Version2: 1320*0fca6ea1SDimitry Andric if (Error E = deserializeV012(Start, Ptr, FirstWord)) 1321*0fca6ea1SDimitry Andric return E; 1322*0fca6ea1SDimitry Andric break; 1323*0fca6ea1SDimitry Andric case memprof::Version3: 1324*0fca6ea1SDimitry Andric if (Error E = deserializeV3(Start, Ptr)) 1325*0fca6ea1SDimitry Andric return E; 1326*0fca6ea1SDimitry Andric break; 1327*0fca6ea1SDimitry Andric } 1328*0fca6ea1SDimitry Andric 1329*0fca6ea1SDimitry Andric #ifdef EXPENSIVE_CHECKS 1330*0fca6ea1SDimitry Andric // Go through all the records and verify that CSId has been correctly 1331*0fca6ea1SDimitry Andric // populated. Do this only under EXPENSIVE_CHECKS. Otherwise, we 1332*0fca6ea1SDimitry Andric // would defeat the purpose of OnDiskIterableChainedHashTable. 1333*0fca6ea1SDimitry Andric // Note that we can compare CSId against actual call stacks only for 1334*0fca6ea1SDimitry Andric // Version0 and Version1 because IndexedAllocationInfo::CallStack and 1335*0fca6ea1SDimitry Andric // IndexedMemProfRecord::CallSites are not populated in Version2. 1336*0fca6ea1SDimitry Andric if (Version <= memprof::Version1) 1337*0fca6ea1SDimitry Andric for (const auto &Record : MemProfRecordTable->data()) 1338*0fca6ea1SDimitry Andric verifyIndexedMemProfRecord(Record); 1339*0fca6ea1SDimitry Andric #endif 1340*0fca6ea1SDimitry Andric 1341*0fca6ea1SDimitry Andric return Error::success(); 1342*0fca6ea1SDimitry Andric } 1343*0fca6ea1SDimitry Andric 13440b57cec5SDimitry Andric Error IndexedInstrProfReader::readHeader() { 13450b57cec5SDimitry Andric using namespace support; 13460b57cec5SDimitry Andric 13470b57cec5SDimitry Andric const unsigned char *Start = 13480b57cec5SDimitry Andric (const unsigned char *)DataBuffer->getBufferStart(); 13490b57cec5SDimitry Andric const unsigned char *Cur = Start; 13500b57cec5SDimitry Andric if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24) 13510b57cec5SDimitry Andric return error(instrprof_error::truncated); 13520b57cec5SDimitry Andric 135381ad6265SDimitry Andric auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start); 135481ad6265SDimitry Andric if (!HeaderOr) 135581ad6265SDimitry Andric return HeaderOr.takeError(); 13560b57cec5SDimitry Andric 135781ad6265SDimitry Andric const IndexedInstrProf::Header *Header = &HeaderOr.get(); 135881ad6265SDimitry Andric Cur += Header->size(); 13590b57cec5SDimitry Andric 1360*0fca6ea1SDimitry Andric Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur, 13610b57cec5SDimitry Andric /* UseCS */ false); 1362*0fca6ea1SDimitry Andric if (Header->Version & VARIANT_MASK_CSIR_PROF) 1363*0fca6ea1SDimitry Andric Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur, 13640b57cec5SDimitry Andric /* UseCS */ true); 13650b57cec5SDimitry Andric // Read the hash type and start offset. 1366*0fca6ea1SDimitry Andric IndexedInstrProf::HashT HashType = 1367*0fca6ea1SDimitry Andric static_cast<IndexedInstrProf::HashT>(Header->HashType); 13680b57cec5SDimitry Andric if (HashType > IndexedInstrProf::HashT::Last) 13690b57cec5SDimitry Andric return error(instrprof_error::unsupported_hash_type); 13700b57cec5SDimitry Andric 137181ad6265SDimitry Andric // The hash table with profile counts comes next. 137281ad6265SDimitry Andric auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>( 1373*0fca6ea1SDimitry Andric Start + Header->HashOffset, Cur, Start, HashType, Header->Version); 137481ad6265SDimitry Andric 1375bdd1243dSDimitry Andric // The MemProfOffset field in the header is only valid when the format 1376bdd1243dSDimitry Andric // version is higher than 8 (when it was introduced). 1377*0fca6ea1SDimitry Andric if (Header->getIndexedProfileVersion() >= 8 && 1378*0fca6ea1SDimitry Andric Header->Version & VARIANT_MASK_MEMPROF) { 1379*0fca6ea1SDimitry Andric if (Error E = MemProfReader.deserialize(Start, Header->MemProfOffset)) 1380*0fca6ea1SDimitry Andric return E; 138181ad6265SDimitry Andric } 13820b57cec5SDimitry Andric 1383bdd1243dSDimitry Andric // BinaryIdOffset field in the header is only valid when the format version 1384bdd1243dSDimitry Andric // is higher than 9 (when it was introduced). 1385*0fca6ea1SDimitry Andric if (Header->getIndexedProfileVersion() >= 9) { 1386*0fca6ea1SDimitry Andric const unsigned char *Ptr = Start + Header->BinaryIdOffset; 1387bdd1243dSDimitry Andric // Read binary ids size. 1388*0fca6ea1SDimitry Andric uint64_t BinaryIdsSize = 1389*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1390bdd1243dSDimitry Andric if (BinaryIdsSize % sizeof(uint64_t)) 1391bdd1243dSDimitry Andric return error(instrprof_error::bad_header); 1392bdd1243dSDimitry Andric // Set the binary ids start. 1393*0fca6ea1SDimitry Andric BinaryIdsBuffer = ArrayRef<uint8_t>(Ptr, BinaryIdsSize); 1394*0fca6ea1SDimitry Andric if (Ptr > (const unsigned char *)DataBuffer->getBufferEnd()) 1395bdd1243dSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed, 1396bdd1243dSDimitry Andric "corrupted binary ids"); 1397bdd1243dSDimitry Andric } 1398bdd1243dSDimitry Andric 1399*0fca6ea1SDimitry Andric if (Header->getIndexedProfileVersion() >= 12) { 1400*0fca6ea1SDimitry Andric const unsigned char *Ptr = Start + Header->VTableNamesOffset; 1401*0fca6ea1SDimitry Andric 1402*0fca6ea1SDimitry Andric uint64_t CompressedVTableNamesLen = 1403*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 1404*0fca6ea1SDimitry Andric 1405*0fca6ea1SDimitry Andric // Writer first writes the length of compressed string, and then the actual 1406*0fca6ea1SDimitry Andric // content. 1407*0fca6ea1SDimitry Andric const char *VTableNamePtr = (const char *)Ptr; 1408*0fca6ea1SDimitry Andric if (VTableNamePtr > (const char *)DataBuffer->getBufferEnd()) 1409*0fca6ea1SDimitry Andric return make_error<InstrProfError>(instrprof_error::truncated); 1410*0fca6ea1SDimitry Andric 1411*0fca6ea1SDimitry Andric VTableName = StringRef(VTableNamePtr, CompressedVTableNamesLen); 1412*0fca6ea1SDimitry Andric } 1413*0fca6ea1SDimitry Andric 1414*0fca6ea1SDimitry Andric if (Header->getIndexedProfileVersion() >= 10 && 1415*0fca6ea1SDimitry Andric Header->Version & VARIANT_MASK_TEMPORAL_PROF) { 1416*0fca6ea1SDimitry Andric const unsigned char *Ptr = Start + Header->TemporalProfTracesOffset; 141706c3fb27SDimitry Andric const auto *PtrEnd = (const unsigned char *)DataBuffer->getBufferEnd(); 141806c3fb27SDimitry Andric // Expect at least two 64 bit fields: NumTraces, and TraceStreamSize 141906c3fb27SDimitry Andric if (Ptr + 2 * sizeof(uint64_t) > PtrEnd) 142006c3fb27SDimitry Andric return error(instrprof_error::truncated); 142106c3fb27SDimitry Andric const uint64_t NumTraces = 1422*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 142306c3fb27SDimitry Andric TemporalProfTraceStreamSize = 1424*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 142506c3fb27SDimitry Andric for (unsigned i = 0; i < NumTraces; i++) { 142606c3fb27SDimitry Andric // Expect at least two 64 bit fields: Weight and NumFunctions 142706c3fb27SDimitry Andric if (Ptr + 2 * sizeof(uint64_t) > PtrEnd) 142806c3fb27SDimitry Andric return error(instrprof_error::truncated); 142906c3fb27SDimitry Andric TemporalProfTraceTy Trace; 143006c3fb27SDimitry Andric Trace.Weight = 1431*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 143206c3fb27SDimitry Andric const uint64_t NumFunctions = 1433*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 143406c3fb27SDimitry Andric // Expect at least NumFunctions 64 bit fields 143506c3fb27SDimitry Andric if (Ptr + NumFunctions * sizeof(uint64_t) > PtrEnd) 143606c3fb27SDimitry Andric return error(instrprof_error::truncated); 143706c3fb27SDimitry Andric for (unsigned j = 0; j < NumFunctions; j++) { 143806c3fb27SDimitry Andric const uint64_t NameRef = 1439*0fca6ea1SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr); 144006c3fb27SDimitry Andric Trace.FunctionNameRefs.push_back(NameRef); 144106c3fb27SDimitry Andric } 144206c3fb27SDimitry Andric TemporalProfTraces.push_back(std::move(Trace)); 144306c3fb27SDimitry Andric } 144406c3fb27SDimitry Andric } 144506c3fb27SDimitry Andric 14460b57cec5SDimitry Andric // Load the remapping table now if requested. 14470b57cec5SDimitry Andric if (RemappingBuffer) { 1448bdd1243dSDimitry Andric Remapper = 1449bdd1243dSDimitry Andric std::make_unique<InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>( 14500b57cec5SDimitry Andric std::move(RemappingBuffer), *IndexPtr); 14510b57cec5SDimitry Andric if (Error E = Remapper->populateRemappings()) 14520b57cec5SDimitry Andric return E; 14530b57cec5SDimitry Andric } else { 14548bcb0991SDimitry Andric Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr); 14550b57cec5SDimitry Andric } 14560b57cec5SDimitry Andric Index = std::move(IndexPtr); 14570b57cec5SDimitry Andric 14580b57cec5SDimitry Andric return success(); 14590b57cec5SDimitry Andric } 14600b57cec5SDimitry Andric 14610b57cec5SDimitry Andric InstrProfSymtab &IndexedInstrProfReader::getSymtab() { 146281ad6265SDimitry Andric if (Symtab) 146381ad6265SDimitry Andric return *Symtab; 14640b57cec5SDimitry Andric 1465*0fca6ea1SDimitry Andric auto NewSymtab = std::make_unique<InstrProfSymtab>(); 1466*0fca6ea1SDimitry Andric 1467*0fca6ea1SDimitry Andric if (Error E = NewSymtab->initVTableNamesFromCompressedStrings(VTableName)) { 1468*0fca6ea1SDimitry Andric auto [ErrCode, Msg] = InstrProfError::take(std::move(E)); 1469*0fca6ea1SDimitry Andric consumeError(error(ErrCode, Msg)); 1470*0fca6ea1SDimitry Andric } 1471*0fca6ea1SDimitry Andric 1472*0fca6ea1SDimitry Andric // finalizeSymtab is called inside populateSymtab. 147381ad6265SDimitry Andric if (Error E = Index->populateSymtab(*NewSymtab)) { 147406c3fb27SDimitry Andric auto [ErrCode, Msg] = InstrProfError::take(std::move(E)); 147506c3fb27SDimitry Andric consumeError(error(ErrCode, Msg)); 14760b57cec5SDimitry Andric } 14770b57cec5SDimitry Andric 14780b57cec5SDimitry Andric Symtab = std::move(NewSymtab); 147981ad6265SDimitry Andric return *Symtab; 14800b57cec5SDimitry Andric } 14810b57cec5SDimitry Andric 1482fcaf7f86SDimitry Andric Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord( 14835f757f3fSDimitry Andric StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName, 14845f757f3fSDimitry Andric uint64_t *MismatchedFuncSum) { 14850b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data; 1486fcaf7f86SDimitry Andric uint64_t FuncSum = 0; 14875f757f3fSDimitry Andric auto Err = Remapper->getRecords(FuncName, Data); 14885f757f3fSDimitry Andric if (Err) { 14895f757f3fSDimitry Andric // If we don't find FuncName, try DeprecatedFuncName to handle profiles 14905f757f3fSDimitry Andric // built by older compilers. 14915f757f3fSDimitry Andric auto Err2 = 14925f757f3fSDimitry Andric handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error { 14935f757f3fSDimitry Andric if (IE.get() != instrprof_error::unknown_function) 14945f757f3fSDimitry Andric return make_error<InstrProfError>(IE); 14955f757f3fSDimitry Andric if (auto Err = Remapper->getRecords(DeprecatedFuncName, Data)) 14965f757f3fSDimitry Andric return Err; 14975f757f3fSDimitry Andric return Error::success(); 14985f757f3fSDimitry Andric }); 14995f757f3fSDimitry Andric if (Err2) 15005f757f3fSDimitry Andric return std::move(Err2); 15015f757f3fSDimitry Andric } 15020b57cec5SDimitry Andric // Found it. Look for counters with the right hash. 1503fcaf7f86SDimitry Andric 1504fcaf7f86SDimitry Andric // A flag to indicate if the records are from the same type 1505fcaf7f86SDimitry Andric // of profile (i.e cs vs nocs). 1506fcaf7f86SDimitry Andric bool CSBitMatch = false; 1507*0fca6ea1SDimitry Andric auto getFuncSum = [](ArrayRef<uint64_t> Counts) { 1508fcaf7f86SDimitry Andric uint64_t ValueSum = 0; 1509bdd1243dSDimitry Andric for (uint64_t CountValue : Counts) { 1510fcaf7f86SDimitry Andric if (CountValue == (uint64_t)-1) 1511fcaf7f86SDimitry Andric continue; 1512fcaf7f86SDimitry Andric // Handle overflow -- if that happens, return max. 1513fcaf7f86SDimitry Andric if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum) 1514fcaf7f86SDimitry Andric return std::numeric_limits<uint64_t>::max(); 1515fcaf7f86SDimitry Andric ValueSum += CountValue; 1516fcaf7f86SDimitry Andric } 1517fcaf7f86SDimitry Andric return ValueSum; 1518fcaf7f86SDimitry Andric }; 1519fcaf7f86SDimitry Andric 15200eae32dcSDimitry Andric for (const NamedInstrProfRecord &I : Data) { 15210b57cec5SDimitry Andric // Check for a match and fill the vector if there is one. 15220eae32dcSDimitry Andric if (I.Hash == FuncHash) 15230eae32dcSDimitry Andric return std::move(I); 1524fcaf7f86SDimitry Andric if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) == 1525fcaf7f86SDimitry Andric NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) { 1526fcaf7f86SDimitry Andric CSBitMatch = true; 1527fcaf7f86SDimitry Andric if (MismatchedFuncSum == nullptr) 1528fcaf7f86SDimitry Andric continue; 1529fcaf7f86SDimitry Andric FuncSum = std::max(FuncSum, getFuncSum(I.Counts)); 15300b57cec5SDimitry Andric } 1531fcaf7f86SDimitry Andric } 1532fcaf7f86SDimitry Andric if (CSBitMatch) { 1533fcaf7f86SDimitry Andric if (MismatchedFuncSum != nullptr) 1534fcaf7f86SDimitry Andric *MismatchedFuncSum = FuncSum; 15350b57cec5SDimitry Andric return error(instrprof_error::hash_mismatch); 15360b57cec5SDimitry Andric } 1537fcaf7f86SDimitry Andric return error(instrprof_error::unknown_function); 1538fcaf7f86SDimitry Andric } 15390b57cec5SDimitry Andric 1540*0fca6ea1SDimitry Andric static Expected<memprof::MemProfRecord> 1541*0fca6ea1SDimitry Andric getMemProfRecordV0(const memprof::IndexedMemProfRecord &IndexedRecord, 1542*0fca6ea1SDimitry Andric MemProfFrameHashTable &MemProfFrameTable) { 1543*0fca6ea1SDimitry Andric memprof::FrameIdConverter<MemProfFrameHashTable> FrameIdConv( 1544*0fca6ea1SDimitry Andric MemProfFrameTable); 1545*0fca6ea1SDimitry Andric 1546*0fca6ea1SDimitry Andric memprof::MemProfRecord Record = 1547*0fca6ea1SDimitry Andric memprof::MemProfRecord(IndexedRecord, FrameIdConv); 1548*0fca6ea1SDimitry Andric 1549*0fca6ea1SDimitry Andric // Check that all frame ids were successfully converted to frames. 1550*0fca6ea1SDimitry Andric if (FrameIdConv.LastUnmappedId) { 1551*0fca6ea1SDimitry Andric return make_error<InstrProfError>(instrprof_error::hash_mismatch, 1552*0fca6ea1SDimitry Andric "memprof frame not found for frame id " + 1553*0fca6ea1SDimitry Andric Twine(*FrameIdConv.LastUnmappedId)); 1554*0fca6ea1SDimitry Andric } 1555*0fca6ea1SDimitry Andric 1556*0fca6ea1SDimitry Andric return Record; 1557*0fca6ea1SDimitry Andric } 1558*0fca6ea1SDimitry Andric 1559*0fca6ea1SDimitry Andric static Expected<memprof::MemProfRecord> 1560*0fca6ea1SDimitry Andric getMemProfRecordV2(const memprof::IndexedMemProfRecord &IndexedRecord, 1561*0fca6ea1SDimitry Andric MemProfFrameHashTable &MemProfFrameTable, 1562*0fca6ea1SDimitry Andric MemProfCallStackHashTable &MemProfCallStackTable) { 1563*0fca6ea1SDimitry Andric memprof::FrameIdConverter<MemProfFrameHashTable> FrameIdConv( 1564*0fca6ea1SDimitry Andric MemProfFrameTable); 1565*0fca6ea1SDimitry Andric 1566*0fca6ea1SDimitry Andric memprof::CallStackIdConverter<MemProfCallStackHashTable> CSIdConv( 1567*0fca6ea1SDimitry Andric MemProfCallStackTable, FrameIdConv); 1568*0fca6ea1SDimitry Andric 1569*0fca6ea1SDimitry Andric memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv); 1570*0fca6ea1SDimitry Andric 1571*0fca6ea1SDimitry Andric // Check that all call stack ids were successfully converted to call stacks. 1572*0fca6ea1SDimitry Andric if (CSIdConv.LastUnmappedId) { 1573*0fca6ea1SDimitry Andric return make_error<InstrProfError>( 1574*0fca6ea1SDimitry Andric instrprof_error::hash_mismatch, 1575*0fca6ea1SDimitry Andric "memprof call stack not found for call stack id " + 1576*0fca6ea1SDimitry Andric Twine(*CSIdConv.LastUnmappedId)); 1577*0fca6ea1SDimitry Andric } 1578*0fca6ea1SDimitry Andric 1579*0fca6ea1SDimitry Andric // Check that all frame ids were successfully converted to frames. 1580*0fca6ea1SDimitry Andric if (FrameIdConv.LastUnmappedId) { 1581*0fca6ea1SDimitry Andric return make_error<InstrProfError>(instrprof_error::hash_mismatch, 1582*0fca6ea1SDimitry Andric "memprof frame not found for frame id " + 1583*0fca6ea1SDimitry Andric Twine(*FrameIdConv.LastUnmappedId)); 1584*0fca6ea1SDimitry Andric } 1585*0fca6ea1SDimitry Andric 1586*0fca6ea1SDimitry Andric return Record; 1587*0fca6ea1SDimitry Andric } 1588*0fca6ea1SDimitry Andric 1589*0fca6ea1SDimitry Andric static Expected<memprof::MemProfRecord> 1590*0fca6ea1SDimitry Andric getMemProfRecordV3(const memprof::IndexedMemProfRecord &IndexedRecord, 1591*0fca6ea1SDimitry Andric const unsigned char *FrameBase, 1592*0fca6ea1SDimitry Andric const unsigned char *CallStackBase) { 1593*0fca6ea1SDimitry Andric memprof::LinearFrameIdConverter FrameIdConv(FrameBase); 1594*0fca6ea1SDimitry Andric memprof::LinearCallStackIdConverter CSIdConv(CallStackBase, FrameIdConv); 1595*0fca6ea1SDimitry Andric memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv); 1596*0fca6ea1SDimitry Andric return Record; 1597*0fca6ea1SDimitry Andric } 1598*0fca6ea1SDimitry Andric 159981ad6265SDimitry Andric Expected<memprof::MemProfRecord> 1600*0fca6ea1SDimitry Andric IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const { 160181ad6265SDimitry Andric // TODO: Add memprof specific errors. 160281ad6265SDimitry Andric if (MemProfRecordTable == nullptr) 160381ad6265SDimitry Andric return make_error<InstrProfError>(instrprof_error::invalid_prof, 160481ad6265SDimitry Andric "no memprof data available in profile"); 160581ad6265SDimitry Andric auto Iter = MemProfRecordTable->find(FuncNameHash); 160681ad6265SDimitry Andric if (Iter == MemProfRecordTable->end()) 160781ad6265SDimitry Andric return make_error<InstrProfError>( 160881ad6265SDimitry Andric instrprof_error::unknown_function, 160981ad6265SDimitry Andric "memprof record not found for function hash " + Twine(FuncNameHash)); 161081ad6265SDimitry Andric 1611*0fca6ea1SDimitry Andric const memprof::IndexedMemProfRecord &IndexedRecord = *Iter; 1612*0fca6ea1SDimitry Andric switch (Version) { 1613*0fca6ea1SDimitry Andric case memprof::Version0: 1614*0fca6ea1SDimitry Andric case memprof::Version1: 1615*0fca6ea1SDimitry Andric assert(MemProfFrameTable && "MemProfFrameTable must be available"); 1616*0fca6ea1SDimitry Andric assert(!MemProfCallStackTable && 1617*0fca6ea1SDimitry Andric "MemProfCallStackTable must not be available"); 1618*0fca6ea1SDimitry Andric return getMemProfRecordV0(IndexedRecord, *MemProfFrameTable); 1619*0fca6ea1SDimitry Andric case memprof::Version2: 1620*0fca6ea1SDimitry Andric assert(MemProfFrameTable && "MemProfFrameTable must be available"); 1621*0fca6ea1SDimitry Andric assert(MemProfCallStackTable && "MemProfCallStackTable must be available"); 1622*0fca6ea1SDimitry Andric return getMemProfRecordV2(IndexedRecord, *MemProfFrameTable, 1623*0fca6ea1SDimitry Andric *MemProfCallStackTable); 1624*0fca6ea1SDimitry Andric case memprof::Version3: 1625*0fca6ea1SDimitry Andric assert(!MemProfFrameTable && "MemProfFrameTable must not be available"); 1626*0fca6ea1SDimitry Andric assert(!MemProfCallStackTable && 1627*0fca6ea1SDimitry Andric "MemProfCallStackTable must not be available"); 1628*0fca6ea1SDimitry Andric assert(FrameBase && "FrameBase must be available"); 1629*0fca6ea1SDimitry Andric assert(CallStackBase && "CallStackBase must be available"); 1630*0fca6ea1SDimitry Andric return getMemProfRecordV3(IndexedRecord, FrameBase, CallStackBase); 163181ad6265SDimitry Andric } 163281ad6265SDimitry Andric 1633*0fca6ea1SDimitry Andric return make_error<InstrProfError>( 1634*0fca6ea1SDimitry Andric instrprof_error::unsupported_version, 1635*0fca6ea1SDimitry Andric formatv("MemProf version {} not supported; " 1636*0fca6ea1SDimitry Andric "requires version between {} and {}, inclusive", 1637*0fca6ea1SDimitry Andric Version, memprof::MinimumSupportedVersion, 1638*0fca6ea1SDimitry Andric memprof::MaximumSupportedVersion)); 163981ad6265SDimitry Andric } 164081ad6265SDimitry Andric 16410b57cec5SDimitry Andric Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, 16420b57cec5SDimitry Andric uint64_t FuncHash, 16430b57cec5SDimitry Andric std::vector<uint64_t> &Counts) { 16440b57cec5SDimitry Andric Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash); 16450b57cec5SDimitry Andric if (Error E = Record.takeError()) 16460b57cec5SDimitry Andric return error(std::move(E)); 16470b57cec5SDimitry Andric 16480b57cec5SDimitry Andric Counts = Record.get().Counts; 16490b57cec5SDimitry Andric return success(); 16500b57cec5SDimitry Andric } 16510b57cec5SDimitry Andric 1652*0fca6ea1SDimitry Andric Error IndexedInstrProfReader::getFunctionBitmap(StringRef FuncName, 1653*0fca6ea1SDimitry Andric uint64_t FuncHash, 1654*0fca6ea1SDimitry Andric BitVector &Bitmap) { 16555f757f3fSDimitry Andric Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash); 16565f757f3fSDimitry Andric if (Error E = Record.takeError()) 16575f757f3fSDimitry Andric return error(std::move(E)); 16585f757f3fSDimitry Andric 1659*0fca6ea1SDimitry Andric const auto &BitmapBytes = Record.get().BitmapBytes; 1660*0fca6ea1SDimitry Andric size_t I = 0, E = BitmapBytes.size(); 1661*0fca6ea1SDimitry Andric Bitmap.resize(E * CHAR_BIT); 1662*0fca6ea1SDimitry Andric BitVector::apply( 1663*0fca6ea1SDimitry Andric [&](auto X) { 1664*0fca6ea1SDimitry Andric using XTy = decltype(X); 1665*0fca6ea1SDimitry Andric alignas(XTy) uint8_t W[sizeof(X)]; 1666*0fca6ea1SDimitry Andric size_t N = std::min(E - I, sizeof(W)); 1667*0fca6ea1SDimitry Andric std::memset(W, 0, sizeof(W)); 1668*0fca6ea1SDimitry Andric std::memcpy(W, &BitmapBytes[I], N); 1669*0fca6ea1SDimitry Andric I += N; 1670*0fca6ea1SDimitry Andric return support::endian::read<XTy, llvm::endianness::little, 1671*0fca6ea1SDimitry Andric support::aligned>(W); 1672*0fca6ea1SDimitry Andric }, 1673*0fca6ea1SDimitry Andric Bitmap, Bitmap); 1674*0fca6ea1SDimitry Andric assert(I == E); 1675*0fca6ea1SDimitry Andric 16765f757f3fSDimitry Andric return success(); 16775f757f3fSDimitry Andric } 16785f757f3fSDimitry Andric 16790b57cec5SDimitry Andric Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { 16800b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data; 16810b57cec5SDimitry Andric 16820b57cec5SDimitry Andric Error E = Index->getRecords(Data); 16830b57cec5SDimitry Andric if (E) 16840b57cec5SDimitry Andric return error(std::move(E)); 16850b57cec5SDimitry Andric 16860b57cec5SDimitry Andric Record = Data[RecordIndex++]; 16870b57cec5SDimitry Andric if (RecordIndex >= Data.size()) { 16880b57cec5SDimitry Andric Index->advanceToNextKey(); 16890b57cec5SDimitry Andric RecordIndex = 0; 16900b57cec5SDimitry Andric } 16910b57cec5SDimitry Andric return success(); 16920b57cec5SDimitry Andric } 16930b57cec5SDimitry Andric 1694bdd1243dSDimitry Andric Error IndexedInstrProfReader::readBinaryIds( 1695bdd1243dSDimitry Andric std::vector<llvm::object::BuildID> &BinaryIds) { 1696*0fca6ea1SDimitry Andric return readBinaryIdsInternal(*DataBuffer, BinaryIdsBuffer, BinaryIds, 1697*0fca6ea1SDimitry Andric llvm::endianness::little); 1698bdd1243dSDimitry Andric } 1699bdd1243dSDimitry Andric 1700bdd1243dSDimitry Andric Error IndexedInstrProfReader::printBinaryIds(raw_ostream &OS) { 17015f757f3fSDimitry Andric std::vector<llvm::object::BuildID> BinaryIds; 17025f757f3fSDimitry Andric if (Error E = readBinaryIds(BinaryIds)) 17035f757f3fSDimitry Andric return E; 17045f757f3fSDimitry Andric printBinaryIdsInternal(OS, BinaryIds); 17055f757f3fSDimitry Andric return Error::success(); 1706bdd1243dSDimitry Andric } 1707bdd1243dSDimitry Andric 17088bcb0991SDimitry Andric void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) { 17090b57cec5SDimitry Andric uint64_t NumFuncs = 0; 17100b57cec5SDimitry Andric for (const auto &Func : *this) { 17110b57cec5SDimitry Andric if (isIRLevelProfile()) { 17120b57cec5SDimitry Andric bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash); 17130b57cec5SDimitry Andric if (FuncIsCS != IsCS) 17140b57cec5SDimitry Andric continue; 17150b57cec5SDimitry Andric } 17168bcb0991SDimitry Andric Func.accumulateCounts(Sum); 17170b57cec5SDimitry Andric ++NumFuncs; 17180b57cec5SDimitry Andric } 17190b57cec5SDimitry Andric Sum.NumEntries = NumFuncs; 17200b57cec5SDimitry Andric } 1721