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" 170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 185ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 190b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 200b57cec5SDimitry Andric #include "llvm/IR/ProfileSummary.h" 210b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 220b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 230b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 240b57cec5SDimitry Andric #include "llvm/Support/Error.h" 250b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 260b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 270b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h" 28*5f7ddb14SDimitry Andric #include "llvm/Support/SymbolRemappingReader.h" 290b57cec5SDimitry Andric #include <algorithm> 300b57cec5SDimitry Andric #include <cctype> 310b57cec5SDimitry Andric #include <cstddef> 320b57cec5SDimitry Andric #include <cstdint> 330b57cec5SDimitry Andric #include <limits> 340b57cec5SDimitry Andric #include <memory> 350b57cec5SDimitry Andric #include <system_error> 360b57cec5SDimitry Andric #include <utility> 370b57cec5SDimitry Andric #include <vector> 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric using namespace llvm; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>> 420b57cec5SDimitry Andric setupMemoryBuffer(const Twine &Path) { 430b57cec5SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 44*5f7ddb14SDimitry Andric MemoryBuffer::getFileOrSTDIN(Path, /*IsText=*/true); 450b57cec5SDimitry Andric if (std::error_code EC = BufferOrErr.getError()) 460b57cec5SDimitry Andric return errorCodeToError(EC); 470b57cec5SDimitry Andric return std::move(BufferOrErr.get()); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric static Error initializeReader(InstrProfReader &Reader) { 510b57cec5SDimitry Andric return Reader.readHeader(); 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>> 550b57cec5SDimitry Andric InstrProfReader::create(const Twine &Path) { 560b57cec5SDimitry Andric // Set up the buffer to read. 570b57cec5SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path); 580b57cec5SDimitry Andric if (Error E = BufferOrError.takeError()) 590b57cec5SDimitry Andric return std::move(E); 600b57cec5SDimitry Andric return InstrProfReader::create(std::move(BufferOrError.get())); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>> 640b57cec5SDimitry Andric InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) { 650b57cec5SDimitry Andric // Sanity check the buffer. 660b57cec5SDimitry Andric if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max()) 670b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::too_large); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric if (Buffer->getBufferSize() == 0) 700b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::empty_raw_profile); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric std::unique_ptr<InstrProfReader> Result; 730b57cec5SDimitry Andric // Create the reader. 740b57cec5SDimitry Andric if (IndexedInstrProfReader::hasFormat(*Buffer)) 750b57cec5SDimitry Andric Result.reset(new IndexedInstrProfReader(std::move(Buffer))); 760b57cec5SDimitry Andric else if (RawInstrProfReader64::hasFormat(*Buffer)) 770b57cec5SDimitry Andric Result.reset(new RawInstrProfReader64(std::move(Buffer))); 780b57cec5SDimitry Andric else if (RawInstrProfReader32::hasFormat(*Buffer)) 790b57cec5SDimitry Andric Result.reset(new RawInstrProfReader32(std::move(Buffer))); 800b57cec5SDimitry Andric else if (TextInstrProfReader::hasFormat(*Buffer)) 810b57cec5SDimitry Andric Result.reset(new TextInstrProfReader(std::move(Buffer))); 820b57cec5SDimitry Andric else 830b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unrecognized_format); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // Initialize the reader and return the result. 860b57cec5SDimitry Andric if (Error E = initializeReader(*Result)) 870b57cec5SDimitry Andric return std::move(E); 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric return std::move(Result); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>> 930b57cec5SDimitry Andric IndexedInstrProfReader::create(const Twine &Path, const Twine &RemappingPath) { 940b57cec5SDimitry Andric // Set up the buffer to read. 950b57cec5SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path); 960b57cec5SDimitry Andric if (Error E = BufferOrError.takeError()) 970b57cec5SDimitry Andric return std::move(E); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric // Set up the remapping buffer if requested. 1000b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer; 1010b57cec5SDimitry Andric std::string RemappingPathStr = RemappingPath.str(); 1020b57cec5SDimitry Andric if (!RemappingPathStr.empty()) { 1030b57cec5SDimitry Andric auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr); 1040b57cec5SDimitry Andric if (Error E = RemappingBufferOrError.takeError()) 1050b57cec5SDimitry Andric return std::move(E); 1060b57cec5SDimitry Andric RemappingBuffer = std::move(RemappingBufferOrError.get()); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric return IndexedInstrProfReader::create(std::move(BufferOrError.get()), 1100b57cec5SDimitry Andric std::move(RemappingBuffer)); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>> 1140b57cec5SDimitry Andric IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer, 1150b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer) { 1160b57cec5SDimitry Andric // Sanity check the buffer. 1170b57cec5SDimitry Andric if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max()) 1180b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::too_large); 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Create the reader. 1210b57cec5SDimitry Andric if (!IndexedInstrProfReader::hasFormat(*Buffer)) 1220b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic); 1238bcb0991SDimitry Andric auto Result = std::make_unique<IndexedInstrProfReader>( 1240b57cec5SDimitry Andric std::move(Buffer), std::move(RemappingBuffer)); 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric // Initialize the reader and return the result. 1270b57cec5SDimitry Andric if (Error E = initializeReader(*Result)) 1280b57cec5SDimitry Andric return std::move(E); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric return std::move(Result); 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric void InstrProfIterator::Increment() { 1340b57cec5SDimitry Andric if (auto E = Reader->readNextRecord(Record)) { 1350b57cec5SDimitry Andric // Handle errors in the reader. 1360b57cec5SDimitry Andric InstrProfError::take(std::move(E)); 1370b57cec5SDimitry Andric *this = InstrProfIterator(); 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { 1420b57cec5SDimitry Andric // Verify that this really looks like plain ASCII text by checking a 1430b57cec5SDimitry Andric // 'reasonable' number of characters (up to profile magic size). 1440b57cec5SDimitry Andric size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t)); 1450b57cec5SDimitry Andric StringRef buffer = Buffer.getBufferStart(); 1460b57cec5SDimitry Andric return count == 0 || 1470b57cec5SDimitry Andric std::all_of(buffer.begin(), buffer.begin() + count, 1485ffd83dbSDimitry Andric [](char c) { return isPrint(c) || isSpace(c); }); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // Read the profile variant flag from the header: ":FE" means this is a FE 1520b57cec5SDimitry Andric // generated profile. ":IR" means this is an IR level profile. Other strings 1530b57cec5SDimitry Andric // with a leading ':' will be reported an error format. 1540b57cec5SDimitry Andric Error TextInstrProfReader::readHeader() { 1550b57cec5SDimitry Andric Symtab.reset(new InstrProfSymtab()); 1560b57cec5SDimitry Andric bool IsIRInstr = false; 157af732203SDimitry Andric bool IsEntryFirst = false; 158af732203SDimitry Andric bool IsCS = false; 159af732203SDimitry Andric 160af732203SDimitry Andric while (Line->startswith(":")) { 161af732203SDimitry Andric StringRef Str = Line->substr(1); 162*5f7ddb14SDimitry Andric if (Str.equals_insensitive("ir")) 1630b57cec5SDimitry Andric IsIRInstr = true; 164*5f7ddb14SDimitry Andric else if (Str.equals_insensitive("fe")) 1650b57cec5SDimitry Andric IsIRInstr = false; 166*5f7ddb14SDimitry Andric else if (Str.equals_insensitive("csir")) { 1670b57cec5SDimitry Andric IsIRInstr = true; 168af732203SDimitry Andric IsCS = true; 169*5f7ddb14SDimitry Andric } else if (Str.equals_insensitive("entry_first")) 170af732203SDimitry Andric IsEntryFirst = true; 171*5f7ddb14SDimitry Andric else if (Str.equals_insensitive("not_entry_first")) 172af732203SDimitry Andric IsEntryFirst = false; 173af732203SDimitry Andric else 1740b57cec5SDimitry Andric return error(instrprof_error::bad_header); 1750b57cec5SDimitry Andric ++Line; 176af732203SDimitry Andric } 1770b57cec5SDimitry Andric IsIRLevelProfile = IsIRInstr; 178af732203SDimitry Andric InstrEntryBBEnabled = IsEntryFirst; 179af732203SDimitry Andric HasCSIRLevelProfile = IsCS; 1800b57cec5SDimitry Andric return success(); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric Error 1840b57cec5SDimitry Andric TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric #define CHECK_LINE_END(Line) \ 1870b57cec5SDimitry Andric if (Line.is_at_end()) \ 1880b57cec5SDimitry Andric return error(instrprof_error::truncated); 1890b57cec5SDimitry Andric #define READ_NUM(Str, Dst) \ 1900b57cec5SDimitry Andric if ((Str).getAsInteger(10, (Dst))) \ 1910b57cec5SDimitry Andric return error(instrprof_error::malformed); 1920b57cec5SDimitry Andric #define VP_READ_ADVANCE(Val) \ 1930b57cec5SDimitry Andric CHECK_LINE_END(Line); \ 1940b57cec5SDimitry Andric uint32_t Val; \ 1950b57cec5SDimitry Andric READ_NUM((*Line), (Val)); \ 1960b57cec5SDimitry Andric Line++; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric if (Line.is_at_end()) 1990b57cec5SDimitry Andric return success(); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric uint32_t NumValueKinds; 2020b57cec5SDimitry Andric if (Line->getAsInteger(10, NumValueKinds)) { 2030b57cec5SDimitry Andric // No value profile data 2040b57cec5SDimitry Andric return success(); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1) 2070b57cec5SDimitry Andric return error(instrprof_error::malformed); 2080b57cec5SDimitry Andric Line++; 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric for (uint32_t VK = 0; VK < NumValueKinds; VK++) { 2110b57cec5SDimitry Andric VP_READ_ADVANCE(ValueKind); 2120b57cec5SDimitry Andric if (ValueKind > IPVK_Last) 2130b57cec5SDimitry Andric return error(instrprof_error::malformed); 2140b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueSites); 2150b57cec5SDimitry Andric if (!NumValueSites) 2160b57cec5SDimitry Andric continue; 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric Record.reserveSites(VK, NumValueSites); 2190b57cec5SDimitry Andric for (uint32_t S = 0; S < NumValueSites; S++) { 2200b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueData); 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric std::vector<InstrProfValueData> CurrentValues; 2230b57cec5SDimitry Andric for (uint32_t V = 0; V < NumValueData; V++) { 2240b57cec5SDimitry Andric CHECK_LINE_END(Line); 2250b57cec5SDimitry Andric std::pair<StringRef, StringRef> VD = Line->rsplit(':'); 2260b57cec5SDimitry Andric uint64_t TakenCount, Value; 2270b57cec5SDimitry Andric if (ValueKind == IPVK_IndirectCallTarget) { 2280b57cec5SDimitry Andric if (InstrProfSymtab::isExternalSymbol(VD.first)) { 2290b57cec5SDimitry Andric Value = 0; 2300b57cec5SDimitry Andric } else { 2310b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(VD.first)) 2320b57cec5SDimitry Andric return E; 2330b57cec5SDimitry Andric Value = IndexedInstrProf::ComputeHash(VD.first); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric } else { 2360b57cec5SDimitry Andric READ_NUM(VD.first, Value); 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric READ_NUM(VD.second, TakenCount); 2390b57cec5SDimitry Andric CurrentValues.push_back({Value, TakenCount}); 2400b57cec5SDimitry Andric Line++; 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData, 2430b57cec5SDimitry Andric nullptr); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric return success(); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric #undef CHECK_LINE_END 2490b57cec5SDimitry Andric #undef READ_NUM 2500b57cec5SDimitry Andric #undef VP_READ_ADVANCE 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { 2540b57cec5SDimitry Andric // Skip empty lines and comments. 2550b57cec5SDimitry Andric while (!Line.is_at_end() && (Line->empty() || Line->startswith("#"))) 2560b57cec5SDimitry Andric ++Line; 2570b57cec5SDimitry Andric // If we hit EOF while looking for a name, we're done. 2580b57cec5SDimitry Andric if (Line.is_at_end()) { 2590b57cec5SDimitry Andric return error(instrprof_error::eof); 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric // Read the function name. 2630b57cec5SDimitry Andric Record.Name = *Line++; 2640b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(Record.Name)) 2650b57cec5SDimitry Andric return error(std::move(E)); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric // Read the function hash. 2680b57cec5SDimitry Andric if (Line.is_at_end()) 2690b57cec5SDimitry Andric return error(instrprof_error::truncated); 2700b57cec5SDimitry Andric if ((Line++)->getAsInteger(0, Record.Hash)) 2710b57cec5SDimitry Andric return error(instrprof_error::malformed); 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric // Read the number of counters. 2740b57cec5SDimitry Andric uint64_t NumCounters; 2750b57cec5SDimitry Andric if (Line.is_at_end()) 2760b57cec5SDimitry Andric return error(instrprof_error::truncated); 2770b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, NumCounters)) 2780b57cec5SDimitry Andric return error(instrprof_error::malformed); 2790b57cec5SDimitry Andric if (NumCounters == 0) 2800b57cec5SDimitry Andric return error(instrprof_error::malformed); 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric // Read each counter and fill our internal storage with the values. 2830b57cec5SDimitry Andric Record.Clear(); 2840b57cec5SDimitry Andric Record.Counts.reserve(NumCounters); 2850b57cec5SDimitry Andric for (uint64_t I = 0; I < NumCounters; ++I) { 2860b57cec5SDimitry Andric if (Line.is_at_end()) 2870b57cec5SDimitry Andric return error(instrprof_error::truncated); 2880b57cec5SDimitry Andric uint64_t Count; 2890b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, Count)) 2900b57cec5SDimitry Andric return error(instrprof_error::malformed); 2910b57cec5SDimitry Andric Record.Counts.push_back(Count); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric // Check if value profile data exists and read it if so. 2950b57cec5SDimitry Andric if (Error E = readValueProfileData(Record)) 2960b57cec5SDimitry Andric return error(std::move(E)); 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric return success(); 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric template <class IntPtrT> 3020b57cec5SDimitry Andric bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { 3030b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < sizeof(uint64_t)) 3040b57cec5SDimitry Andric return false; 3050b57cec5SDimitry Andric uint64_t Magic = 3060b57cec5SDimitry Andric *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); 3070b57cec5SDimitry Andric return RawInstrProf::getMagic<IntPtrT>() == Magic || 3080b57cec5SDimitry Andric sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric template <class IntPtrT> 3120b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader() { 3130b57cec5SDimitry Andric if (!hasFormat(*DataBuffer)) 3140b57cec5SDimitry Andric return error(instrprof_error::bad_magic); 3150b57cec5SDimitry Andric if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header)) 3160b57cec5SDimitry Andric return error(instrprof_error::bad_header); 3170b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>( 3180b57cec5SDimitry Andric DataBuffer->getBufferStart()); 3190b57cec5SDimitry Andric ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>(); 3200b57cec5SDimitry Andric return readHeader(*Header); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric template <class IntPtrT> 3240b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) { 3250b57cec5SDimitry Andric const char *End = DataBuffer->getBufferEnd(); 3260b57cec5SDimitry Andric // Skip zero padding between profiles. 3270b57cec5SDimitry Andric while (CurrentPos != End && *CurrentPos == 0) 3280b57cec5SDimitry Andric ++CurrentPos; 3290b57cec5SDimitry Andric // If there's nothing left, we're done. 3300b57cec5SDimitry Andric if (CurrentPos == End) 3310b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof); 3320b57cec5SDimitry Andric // If there isn't enough space for another header, this is probably just 3330b57cec5SDimitry Andric // garbage at the end of the file. 3340b57cec5SDimitry Andric if (CurrentPos + sizeof(RawInstrProf::Header) > End) 3350b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 3360b57cec5SDimitry Andric // The writer ensures each profile is padded to start at an aligned address. 3370b57cec5SDimitry Andric if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t)) 3380b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 3390b57cec5SDimitry Andric // The magic should have the same byte order as in the previous header. 3400b57cec5SDimitry Andric uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos); 3410b57cec5SDimitry Andric if (Magic != swap(RawInstrProf::getMagic<IntPtrT>())) 3420b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic); 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric // There's another profile to read, so we need to process the header. 3450b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos); 3460b57cec5SDimitry Andric return readHeader(*Header); 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric template <class IntPtrT> 3500b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { 3510b57cec5SDimitry Andric if (Error E = Symtab.create(StringRef(NamesStart, NamesSize))) 3520b57cec5SDimitry Andric return error(std::move(E)); 3530b57cec5SDimitry Andric for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) { 3540b57cec5SDimitry Andric const IntPtrT FPtr = swap(I->FunctionPointer); 3550b57cec5SDimitry Andric if (!FPtr) 3560b57cec5SDimitry Andric continue; 3570b57cec5SDimitry Andric Symtab.mapAddress(FPtr, I->NameRef); 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric return success(); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric template <class IntPtrT> 3630b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader( 3640b57cec5SDimitry Andric const RawInstrProf::Header &Header) { 3650b57cec5SDimitry Andric Version = swap(Header.Version); 3660b57cec5SDimitry Andric if (GET_VERSION(Version) != RawInstrProf::Version) 3670b57cec5SDimitry Andric return error(instrprof_error::unsupported_version); 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric CountersDelta = swap(Header.CountersDelta); 3700b57cec5SDimitry Andric NamesDelta = swap(Header.NamesDelta); 3710b57cec5SDimitry Andric auto DataSize = swap(Header.DataSize); 372480093f4SDimitry Andric auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters); 3730b57cec5SDimitry Andric auto CountersSize = swap(Header.CountersSize); 374480093f4SDimitry Andric auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters); 3750b57cec5SDimitry Andric NamesSize = swap(Header.NamesSize); 3760b57cec5SDimitry Andric ValueKindLast = swap(Header.ValueKindLast); 377*5f7ddb14SDimitry Andric BinaryIdsSize = swap(Header.BinaryIdsSize); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>); 3800b57cec5SDimitry Andric auto PaddingSize = getNumPaddingBytes(NamesSize); 3810b57cec5SDimitry Andric 382*5f7ddb14SDimitry Andric // Profile data starts after profile header and binary ids if exist. 383*5f7ddb14SDimitry Andric ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdsSize; 384480093f4SDimitry Andric ptrdiff_t CountersOffset = 385480093f4SDimitry Andric DataOffset + DataSizeInBytes + PaddingBytesBeforeCounters; 386480093f4SDimitry Andric ptrdiff_t NamesOffset = CountersOffset + (sizeof(uint64_t) * CountersSize) + 387480093f4SDimitry Andric PaddingBytesAfterCounters; 3880b57cec5SDimitry Andric ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize; 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric auto *Start = reinterpret_cast<const char *>(&Header); 3910b57cec5SDimitry Andric if (Start + ValueDataOffset > DataBuffer->getBufferEnd()) 3920b57cec5SDimitry Andric return error(instrprof_error::bad_header); 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>( 3950b57cec5SDimitry Andric Start + DataOffset); 3960b57cec5SDimitry Andric DataEnd = Data + DataSize; 397*5f7ddb14SDimitry Andric 398*5f7ddb14SDimitry Andric // Binary ids start just after the header. 399*5f7ddb14SDimitry Andric BinaryIdsStart = 400*5f7ddb14SDimitry Andric reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header); 4010b57cec5SDimitry Andric CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset); 4020b57cec5SDimitry Andric NamesStart = Start + NamesOffset; 4030b57cec5SDimitry Andric ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset); 4040b57cec5SDimitry Andric 4058bcb0991SDimitry Andric std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>(); 4060b57cec5SDimitry Andric if (Error E = createSymtab(*NewSymtab.get())) 4070b57cec5SDimitry Andric return E; 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric Symtab = std::move(NewSymtab); 4100b57cec5SDimitry Andric return success(); 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric template <class IntPtrT> 4140b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) { 4150b57cec5SDimitry Andric Record.Name = getName(Data->NameRef); 4160b57cec5SDimitry Andric return success(); 4170b57cec5SDimitry Andric } 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric template <class IntPtrT> 4200b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) { 4210b57cec5SDimitry Andric Record.Hash = swap(Data->FuncHash); 4220b57cec5SDimitry Andric return success(); 4230b57cec5SDimitry Andric } 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric template <class IntPtrT> 4260b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawCounts( 4270b57cec5SDimitry Andric InstrProfRecord &Record) { 4280b57cec5SDimitry Andric uint32_t NumCounters = swap(Data->NumCounters); 4290b57cec5SDimitry Andric IntPtrT CounterPtr = Data->CounterPtr; 4300b57cec5SDimitry Andric if (NumCounters == 0) 4310b57cec5SDimitry Andric return error(instrprof_error::malformed); 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); 4348bcb0991SDimitry Andric ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart; 4350b57cec5SDimitry Andric 4368bcb0991SDimitry Andric // Check bounds. Note that the counter pointer embedded in the data record 4378bcb0991SDimitry Andric // may itself be corrupt. 4385ffd83dbSDimitry Andric if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters) 4390b57cec5SDimitry Andric return error(instrprof_error::malformed); 4408bcb0991SDimitry Andric ptrdiff_t CounterOffset = getCounterOffset(CounterPtr); 4418bcb0991SDimitry Andric if (CounterOffset < 0 || CounterOffset > MaxNumCounters || 4425ffd83dbSDimitry Andric ((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters) 4438bcb0991SDimitry Andric return error(instrprof_error::malformed); 4448bcb0991SDimitry Andric 4458bcb0991SDimitry Andric auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters); 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric if (ShouldSwapBytes) { 4480b57cec5SDimitry Andric Record.Counts.clear(); 4490b57cec5SDimitry Andric Record.Counts.reserve(RawCounts.size()); 4500b57cec5SDimitry Andric for (uint64_t Count : RawCounts) 4510b57cec5SDimitry Andric Record.Counts.push_back(swap(Count)); 4520b57cec5SDimitry Andric } else 4530b57cec5SDimitry Andric Record.Counts = RawCounts; 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric return success(); 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric template <class IntPtrT> 4590b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readValueProfilingData( 4600b57cec5SDimitry Andric InstrProfRecord &Record) { 4610b57cec5SDimitry Andric Record.clearValueData(); 4620b57cec5SDimitry Andric CurValueDataSize = 0; 4630b57cec5SDimitry Andric // Need to match the logic in value profile dumper code in compiler-rt: 4640b57cec5SDimitry Andric uint32_t NumValueKinds = 0; 4650b57cec5SDimitry Andric for (uint32_t I = 0; I < IPVK_Last + 1; I++) 4660b57cec5SDimitry Andric NumValueKinds += (Data->NumValueSites[I] != 0); 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric if (!NumValueKinds) 4690b57cec5SDimitry Andric return success(); 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 4720b57cec5SDimitry Andric ValueProfData::getValueProfData( 4730b57cec5SDimitry Andric ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(), 4740b57cec5SDimitry Andric getDataEndianness()); 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric if (Error E = VDataPtrOrErr.takeError()) 4770b57cec5SDimitry Andric return E; 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric // Note that besides deserialization, this also performs the conversion for 4800b57cec5SDimitry Andric // indirect call targets. The function pointers from the raw profile are 4810b57cec5SDimitry Andric // remapped into function name hashes. 4820b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get()); 4830b57cec5SDimitry Andric CurValueDataSize = VDataPtrOrErr.get()->getSize(); 4840b57cec5SDimitry Andric return success(); 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric template <class IntPtrT> 4880b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) { 4890b57cec5SDimitry Andric if (atEnd()) 4900b57cec5SDimitry Andric // At this point, ValueDataStart field points to the next header. 4910b57cec5SDimitry Andric if (Error E = readNextHeader(getNextHeaderPos())) 4920b57cec5SDimitry Andric return error(std::move(E)); 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric // Read name ad set it in Record. 4950b57cec5SDimitry Andric if (Error E = readName(Record)) 4960b57cec5SDimitry Andric return error(std::move(E)); 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric // Read FuncHash and set it in Record. 4990b57cec5SDimitry Andric if (Error E = readFuncHash(Record)) 5000b57cec5SDimitry Andric return error(std::move(E)); 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric // Read raw counts and set Record. 5030b57cec5SDimitry Andric if (Error E = readRawCounts(Record)) 5040b57cec5SDimitry Andric return error(std::move(E)); 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric // Read value data and set Record. 5070b57cec5SDimitry Andric if (Error E = readValueProfilingData(Record)) 5080b57cec5SDimitry Andric return error(std::move(E)); 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric // Iterate. 5110b57cec5SDimitry Andric advanceData(); 5120b57cec5SDimitry Andric return success(); 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric 515*5f7ddb14SDimitry Andric template <class IntPtrT> 516*5f7ddb14SDimitry Andric Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) { 517*5f7ddb14SDimitry Andric if (BinaryIdsSize == 0) 518*5f7ddb14SDimitry Andric return success(); 519*5f7ddb14SDimitry Andric 520*5f7ddb14SDimitry Andric OS << "Binary IDs: \n"; 521*5f7ddb14SDimitry Andric const uint8_t *BI = BinaryIdsStart; 522*5f7ddb14SDimitry Andric while (BI < BinaryIdsStart + BinaryIdsSize) { 523*5f7ddb14SDimitry Andric uint64_t BinaryIdLen = swap(*reinterpret_cast<const uint64_t *>(BI)); 524*5f7ddb14SDimitry Andric // Increment by binary id length data type size. 525*5f7ddb14SDimitry Andric BI += sizeof(BinaryIdLen); 526*5f7ddb14SDimitry Andric if (BI > (const uint8_t *)DataBuffer->getBufferEnd()) 527*5f7ddb14SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 528*5f7ddb14SDimitry Andric 529*5f7ddb14SDimitry Andric for (uint64_t I = 0; I < BinaryIdLen; I++) 530*5f7ddb14SDimitry Andric OS << format("%02x", BI[I]); 531*5f7ddb14SDimitry Andric OS << "\n"; 532*5f7ddb14SDimitry Andric 533*5f7ddb14SDimitry Andric // Increment by binary id data length. 534*5f7ddb14SDimitry Andric BI += BinaryIdLen; 535*5f7ddb14SDimitry Andric if (BI > (const uint8_t *)DataBuffer->getBufferEnd()) 536*5f7ddb14SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 537*5f7ddb14SDimitry Andric } 538*5f7ddb14SDimitry Andric 539*5f7ddb14SDimitry Andric return success(); 540*5f7ddb14SDimitry Andric } 541*5f7ddb14SDimitry Andric 5420b57cec5SDimitry Andric namespace llvm { 5430b57cec5SDimitry Andric 5440b57cec5SDimitry Andric template class RawInstrProfReader<uint32_t>; 5450b57cec5SDimitry Andric template class RawInstrProfReader<uint64_t>; 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric } // end namespace llvm 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric InstrProfLookupTrait::hash_value_type 5500b57cec5SDimitry Andric InstrProfLookupTrait::ComputeHash(StringRef K) { 5510b57cec5SDimitry Andric return IndexedInstrProf::ComputeHash(HashType, K); 5520b57cec5SDimitry Andric } 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric using data_type = InstrProfLookupTrait::data_type; 5550b57cec5SDimitry Andric using offset_type = InstrProfLookupTrait::offset_type; 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric bool InstrProfLookupTrait::readValueProfilingData( 5580b57cec5SDimitry Andric const unsigned char *&D, const unsigned char *const End) { 5590b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 5600b57cec5SDimitry Andric ValueProfData::getValueProfData(D, End, ValueProfDataEndianness); 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric if (VDataPtrOrErr.takeError()) 5630b57cec5SDimitry Andric return false; 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr); 5660b57cec5SDimitry Andric D += VDataPtrOrErr.get()->TotalSize; 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric return true; 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, 5720b57cec5SDimitry Andric offset_type N) { 5730b57cec5SDimitry Andric using namespace support; 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric // Check if the data is corrupt. If so, don't try to read it. 5760b57cec5SDimitry Andric if (N % sizeof(uint64_t)) 5770b57cec5SDimitry Andric return data_type(); 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric DataBuffer.clear(); 5800b57cec5SDimitry Andric std::vector<uint64_t> CounterBuffer; 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric const unsigned char *End = D + N; 5830b57cec5SDimitry Andric while (D < End) { 5840b57cec5SDimitry Andric // Read hash. 5850b57cec5SDimitry Andric if (D + sizeof(uint64_t) >= End) 5860b57cec5SDimitry Andric return data_type(); 5870b57cec5SDimitry Andric uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D); 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric // Initialize number of counters for GET_VERSION(FormatVersion) == 1. 5900b57cec5SDimitry Andric uint64_t CountsSize = N / sizeof(uint64_t) - 1; 5910b57cec5SDimitry Andric // If format version is different then read the number of counters. 5920b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) { 5930b57cec5SDimitry Andric if (D + sizeof(uint64_t) > End) 5940b57cec5SDimitry Andric return data_type(); 5950b57cec5SDimitry Andric CountsSize = endian::readNext<uint64_t, little, unaligned>(D); 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric // Read counter values. 5980b57cec5SDimitry Andric if (D + CountsSize * sizeof(uint64_t) > End) 5990b57cec5SDimitry Andric return data_type(); 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric CounterBuffer.clear(); 6020b57cec5SDimitry Andric CounterBuffer.reserve(CountsSize); 6030b57cec5SDimitry Andric for (uint64_t J = 0; J < CountsSize; ++J) 6040b57cec5SDimitry Andric CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D)); 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer)); 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric // Read value profiling data. 6090b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 && 6100b57cec5SDimitry Andric !readValueProfilingData(D, End)) { 6110b57cec5SDimitry Andric DataBuffer.clear(); 6120b57cec5SDimitry Andric return data_type(); 6130b57cec5SDimitry Andric } 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric return DataBuffer; 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric template <typename HashTableImpl> 6190b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords( 6200b57cec5SDimitry Andric StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) { 6210b57cec5SDimitry Andric auto Iter = HashTable->find(FuncName); 6220b57cec5SDimitry Andric if (Iter == HashTable->end()) 6230b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unknown_function); 6240b57cec5SDimitry Andric 6250b57cec5SDimitry Andric Data = (*Iter); 6260b57cec5SDimitry Andric if (Data.empty()) 6270b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric return Error::success(); 6300b57cec5SDimitry Andric } 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric template <typename HashTableImpl> 6330b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords( 6340b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) { 6350b57cec5SDimitry Andric if (atEnd()) 6360b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof); 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric Data = *RecordIterator; 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric if (Data.empty()) 6410b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed); 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric return Error::success(); 6440b57cec5SDimitry Andric } 6450b57cec5SDimitry Andric 6460b57cec5SDimitry Andric template <typename HashTableImpl> 6470b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex( 6480b57cec5SDimitry Andric const unsigned char *Buckets, const unsigned char *const Payload, 6490b57cec5SDimitry Andric const unsigned char *const Base, IndexedInstrProf::HashT HashType, 6500b57cec5SDimitry Andric uint64_t Version) { 6510b57cec5SDimitry Andric FormatVersion = Version; 6520b57cec5SDimitry Andric HashTable.reset(HashTableImpl::Create( 6530b57cec5SDimitry Andric Buckets, Payload, Base, 6540b57cec5SDimitry Andric typename HashTableImpl::InfoType(HashType, Version))); 6550b57cec5SDimitry Andric RecordIterator = HashTable->data_begin(); 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric namespace { 6590b57cec5SDimitry Andric /// A remapper that does not apply any remappings. 6600b57cec5SDimitry Andric class InstrProfReaderNullRemapper : public InstrProfReaderRemapper { 6610b57cec5SDimitry Andric InstrProfReaderIndexBase &Underlying; 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric public: 6640b57cec5SDimitry Andric InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying) 6650b57cec5SDimitry Andric : Underlying(Underlying) {} 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric Error getRecords(StringRef FuncName, 6680b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override { 6690b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data); 6700b57cec5SDimitry Andric } 6710b57cec5SDimitry Andric }; 6720b57cec5SDimitry Andric } 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric /// A remapper that applies remappings based on a symbol remapping file. 6750b57cec5SDimitry Andric template <typename HashTableImpl> 6760b57cec5SDimitry Andric class llvm::InstrProfReaderItaniumRemapper 6770b57cec5SDimitry Andric : public InstrProfReaderRemapper { 6780b57cec5SDimitry Andric public: 6790b57cec5SDimitry Andric InstrProfReaderItaniumRemapper( 6800b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer, 6810b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying) 6820b57cec5SDimitry Andric : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) { 6830b57cec5SDimitry Andric } 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric /// Extract the original function name from a PGO function name. 6860b57cec5SDimitry Andric static StringRef extractName(StringRef Name) { 6870b57cec5SDimitry Andric // We can have multiple :-separated pieces; there can be pieces both 6880b57cec5SDimitry Andric // before and after the mangled name. Find the first part that starts 6890b57cec5SDimitry Andric // with '_Z'; we'll assume that's the mangled name we want. 6900b57cec5SDimitry Andric std::pair<StringRef, StringRef> Parts = {StringRef(), Name}; 6910b57cec5SDimitry Andric while (true) { 6920b57cec5SDimitry Andric Parts = Parts.second.split(':'); 6930b57cec5SDimitry Andric if (Parts.first.startswith("_Z")) 6940b57cec5SDimitry Andric return Parts.first; 6950b57cec5SDimitry Andric if (Parts.second.empty()) 6960b57cec5SDimitry Andric return Name; 6970b57cec5SDimitry Andric } 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric /// Given a mangled name extracted from a PGO function name, and a new 7010b57cec5SDimitry Andric /// form for that mangled name, reconstitute the name. 7020b57cec5SDimitry Andric static void reconstituteName(StringRef OrigName, StringRef ExtractedName, 7030b57cec5SDimitry Andric StringRef Replacement, 7040b57cec5SDimitry Andric SmallVectorImpl<char> &Out) { 7050b57cec5SDimitry Andric Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size()); 7060b57cec5SDimitry Andric Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin()); 7070b57cec5SDimitry Andric Out.insert(Out.end(), Replacement.begin(), Replacement.end()); 7080b57cec5SDimitry Andric Out.insert(Out.end(), ExtractedName.end(), OrigName.end()); 7090b57cec5SDimitry Andric } 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric Error populateRemappings() override { 7120b57cec5SDimitry Andric if (Error E = Remappings.read(*RemapBuffer)) 7130b57cec5SDimitry Andric return E; 7140b57cec5SDimitry Andric for (StringRef Name : Underlying.HashTable->keys()) { 7150b57cec5SDimitry Andric StringRef RealName = extractName(Name); 7160b57cec5SDimitry Andric if (auto Key = Remappings.insert(RealName)) { 7170b57cec5SDimitry Andric // FIXME: We could theoretically map the same equivalence class to 7180b57cec5SDimitry Andric // multiple names in the profile data. If that happens, we should 7190b57cec5SDimitry Andric // return NamedInstrProfRecords from all of them. 7200b57cec5SDimitry Andric MappedNames.insert({Key, RealName}); 7210b57cec5SDimitry Andric } 7220b57cec5SDimitry Andric } 7230b57cec5SDimitry Andric return Error::success(); 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric Error getRecords(StringRef FuncName, 7270b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override { 7280b57cec5SDimitry Andric StringRef RealName = extractName(FuncName); 7290b57cec5SDimitry Andric if (auto Key = Remappings.lookup(RealName)) { 7300b57cec5SDimitry Andric StringRef Remapped = MappedNames.lookup(Key); 7310b57cec5SDimitry Andric if (!Remapped.empty()) { 7320b57cec5SDimitry Andric if (RealName.begin() == FuncName.begin() && 7330b57cec5SDimitry Andric RealName.end() == FuncName.end()) 7340b57cec5SDimitry Andric FuncName = Remapped; 7350b57cec5SDimitry Andric else { 7360b57cec5SDimitry Andric // Try rebuilding the name from the given remapping. 7370b57cec5SDimitry Andric SmallString<256> Reconstituted; 7380b57cec5SDimitry Andric reconstituteName(FuncName, RealName, Remapped, Reconstituted); 7390b57cec5SDimitry Andric Error E = Underlying.getRecords(Reconstituted, Data); 7400b57cec5SDimitry Andric if (!E) 7410b57cec5SDimitry Andric return E; 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric // If we failed because the name doesn't exist, fall back to asking 7440b57cec5SDimitry Andric // about the original name. 7450b57cec5SDimitry Andric if (Error Unhandled = handleErrors( 7460b57cec5SDimitry Andric std::move(E), [](std::unique_ptr<InstrProfError> Err) { 7470b57cec5SDimitry Andric return Err->get() == instrprof_error::unknown_function 7480b57cec5SDimitry Andric ? Error::success() 7490b57cec5SDimitry Andric : Error(std::move(Err)); 7500b57cec5SDimitry Andric })) 7510b57cec5SDimitry Andric return Unhandled; 7520b57cec5SDimitry Andric } 7530b57cec5SDimitry Andric } 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data); 7560b57cec5SDimitry Andric } 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric private: 7590b57cec5SDimitry Andric /// The memory buffer containing the remapping configuration. Remappings 7600b57cec5SDimitry Andric /// holds pointers into this buffer. 7610b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer; 7620b57cec5SDimitry Andric 7630b57cec5SDimitry Andric /// The mangling remapper. 7640b57cec5SDimitry Andric SymbolRemappingReader Remappings; 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric /// Mapping from mangled name keys to the name used for the key in the 7670b57cec5SDimitry Andric /// profile data. 7680b57cec5SDimitry Andric /// FIXME: Can we store a location within the on-disk hash table instead of 7690b57cec5SDimitry Andric /// redoing lookup? 7700b57cec5SDimitry Andric DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames; 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric /// The real profile data reader. 7730b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying; 7740b57cec5SDimitry Andric }; 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { 7770b57cec5SDimitry Andric using namespace support; 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < 8) 7800b57cec5SDimitry Andric return false; 7810b57cec5SDimitry Andric uint64_t Magic = 7820b57cec5SDimitry Andric endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart()); 7830b57cec5SDimitry Andric // Verify that it's magical. 7840b57cec5SDimitry Andric return Magic == IndexedInstrProf::Magic; 7850b57cec5SDimitry Andric } 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric const unsigned char * 7880b57cec5SDimitry Andric IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, 7890b57cec5SDimitry Andric const unsigned char *Cur, bool UseCS) { 7900b57cec5SDimitry Andric using namespace IndexedInstrProf; 7910b57cec5SDimitry Andric using namespace support; 7920b57cec5SDimitry Andric 7930b57cec5SDimitry Andric if (Version >= IndexedInstrProf::Version4) { 7940b57cec5SDimitry Andric const IndexedInstrProf::Summary *SummaryInLE = 7950b57cec5SDimitry Andric reinterpret_cast<const IndexedInstrProf::Summary *>(Cur); 7960b57cec5SDimitry Andric uint64_t NFields = 7970b57cec5SDimitry Andric endian::byte_swap<uint64_t, little>(SummaryInLE->NumSummaryFields); 7980b57cec5SDimitry Andric uint64_t NEntries = 7990b57cec5SDimitry Andric endian::byte_swap<uint64_t, little>(SummaryInLE->NumCutoffEntries); 8000b57cec5SDimitry Andric uint32_t SummarySize = 8010b57cec5SDimitry Andric IndexedInstrProf::Summary::getSize(NFields, NEntries); 8020b57cec5SDimitry Andric std::unique_ptr<IndexedInstrProf::Summary> SummaryData = 8030b57cec5SDimitry Andric IndexedInstrProf::allocSummary(SummarySize); 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE); 8060b57cec5SDimitry Andric uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get()); 8070b57cec5SDimitry Andric for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) 8080b57cec5SDimitry Andric Dst[I] = endian::byte_swap<uint64_t, little>(Src[I]); 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric SummaryEntryVector DetailedSummary; 8110b57cec5SDimitry Andric for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) { 8120b57cec5SDimitry Andric const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I); 8130b57cec5SDimitry Andric DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount, 8140b57cec5SDimitry Andric Ent.NumBlocks); 8150b57cec5SDimitry Andric } 8160b57cec5SDimitry Andric std::unique_ptr<llvm::ProfileSummary> &Summary = 8170b57cec5SDimitry Andric UseCS ? this->CS_Summary : this->Summary; 8180b57cec5SDimitry Andric 8190b57cec5SDimitry Andric // initialize InstrProfSummary using the SummaryData from disk. 8208bcb0991SDimitry Andric Summary = std::make_unique<ProfileSummary>( 8210b57cec5SDimitry Andric UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr, 8220b57cec5SDimitry Andric DetailedSummary, SummaryData->get(Summary::TotalBlockCount), 8230b57cec5SDimitry Andric SummaryData->get(Summary::MaxBlockCount), 8240b57cec5SDimitry Andric SummaryData->get(Summary::MaxInternalBlockCount), 8250b57cec5SDimitry Andric SummaryData->get(Summary::MaxFunctionCount), 8260b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumBlocks), 8270b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumFunctions)); 8280b57cec5SDimitry Andric return Cur + SummarySize; 8290b57cec5SDimitry Andric } else { 8308bcb0991SDimitry Andric // The older versions do not support a profile summary. This just computes 8318bcb0991SDimitry Andric // an empty summary, which will not result in accurate hot/cold detection. 8328bcb0991SDimitry Andric // We would need to call addRecord for all NamedInstrProfRecords to get the 8338bcb0991SDimitry Andric // correct summary. However, this version is old (prior to early 2016) and 8348bcb0991SDimitry Andric // has not been supporting an accurate summary for several years. 8350b57cec5SDimitry Andric InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 8368bcb0991SDimitry Andric Summary = Builder.getSummary(); 8370b57cec5SDimitry Andric return Cur; 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric } 8400b57cec5SDimitry Andric 8410b57cec5SDimitry Andric Error IndexedInstrProfReader::readHeader() { 8420b57cec5SDimitry Andric using namespace support; 8430b57cec5SDimitry Andric 8440b57cec5SDimitry Andric const unsigned char *Start = 8450b57cec5SDimitry Andric (const unsigned char *)DataBuffer->getBufferStart(); 8460b57cec5SDimitry Andric const unsigned char *Cur = Start; 8470b57cec5SDimitry Andric if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24) 8480b57cec5SDimitry Andric return error(instrprof_error::truncated); 8490b57cec5SDimitry Andric 8500b57cec5SDimitry Andric auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur); 8510b57cec5SDimitry Andric Cur += sizeof(IndexedInstrProf::Header); 8520b57cec5SDimitry Andric 8530b57cec5SDimitry Andric // Check the magic number. 8540b57cec5SDimitry Andric uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic); 8550b57cec5SDimitry Andric if (Magic != IndexedInstrProf::Magic) 8560b57cec5SDimitry Andric return error(instrprof_error::bad_magic); 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric // Read the version. 8590b57cec5SDimitry Andric uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version); 8600b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) > 8610b57cec5SDimitry Andric IndexedInstrProf::ProfVersion::CurrentVersion) 8620b57cec5SDimitry Andric return error(instrprof_error::unsupported_version); 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, 8650b57cec5SDimitry Andric /* UseCS */ false); 8660b57cec5SDimitry Andric if (FormatVersion & VARIANT_MASK_CSIR_PROF) 8670b57cec5SDimitry Andric Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, 8680b57cec5SDimitry Andric /* UseCS */ true); 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric // Read the hash type and start offset. 8710b57cec5SDimitry Andric IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>( 8720b57cec5SDimitry Andric endian::byte_swap<uint64_t, little>(Header->HashType)); 8730b57cec5SDimitry Andric if (HashType > IndexedInstrProf::HashT::Last) 8740b57cec5SDimitry Andric return error(instrprof_error::unsupported_hash_type); 8750b57cec5SDimitry Andric 8760b57cec5SDimitry Andric uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset); 8770b57cec5SDimitry Andric 8780b57cec5SDimitry Andric // The rest of the file is an on disk hash table. 8790b57cec5SDimitry Andric auto IndexPtr = 8808bcb0991SDimitry Andric std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>( 8810b57cec5SDimitry Andric Start + HashOffset, Cur, Start, HashType, FormatVersion); 8820b57cec5SDimitry Andric 8830b57cec5SDimitry Andric // Load the remapping table now if requested. 8840b57cec5SDimitry Andric if (RemappingBuffer) { 8858bcb0991SDimitry Andric Remapper = std::make_unique< 8860b57cec5SDimitry Andric InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>( 8870b57cec5SDimitry Andric std::move(RemappingBuffer), *IndexPtr); 8880b57cec5SDimitry Andric if (Error E = Remapper->populateRemappings()) 8890b57cec5SDimitry Andric return E; 8900b57cec5SDimitry Andric } else { 8918bcb0991SDimitry Andric Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr); 8920b57cec5SDimitry Andric } 8930b57cec5SDimitry Andric Index = std::move(IndexPtr); 8940b57cec5SDimitry Andric 8950b57cec5SDimitry Andric return success(); 8960b57cec5SDimitry Andric } 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric InstrProfSymtab &IndexedInstrProfReader::getSymtab() { 8990b57cec5SDimitry Andric if (Symtab.get()) 9000b57cec5SDimitry Andric return *Symtab.get(); 9010b57cec5SDimitry Andric 9028bcb0991SDimitry Andric std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>(); 9030b57cec5SDimitry Andric if (Error E = Index->populateSymtab(*NewSymtab.get())) { 9040b57cec5SDimitry Andric consumeError(error(InstrProfError::take(std::move(E)))); 9050b57cec5SDimitry Andric } 9060b57cec5SDimitry Andric 9070b57cec5SDimitry Andric Symtab = std::move(NewSymtab); 9080b57cec5SDimitry Andric return *Symtab.get(); 9090b57cec5SDimitry Andric } 9100b57cec5SDimitry Andric 9110b57cec5SDimitry Andric Expected<InstrProfRecord> 9120b57cec5SDimitry Andric IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, 9130b57cec5SDimitry Andric uint64_t FuncHash) { 9140b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data; 9150b57cec5SDimitry Andric Error Err = Remapper->getRecords(FuncName, Data); 9160b57cec5SDimitry Andric if (Err) 9170b57cec5SDimitry Andric return std::move(Err); 9180b57cec5SDimitry Andric // Found it. Look for counters with the right hash. 9190b57cec5SDimitry Andric for (unsigned I = 0, E = Data.size(); I < E; ++I) { 9200b57cec5SDimitry Andric // Check for a match and fill the vector if there is one. 9210b57cec5SDimitry Andric if (Data[I].Hash == FuncHash) { 9220b57cec5SDimitry Andric return std::move(Data[I]); 9230b57cec5SDimitry Andric } 9240b57cec5SDimitry Andric } 9250b57cec5SDimitry Andric return error(instrprof_error::hash_mismatch); 9260b57cec5SDimitry Andric } 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, 9290b57cec5SDimitry Andric uint64_t FuncHash, 9300b57cec5SDimitry Andric std::vector<uint64_t> &Counts) { 9310b57cec5SDimitry Andric Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash); 9320b57cec5SDimitry Andric if (Error E = Record.takeError()) 9330b57cec5SDimitry Andric return error(std::move(E)); 9340b57cec5SDimitry Andric 9350b57cec5SDimitry Andric Counts = Record.get().Counts; 9360b57cec5SDimitry Andric return success(); 9370b57cec5SDimitry Andric } 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { 9400b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data; 9410b57cec5SDimitry Andric 9420b57cec5SDimitry Andric Error E = Index->getRecords(Data); 9430b57cec5SDimitry Andric if (E) 9440b57cec5SDimitry Andric return error(std::move(E)); 9450b57cec5SDimitry Andric 9460b57cec5SDimitry Andric Record = Data[RecordIndex++]; 9470b57cec5SDimitry Andric if (RecordIndex >= Data.size()) { 9480b57cec5SDimitry Andric Index->advanceToNextKey(); 9490b57cec5SDimitry Andric RecordIndex = 0; 9500b57cec5SDimitry Andric } 9510b57cec5SDimitry Andric return success(); 9520b57cec5SDimitry Andric } 9530b57cec5SDimitry Andric 9548bcb0991SDimitry Andric void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) { 9550b57cec5SDimitry Andric uint64_t NumFuncs = 0; 9560b57cec5SDimitry Andric for (const auto &Func : *this) { 9570b57cec5SDimitry Andric if (isIRLevelProfile()) { 9580b57cec5SDimitry Andric bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash); 9590b57cec5SDimitry Andric if (FuncIsCS != IsCS) 9600b57cec5SDimitry Andric continue; 9610b57cec5SDimitry Andric } 9628bcb0991SDimitry Andric Func.accumulateCounts(Sum); 9630b57cec5SDimitry Andric ++NumFuncs; 9640b57cec5SDimitry Andric } 9650b57cec5SDimitry Andric Sum.NumEntries = NumFuncs; 9660b57cec5SDimitry Andric } 967