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"
23fe013be4SDimitry 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"
270b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
280b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h"
29fe013be4SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
300b57cec5SDimitry Andric #include <algorithm>
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
41c9157d92SDimitry Andric // Extracts the variant information from the top 32 bits in the version and
421fd87a68SDimitry Andric // returns an enum specifying the variants present.
getProfileKindFromVersion(uint64_t Version)431fd87a68SDimitry Andric static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
441fd87a68SDimitry Andric InstrProfKind ProfileKind = InstrProfKind::Unknown;
451fd87a68SDimitry Andric if (Version & VARIANT_MASK_IR_PROF) {
4681ad6265SDimitry Andric ProfileKind |= InstrProfKind::IRInstrumentation;
471fd87a68SDimitry Andric }
481fd87a68SDimitry Andric if (Version & VARIANT_MASK_CSIR_PROF) {
4981ad6265SDimitry Andric ProfileKind |= InstrProfKind::ContextSensitive;
501fd87a68SDimitry Andric }
511fd87a68SDimitry Andric if (Version & VARIANT_MASK_INSTR_ENTRY) {
5281ad6265SDimitry Andric ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
531fd87a68SDimitry Andric }
541fd87a68SDimitry Andric if (Version & VARIANT_MASK_BYTE_COVERAGE) {
551fd87a68SDimitry Andric ProfileKind |= InstrProfKind::SingleByteCoverage;
561fd87a68SDimitry Andric }
571fd87a68SDimitry Andric if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
581fd87a68SDimitry Andric ProfileKind |= InstrProfKind::FunctionEntryOnly;
591fd87a68SDimitry Andric }
6081ad6265SDimitry Andric if (Version & VARIANT_MASK_MEMPROF) {
6181ad6265SDimitry Andric ProfileKind |= InstrProfKind::MemProf;
6281ad6265SDimitry Andric }
63fe013be4SDimitry Andric if (Version & VARIANT_MASK_TEMPORAL_PROF) {
64fe013be4SDimitry Andric ProfileKind |= InstrProfKind::TemporalProfile;
65fe013be4SDimitry Andric }
661fd87a68SDimitry Andric return ProfileKind;
671fd87a68SDimitry Andric }
681fd87a68SDimitry Andric
690b57cec5SDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>>
setupMemoryBuffer(const Twine & Filename,vfs::FileSystem & FS)70fe013be4SDimitry Andric setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) {
71fe013be4SDimitry Andric auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
72fe013be4SDimitry Andric : FS.getBufferForFile(Filename);
730b57cec5SDimitry Andric if (std::error_code EC = BufferOrErr.getError())
740b57cec5SDimitry Andric return errorCodeToError(EC);
750b57cec5SDimitry Andric return std::move(BufferOrErr.get());
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
initializeReader(InstrProfReader & Reader)780b57cec5SDimitry Andric static Error initializeReader(InstrProfReader &Reader) {
790b57cec5SDimitry Andric return Reader.readHeader();
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
82bdd1243dSDimitry Andric /// Read a list of binary ids from a profile that consist of
83bdd1243dSDimitry Andric /// a. uint64_t binary id length
84bdd1243dSDimitry Andric /// b. uint8_t binary id data
85bdd1243dSDimitry Andric /// c. uint8_t padding (if necessary)
86bdd1243dSDimitry Andric /// This function is shared between raw and indexed profiles.
87bdd1243dSDimitry Andric /// Raw profiles are in host-endian format, and indexed profiles are in
88bdd1243dSDimitry Andric /// little-endian format. So, this function takes an argument indicating the
89bdd1243dSDimitry Andric /// associated endian format to read the binary ids correctly.
90bdd1243dSDimitry Andric static Error
readBinaryIdsInternal(const MemoryBuffer & DataBuffer,const uint64_t BinaryIdsSize,const uint8_t * BinaryIdsStart,std::vector<llvm::object::BuildID> & BinaryIds,const llvm::endianness Endian)91bdd1243dSDimitry Andric readBinaryIdsInternal(const MemoryBuffer &DataBuffer,
92bdd1243dSDimitry Andric const uint64_t BinaryIdsSize,
93bdd1243dSDimitry Andric const uint8_t *BinaryIdsStart,
94bdd1243dSDimitry Andric std::vector<llvm::object::BuildID> &BinaryIds,
95c9157d92SDimitry Andric const llvm::endianness Endian) {
96bdd1243dSDimitry Andric using namespace support;
97bdd1243dSDimitry Andric
98bdd1243dSDimitry Andric if (BinaryIdsSize == 0)
99bdd1243dSDimitry Andric return Error::success();
100bdd1243dSDimitry Andric
101bdd1243dSDimitry Andric const uint8_t *BI = BinaryIdsStart;
102bdd1243dSDimitry Andric const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
103bdd1243dSDimitry Andric const uint8_t *End =
104bdd1243dSDimitry Andric reinterpret_cast<const uint8_t *>(DataBuffer.getBufferEnd());
105bdd1243dSDimitry Andric
106bdd1243dSDimitry Andric while (BI < BIEnd) {
107bdd1243dSDimitry Andric size_t Remaining = BIEnd - BI;
108bdd1243dSDimitry Andric // There should be enough left to read the binary id length.
109bdd1243dSDimitry Andric if (Remaining < sizeof(uint64_t))
110bdd1243dSDimitry Andric return make_error<InstrProfError>(
111bdd1243dSDimitry Andric instrprof_error::malformed,
112bdd1243dSDimitry Andric "not enough data to read binary id length");
113bdd1243dSDimitry Andric
114bdd1243dSDimitry Andric uint64_t BILen = 0;
115c9157d92SDimitry Andric if (Endian == llvm::endianness::little)
116c9157d92SDimitry Andric BILen =
117c9157d92SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little, unaligned>(BI);
118bdd1243dSDimitry Andric else
119c9157d92SDimitry Andric BILen = endian::readNext<uint64_t, llvm::endianness::big, unaligned>(BI);
120bdd1243dSDimitry Andric
121bdd1243dSDimitry Andric if (BILen == 0)
122bdd1243dSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed,
123bdd1243dSDimitry Andric "binary id length is 0");
124bdd1243dSDimitry Andric
125bdd1243dSDimitry Andric Remaining = BIEnd - BI;
126bdd1243dSDimitry Andric // There should be enough left to read the binary id data.
127bdd1243dSDimitry Andric if (Remaining < alignToPowerOf2(BILen, sizeof(uint64_t)))
128bdd1243dSDimitry Andric return make_error<InstrProfError>(
129bdd1243dSDimitry Andric instrprof_error::malformed, "not enough data to read binary id data");
130bdd1243dSDimitry Andric
131bdd1243dSDimitry Andric // Add binary id to the binary ids list.
132bdd1243dSDimitry Andric BinaryIds.push_back(object::BuildID(BI, BI + BILen));
133bdd1243dSDimitry Andric
134bdd1243dSDimitry Andric // Increment by binary id data length, which aligned to the size of uint64.
135bdd1243dSDimitry Andric BI += alignToPowerOf2(BILen, sizeof(uint64_t));
136bdd1243dSDimitry Andric if (BI > End)
137bdd1243dSDimitry Andric return make_error<InstrProfError>(
138bdd1243dSDimitry Andric instrprof_error::malformed,
139bdd1243dSDimitry Andric "binary id section is greater than buffer size");
140bdd1243dSDimitry Andric }
141bdd1243dSDimitry Andric
142bdd1243dSDimitry Andric return Error::success();
143bdd1243dSDimitry Andric }
144bdd1243dSDimitry Andric
145c9157d92SDimitry Andric static void
printBinaryIdsInternal(raw_ostream & OS,std::vector<llvm::object::BuildID> & BinaryIds)146c9157d92SDimitry Andric printBinaryIdsInternal(raw_ostream &OS,
147c9157d92SDimitry Andric std::vector<llvm::object::BuildID> &BinaryIds) {
148bdd1243dSDimitry Andric OS << "Binary IDs: \n";
149bdd1243dSDimitry Andric for (auto BI : BinaryIds) {
150bdd1243dSDimitry Andric for (uint64_t I = 0; I < BI.size(); I++)
151bdd1243dSDimitry Andric OS << format("%02x", BI[I]);
152bdd1243dSDimitry Andric OS << "\n";
153bdd1243dSDimitry Andric }
154bdd1243dSDimitry Andric }
155bdd1243dSDimitry Andric
1560b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>>
create(const Twine & Path,vfs::FileSystem & FS,const InstrProfCorrelator * Correlator,std::function<void (Error)> Warn)157fe013be4SDimitry Andric InstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
158c9157d92SDimitry Andric const InstrProfCorrelator *Correlator,
159c9157d92SDimitry Andric std::function<void(Error)> Warn) {
1600b57cec5SDimitry Andric // Set up the buffer to read.
161fe013be4SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path, FS);
1620b57cec5SDimitry Andric if (Error E = BufferOrError.takeError())
1630b57cec5SDimitry Andric return std::move(E);
164c9157d92SDimitry Andric return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
165c9157d92SDimitry Andric Warn);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,const InstrProfCorrelator * Correlator,std::function<void (Error)> Warn)1690eae32dcSDimitry Andric InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
170c9157d92SDimitry Andric const InstrProfCorrelator *Correlator,
171c9157d92SDimitry Andric std::function<void(Error)> Warn) {
1720b57cec5SDimitry Andric if (Buffer->getBufferSize() == 0)
1730b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric std::unique_ptr<InstrProfReader> Result;
1760b57cec5SDimitry Andric // Create the reader.
1770b57cec5SDimitry Andric if (IndexedInstrProfReader::hasFormat(*Buffer))
1780b57cec5SDimitry Andric Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
1790b57cec5SDimitry Andric else if (RawInstrProfReader64::hasFormat(*Buffer))
180c9157d92SDimitry Andric Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn));
1810b57cec5SDimitry Andric else if (RawInstrProfReader32::hasFormat(*Buffer))
182c9157d92SDimitry Andric Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn));
1830b57cec5SDimitry Andric else if (TextInstrProfReader::hasFormat(*Buffer))
1840b57cec5SDimitry Andric Result.reset(new TextInstrProfReader(std::move(Buffer)));
1850b57cec5SDimitry Andric else
1860b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unrecognized_format);
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric // Initialize the reader and return the result.
1890b57cec5SDimitry Andric if (Error E = initializeReader(*Result))
1900b57cec5SDimitry Andric return std::move(E);
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric return std::move(Result);
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric
1950b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>>
create(const Twine & Path,vfs::FileSystem & FS,const Twine & RemappingPath)196fe013be4SDimitry Andric IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
197fe013be4SDimitry Andric const Twine &RemappingPath) {
1980b57cec5SDimitry Andric // Set up the buffer to read.
199fe013be4SDimitry Andric auto BufferOrError = setupMemoryBuffer(Path, FS);
2000b57cec5SDimitry Andric if (Error E = BufferOrError.takeError())
2010b57cec5SDimitry Andric return std::move(E);
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric // Set up the remapping buffer if requested.
2040b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer;
2050b57cec5SDimitry Andric std::string RemappingPathStr = RemappingPath.str();
2060b57cec5SDimitry Andric if (!RemappingPathStr.empty()) {
207fe013be4SDimitry Andric auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS);
2080b57cec5SDimitry Andric if (Error E = RemappingBufferOrError.takeError())
2090b57cec5SDimitry Andric return std::move(E);
2100b57cec5SDimitry Andric RemappingBuffer = std::move(RemappingBufferOrError.get());
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
2140b57cec5SDimitry Andric std::move(RemappingBuffer));
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<MemoryBuffer> RemappingBuffer)2180b57cec5SDimitry Andric IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
2190b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemappingBuffer) {
2200b57cec5SDimitry Andric // Create the reader.
2210b57cec5SDimitry Andric if (!IndexedInstrProfReader::hasFormat(*Buffer))
2220b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic);
2238bcb0991SDimitry Andric auto Result = std::make_unique<IndexedInstrProfReader>(
2240b57cec5SDimitry Andric std::move(Buffer), std::move(RemappingBuffer));
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric // Initialize the reader and return the result.
2270b57cec5SDimitry Andric if (Error E = initializeReader(*Result))
2280b57cec5SDimitry Andric return std::move(E);
2290b57cec5SDimitry Andric
2300b57cec5SDimitry Andric return std::move(Result);
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric
hasFormat(const MemoryBuffer & Buffer)2330b57cec5SDimitry Andric bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
2340b57cec5SDimitry Andric // Verify that this really looks like plain ASCII text by checking a
2350b57cec5SDimitry Andric // 'reasonable' number of characters (up to profile magic size).
2360b57cec5SDimitry Andric size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
2370b57cec5SDimitry Andric StringRef buffer = Buffer.getBufferStart();
2380b57cec5SDimitry Andric return count == 0 ||
2390b57cec5SDimitry Andric std::all_of(buffer.begin(), buffer.begin() + count,
2405ffd83dbSDimitry Andric [](char c) { return isPrint(c) || isSpace(c); });
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric // Read the profile variant flag from the header: ":FE" means this is a FE
2440b57cec5SDimitry Andric // generated profile. ":IR" means this is an IR level profile. Other strings
2450b57cec5SDimitry Andric // with a leading ':' will be reported an error format.
readHeader()2460b57cec5SDimitry Andric Error TextInstrProfReader::readHeader() {
2470b57cec5SDimitry Andric Symtab.reset(new InstrProfSymtab());
248e8d8bef9SDimitry Andric
249c9157d92SDimitry Andric while (Line->starts_with(":")) {
250e8d8bef9SDimitry Andric StringRef Str = Line->substr(1);
251fe6060f1SDimitry Andric if (Str.equals_insensitive("ir"))
25281ad6265SDimitry Andric ProfileKind |= InstrProfKind::IRInstrumentation;
253fe6060f1SDimitry Andric else if (Str.equals_insensitive("fe"))
25481ad6265SDimitry Andric ProfileKind |= InstrProfKind::FrontendInstrumentation;
255fe6060f1SDimitry Andric else if (Str.equals_insensitive("csir")) {
25681ad6265SDimitry Andric ProfileKind |= InstrProfKind::IRInstrumentation;
25781ad6265SDimitry Andric ProfileKind |= InstrProfKind::ContextSensitive;
258fe6060f1SDimitry Andric } else if (Str.equals_insensitive("entry_first"))
25981ad6265SDimitry Andric ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
260fe6060f1SDimitry Andric else if (Str.equals_insensitive("not_entry_first"))
26181ad6265SDimitry Andric ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
262c9157d92SDimitry Andric else if (Str.equals_insensitive("single_byte_coverage"))
263c9157d92SDimitry Andric ProfileKind |= InstrProfKind::SingleByteCoverage;
264fe013be4SDimitry Andric else if (Str.equals_insensitive("temporal_prof_traces")) {
265fe013be4SDimitry Andric ProfileKind |= InstrProfKind::TemporalProfile;
266fe013be4SDimitry Andric if (auto Err = readTemporalProfTraceData())
267fe013be4SDimitry Andric return error(std::move(Err));
268fe013be4SDimitry Andric } else
2690b57cec5SDimitry Andric return error(instrprof_error::bad_header);
2700b57cec5SDimitry Andric ++Line;
271e8d8bef9SDimitry Andric }
2720b57cec5SDimitry Andric return success();
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric
275fe013be4SDimitry Andric /// Temporal profile trace data is stored in the header immediately after
276fe013be4SDimitry Andric /// ":temporal_prof_traces". The first integer is the number of traces, the
277fe013be4SDimitry Andric /// second integer is the stream size, then the following lines are the actual
278fe013be4SDimitry Andric /// traces which consist of a weight and a comma separated list of function
279fe013be4SDimitry Andric /// names.
readTemporalProfTraceData()280fe013be4SDimitry Andric Error TextInstrProfReader::readTemporalProfTraceData() {
281fe013be4SDimitry Andric if ((++Line).is_at_end())
282fe013be4SDimitry Andric return error(instrprof_error::eof);
283fe013be4SDimitry Andric
284fe013be4SDimitry Andric uint32_t NumTraces;
285fe013be4SDimitry Andric if (Line->getAsInteger(0, NumTraces))
286fe013be4SDimitry Andric return error(instrprof_error::malformed);
287fe013be4SDimitry Andric
288fe013be4SDimitry Andric if ((++Line).is_at_end())
289fe013be4SDimitry Andric return error(instrprof_error::eof);
290fe013be4SDimitry Andric
291fe013be4SDimitry Andric if (Line->getAsInteger(0, TemporalProfTraceStreamSize))
292fe013be4SDimitry Andric return error(instrprof_error::malformed);
293fe013be4SDimitry Andric
294fe013be4SDimitry Andric for (uint32_t i = 0; i < NumTraces; i++) {
295fe013be4SDimitry Andric if ((++Line).is_at_end())
296fe013be4SDimitry Andric return error(instrprof_error::eof);
297fe013be4SDimitry Andric
298fe013be4SDimitry Andric TemporalProfTraceTy Trace;
299fe013be4SDimitry Andric if (Line->getAsInteger(0, Trace.Weight))
300fe013be4SDimitry Andric return error(instrprof_error::malformed);
301fe013be4SDimitry Andric
302fe013be4SDimitry Andric if ((++Line).is_at_end())
303fe013be4SDimitry Andric return error(instrprof_error::eof);
304fe013be4SDimitry Andric
305fe013be4SDimitry Andric SmallVector<StringRef> FuncNames;
306fe013be4SDimitry Andric Line->split(FuncNames, ",", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
307fe013be4SDimitry Andric for (auto &FuncName : FuncNames)
308fe013be4SDimitry Andric Trace.FunctionNameRefs.push_back(
309fe013be4SDimitry Andric IndexedInstrProf::ComputeHash(FuncName.trim()));
310fe013be4SDimitry Andric TemporalProfTraces.push_back(std::move(Trace));
311fe013be4SDimitry Andric }
312fe013be4SDimitry Andric return success();
313fe013be4SDimitry Andric }
314fe013be4SDimitry Andric
3150b57cec5SDimitry Andric Error
readValueProfileData(InstrProfRecord & Record)3160b57cec5SDimitry Andric TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
3170b57cec5SDimitry Andric
3180b57cec5SDimitry Andric #define CHECK_LINE_END(Line) \
3190b57cec5SDimitry Andric if (Line.is_at_end()) \
3200b57cec5SDimitry Andric return error(instrprof_error::truncated);
3210b57cec5SDimitry Andric #define READ_NUM(Str, Dst) \
3220b57cec5SDimitry Andric if ((Str).getAsInteger(10, (Dst))) \
3230b57cec5SDimitry Andric return error(instrprof_error::malformed);
3240b57cec5SDimitry Andric #define VP_READ_ADVANCE(Val) \
3250b57cec5SDimitry Andric CHECK_LINE_END(Line); \
3260b57cec5SDimitry Andric uint32_t Val; \
3270b57cec5SDimitry Andric READ_NUM((*Line), (Val)); \
3280b57cec5SDimitry Andric Line++;
3290b57cec5SDimitry Andric
3300b57cec5SDimitry Andric if (Line.is_at_end())
3310b57cec5SDimitry Andric return success();
3320b57cec5SDimitry Andric
3330b57cec5SDimitry Andric uint32_t NumValueKinds;
3340b57cec5SDimitry Andric if (Line->getAsInteger(10, NumValueKinds)) {
3350b57cec5SDimitry Andric // No value profile data
3360b57cec5SDimitry Andric return success();
3370b57cec5SDimitry Andric }
3380b57cec5SDimitry Andric if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
339349cc55cSDimitry Andric return error(instrprof_error::malformed,
340349cc55cSDimitry Andric "number of value kinds is invalid");
3410b57cec5SDimitry Andric Line++;
3420b57cec5SDimitry Andric
3430b57cec5SDimitry Andric for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
3440b57cec5SDimitry Andric VP_READ_ADVANCE(ValueKind);
3450b57cec5SDimitry Andric if (ValueKind > IPVK_Last)
346349cc55cSDimitry Andric return error(instrprof_error::malformed, "value kind is invalid");
347349cc55cSDimitry Andric ;
3480b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueSites);
3490b57cec5SDimitry Andric if (!NumValueSites)
3500b57cec5SDimitry Andric continue;
3510b57cec5SDimitry Andric
3520b57cec5SDimitry Andric Record.reserveSites(VK, NumValueSites);
3530b57cec5SDimitry Andric for (uint32_t S = 0; S < NumValueSites; S++) {
3540b57cec5SDimitry Andric VP_READ_ADVANCE(NumValueData);
3550b57cec5SDimitry Andric
3560b57cec5SDimitry Andric std::vector<InstrProfValueData> CurrentValues;
3570b57cec5SDimitry Andric for (uint32_t V = 0; V < NumValueData; V++) {
3580b57cec5SDimitry Andric CHECK_LINE_END(Line);
3590b57cec5SDimitry Andric std::pair<StringRef, StringRef> VD = Line->rsplit(':');
3600b57cec5SDimitry Andric uint64_t TakenCount, Value;
3610b57cec5SDimitry Andric if (ValueKind == IPVK_IndirectCallTarget) {
3620b57cec5SDimitry Andric if (InstrProfSymtab::isExternalSymbol(VD.first)) {
3630b57cec5SDimitry Andric Value = 0;
3640b57cec5SDimitry Andric } else {
3650b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(VD.first))
3660b57cec5SDimitry Andric return E;
3670b57cec5SDimitry Andric Value = IndexedInstrProf::ComputeHash(VD.first);
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric } else {
3700b57cec5SDimitry Andric READ_NUM(VD.first, Value);
3710b57cec5SDimitry Andric }
3720b57cec5SDimitry Andric READ_NUM(VD.second, TakenCount);
3730b57cec5SDimitry Andric CurrentValues.push_back({Value, TakenCount});
3740b57cec5SDimitry Andric Line++;
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData,
3770b57cec5SDimitry Andric nullptr);
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric return success();
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric #undef CHECK_LINE_END
3830b57cec5SDimitry Andric #undef READ_NUM
3840b57cec5SDimitry Andric #undef VP_READ_ADVANCE
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric
readNextRecord(NamedInstrProfRecord & Record)3870b57cec5SDimitry Andric Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
3880b57cec5SDimitry Andric // Skip empty lines and comments.
389c9157d92SDimitry Andric while (!Line.is_at_end() && (Line->empty() || Line->starts_with("#")))
3900b57cec5SDimitry Andric ++Line;
3910b57cec5SDimitry Andric // If we hit EOF while looking for a name, we're done.
3920b57cec5SDimitry Andric if (Line.is_at_end()) {
3930b57cec5SDimitry Andric return error(instrprof_error::eof);
3940b57cec5SDimitry Andric }
3950b57cec5SDimitry Andric
3960b57cec5SDimitry Andric // Read the function name.
3970b57cec5SDimitry Andric Record.Name = *Line++;
3980b57cec5SDimitry Andric if (Error E = Symtab->addFuncName(Record.Name))
3990b57cec5SDimitry Andric return error(std::move(E));
4000b57cec5SDimitry Andric
4010b57cec5SDimitry Andric // Read the function hash.
4020b57cec5SDimitry Andric if (Line.is_at_end())
4030b57cec5SDimitry Andric return error(instrprof_error::truncated);
4040b57cec5SDimitry Andric if ((Line++)->getAsInteger(0, Record.Hash))
405349cc55cSDimitry Andric return error(instrprof_error::malformed,
406349cc55cSDimitry Andric "function hash is not a valid integer");
4070b57cec5SDimitry Andric
4080b57cec5SDimitry Andric // Read the number of counters.
4090b57cec5SDimitry Andric uint64_t NumCounters;
4100b57cec5SDimitry Andric if (Line.is_at_end())
4110b57cec5SDimitry Andric return error(instrprof_error::truncated);
4120b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, NumCounters))
413349cc55cSDimitry Andric return error(instrprof_error::malformed,
414349cc55cSDimitry Andric "number of counters is not a valid integer");
4150b57cec5SDimitry Andric if (NumCounters == 0)
416349cc55cSDimitry Andric return error(instrprof_error::malformed, "number of counters is zero");
4170b57cec5SDimitry Andric
4180b57cec5SDimitry Andric // Read each counter and fill our internal storage with the values.
4190b57cec5SDimitry Andric Record.Clear();
4200b57cec5SDimitry Andric Record.Counts.reserve(NumCounters);
4210b57cec5SDimitry Andric for (uint64_t I = 0; I < NumCounters; ++I) {
4220b57cec5SDimitry Andric if (Line.is_at_end())
4230b57cec5SDimitry Andric return error(instrprof_error::truncated);
4240b57cec5SDimitry Andric uint64_t Count;
4250b57cec5SDimitry Andric if ((Line++)->getAsInteger(10, Count))
426349cc55cSDimitry Andric return error(instrprof_error::malformed, "count is invalid");
4270b57cec5SDimitry Andric Record.Counts.push_back(Count);
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric
430c9157d92SDimitry Andric // Bitmap byte information is indicated with special character.
431c9157d92SDimitry Andric if (Line->starts_with("$")) {
432c9157d92SDimitry Andric Record.BitmapBytes.clear();
433c9157d92SDimitry Andric // Read the number of bitmap bytes.
434c9157d92SDimitry Andric uint64_t NumBitmapBytes;
435c9157d92SDimitry Andric if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes))
436c9157d92SDimitry Andric return error(instrprof_error::malformed,
437c9157d92SDimitry Andric "number of bitmap bytes is not a valid integer");
438c9157d92SDimitry Andric if (NumBitmapBytes != 0) {
439c9157d92SDimitry Andric // Read each bitmap and fill our internal storage with the values.
440c9157d92SDimitry Andric Record.BitmapBytes.reserve(NumBitmapBytes);
441c9157d92SDimitry Andric for (uint8_t I = 0; I < NumBitmapBytes; ++I) {
442c9157d92SDimitry Andric if (Line.is_at_end())
443c9157d92SDimitry Andric return error(instrprof_error::truncated);
444c9157d92SDimitry Andric uint8_t BitmapByte;
445c9157d92SDimitry Andric if ((Line++)->getAsInteger(0, BitmapByte))
446c9157d92SDimitry Andric return error(instrprof_error::malformed,
447c9157d92SDimitry Andric "bitmap byte is not a valid integer");
448c9157d92SDimitry Andric Record.BitmapBytes.push_back(BitmapByte);
449c9157d92SDimitry Andric }
450c9157d92SDimitry Andric }
451c9157d92SDimitry Andric }
452c9157d92SDimitry Andric
4530b57cec5SDimitry Andric // Check if value profile data exists and read it if so.
4540b57cec5SDimitry Andric if (Error E = readValueProfileData(Record))
4550b57cec5SDimitry Andric return error(std::move(E));
4560b57cec5SDimitry Andric
4570b57cec5SDimitry Andric return success();
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric template <class IntPtrT>
getProfileKind() const4611fd87a68SDimitry Andric InstrProfKind RawInstrProfReader<IntPtrT>::getProfileKind() const {
4621fd87a68SDimitry Andric return getProfileKindFromVersion(Version);
4631fd87a68SDimitry Andric }
4641fd87a68SDimitry Andric
4651fd87a68SDimitry Andric template <class IntPtrT>
466fe013be4SDimitry Andric SmallVector<TemporalProfTraceTy> &
getTemporalProfTraces(std::optional<uint64_t> Weight)467fe013be4SDimitry Andric RawInstrProfReader<IntPtrT>::getTemporalProfTraces(
468fe013be4SDimitry Andric std::optional<uint64_t> Weight) {
469fe013be4SDimitry Andric if (TemporalProfTimestamps.empty()) {
470fe013be4SDimitry Andric assert(TemporalProfTraces.empty());
471fe013be4SDimitry Andric return TemporalProfTraces;
472fe013be4SDimitry Andric }
473fe013be4SDimitry Andric // Sort functions by their timestamps to build the trace.
474fe013be4SDimitry Andric std::sort(TemporalProfTimestamps.begin(), TemporalProfTimestamps.end());
475fe013be4SDimitry Andric TemporalProfTraceTy Trace;
476fe013be4SDimitry Andric if (Weight)
477fe013be4SDimitry Andric Trace.Weight = *Weight;
478fe013be4SDimitry Andric for (auto &[TimestampValue, NameRef] : TemporalProfTimestamps)
479fe013be4SDimitry Andric Trace.FunctionNameRefs.push_back(NameRef);
480fe013be4SDimitry Andric TemporalProfTraces = {std::move(Trace)};
481fe013be4SDimitry Andric return TemporalProfTraces;
482fe013be4SDimitry Andric }
483fe013be4SDimitry Andric
484fe013be4SDimitry Andric template <class IntPtrT>
hasFormat(const MemoryBuffer & DataBuffer)4850b57cec5SDimitry Andric bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
4860b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < sizeof(uint64_t))
4870b57cec5SDimitry Andric return false;
4880b57cec5SDimitry Andric uint64_t Magic =
4890b57cec5SDimitry Andric *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
4900b57cec5SDimitry Andric return RawInstrProf::getMagic<IntPtrT>() == Magic ||
491c9157d92SDimitry Andric llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic;
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric
4940b57cec5SDimitry Andric template <class IntPtrT>
readHeader()4950b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader() {
4960b57cec5SDimitry Andric if (!hasFormat(*DataBuffer))
4970b57cec5SDimitry Andric return error(instrprof_error::bad_magic);
4980b57cec5SDimitry Andric if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
4990b57cec5SDimitry Andric return error(instrprof_error::bad_header);
5000b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
5010b57cec5SDimitry Andric DataBuffer->getBufferStart());
5020b57cec5SDimitry Andric ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
5030b57cec5SDimitry Andric return readHeader(*Header);
5040b57cec5SDimitry Andric }
5050b57cec5SDimitry Andric
5060b57cec5SDimitry Andric template <class IntPtrT>
readNextHeader(const char * CurrentPos)5070b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
5080b57cec5SDimitry Andric const char *End = DataBuffer->getBufferEnd();
5090b57cec5SDimitry Andric // Skip zero padding between profiles.
5100b57cec5SDimitry Andric while (CurrentPos != End && *CurrentPos == 0)
5110b57cec5SDimitry Andric ++CurrentPos;
5120b57cec5SDimitry Andric // If there's nothing left, we're done.
5130b57cec5SDimitry Andric if (CurrentPos == End)
5140b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof);
5150b57cec5SDimitry Andric // If there isn't enough space for another header, this is probably just
5160b57cec5SDimitry Andric // garbage at the end of the file.
5170b57cec5SDimitry Andric if (CurrentPos + sizeof(RawInstrProf::Header) > End)
518349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed,
519349cc55cSDimitry Andric "not enough space for another header");
5200b57cec5SDimitry Andric // The writer ensures each profile is padded to start at an aligned address.
5210b57cec5SDimitry Andric if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
522349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed,
523349cc55cSDimitry Andric "insufficient padding");
5240b57cec5SDimitry Andric // The magic should have the same byte order as in the previous header.
5250b57cec5SDimitry Andric uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
5260b57cec5SDimitry Andric if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
5270b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic);
5280b57cec5SDimitry Andric
5290b57cec5SDimitry Andric // There's another profile to read, so we need to process the header.
5300b57cec5SDimitry Andric auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
5310b57cec5SDimitry Andric return readHeader(*Header);
5320b57cec5SDimitry Andric }
5330b57cec5SDimitry Andric
5340b57cec5SDimitry Andric template <class IntPtrT>
createSymtab(InstrProfSymtab & Symtab)5350b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
5360eae32dcSDimitry Andric if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart)))
5370b57cec5SDimitry Andric return error(std::move(E));
5380b57cec5SDimitry Andric for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
5390b57cec5SDimitry Andric const IntPtrT FPtr = swap(I->FunctionPointer);
5400b57cec5SDimitry Andric if (!FPtr)
5410b57cec5SDimitry Andric continue;
542*de8261c4SDimitry Andric Symtab.mapAddress(FPtr, swap(I->NameRef));
5430b57cec5SDimitry Andric }
5440b57cec5SDimitry Andric return success();
5450b57cec5SDimitry Andric }
5460b57cec5SDimitry Andric
5470b57cec5SDimitry Andric template <class IntPtrT>
readHeader(const RawInstrProf::Header & Header)5480b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader(
5490b57cec5SDimitry Andric const RawInstrProf::Header &Header) {
5500b57cec5SDimitry Andric Version = swap(Header.Version);
5510b57cec5SDimitry Andric if (GET_VERSION(Version) != RawInstrProf::Version)
552fe013be4SDimitry Andric return error(instrprof_error::raw_profile_version_mismatch,
553fe013be4SDimitry Andric ("Profile uses raw profile format version = " +
554fe013be4SDimitry Andric Twine(GET_VERSION(Version)) +
555fe013be4SDimitry Andric "; expected version = " + Twine(RawInstrProf::Version) +
556fe013be4SDimitry Andric "\nPLEASE update this tool to version in the raw profile, or "
557fe013be4SDimitry Andric "regenerate raw profile with expected version.")
558fe013be4SDimitry Andric .str());
5590b57cec5SDimitry Andric
560c9157d92SDimitry Andric uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
561c9157d92SDimitry Andric // Binary id start just after the header if exists.
562c9157d92SDimitry Andric const uint8_t *BinaryIdStart =
563c9157d92SDimitry Andric reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
564c9157d92SDimitry Andric const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
565c9157d92SDimitry Andric const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
566c9157d92SDimitry Andric if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
567349cc55cSDimitry Andric return error(instrprof_error::bad_header);
568c9157d92SDimitry Andric if (BinaryIdSize != 0) {
569c9157d92SDimitry Andric if (Error Err =
570c9157d92SDimitry Andric readBinaryIdsInternal(*DataBuffer, BinaryIdSize, BinaryIdStart,
571c9157d92SDimitry Andric BinaryIds, getDataEndianness()))
572c9157d92SDimitry Andric return Err;
573c9157d92SDimitry Andric }
574349cc55cSDimitry Andric
5750b57cec5SDimitry Andric CountersDelta = swap(Header.CountersDelta);
576c9157d92SDimitry Andric BitmapDelta = swap(Header.BitmapDelta);
5770b57cec5SDimitry Andric NamesDelta = swap(Header.NamesDelta);
578c9157d92SDimitry Andric auto NumData = swap(Header.NumData);
579480093f4SDimitry Andric auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
580c9157d92SDimitry Andric auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize();
581480093f4SDimitry Andric auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
582c9157d92SDimitry Andric auto NumBitmapBytes = swap(Header.NumBitmapBytes);
583c9157d92SDimitry Andric auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes);
5840eae32dcSDimitry Andric auto NamesSize = swap(Header.NamesSize);
5850b57cec5SDimitry Andric ValueKindLast = swap(Header.ValueKindLast);
5860b57cec5SDimitry Andric
58704eeddc0SDimitry Andric auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
5880b57cec5SDimitry Andric auto PaddingSize = getNumPaddingBytes(NamesSize);
5890b57cec5SDimitry Andric
590fe6060f1SDimitry Andric // Profile data starts after profile header and binary ids if exist.
591c9157d92SDimitry Andric ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdSize;
59204eeddc0SDimitry Andric ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
593c9157d92SDimitry Andric ptrdiff_t BitmapOffset =
59404eeddc0SDimitry Andric CountersOffset + CountersSize + PaddingBytesAfterCounters;
595c9157d92SDimitry Andric ptrdiff_t NamesOffset =
596c9157d92SDimitry Andric BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes;
5970b57cec5SDimitry Andric ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
5980b57cec5SDimitry Andric
5990b57cec5SDimitry Andric auto *Start = reinterpret_cast<const char *>(&Header);
6000b57cec5SDimitry Andric if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
6010b57cec5SDimitry Andric return error(instrprof_error::bad_header);
6020b57cec5SDimitry Andric
6030eae32dcSDimitry Andric if (Correlator) {
6040eae32dcSDimitry Andric // These sizes in the raw file are zero because we constructed them in the
6050eae32dcSDimitry Andric // Correlator.
606c9157d92SDimitry Andric if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 &&
607c9157d92SDimitry Andric NamesDelta == 0))
608c9157d92SDimitry Andric return error(instrprof_error::unexpected_correlation_info);
6090eae32dcSDimitry Andric Data = Correlator->getDataPointer();
6100eae32dcSDimitry Andric DataEnd = Data + Correlator->getDataSize();
61104eeddc0SDimitry Andric NamesStart = Correlator->getNamesPointer();
61204eeddc0SDimitry Andric NamesEnd = NamesStart + Correlator->getNamesSize();
6130eae32dcSDimitry Andric } else {
6140b57cec5SDimitry Andric Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
6150b57cec5SDimitry Andric Start + DataOffset);
61604eeddc0SDimitry Andric DataEnd = Data + NumData;
6170eae32dcSDimitry Andric NamesStart = Start + NamesOffset;
6180eae32dcSDimitry Andric NamesEnd = NamesStart + NamesSize;
6190eae32dcSDimitry Andric }
620fe6060f1SDimitry Andric
62104eeddc0SDimitry Andric CountersStart = Start + CountersOffset;
62204eeddc0SDimitry Andric CountersEnd = CountersStart + CountersSize;
623c9157d92SDimitry Andric BitmapStart = Start + BitmapOffset;
624c9157d92SDimitry Andric BitmapEnd = BitmapStart + NumBitmapBytes;
6250b57cec5SDimitry Andric ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
6260b57cec5SDimitry Andric
6278bcb0991SDimitry Andric std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
62881ad6265SDimitry Andric if (Error E = createSymtab(*NewSymtab))
6290b57cec5SDimitry Andric return E;
6300b57cec5SDimitry Andric
6310b57cec5SDimitry Andric Symtab = std::move(NewSymtab);
6320b57cec5SDimitry Andric return success();
6330b57cec5SDimitry Andric }
6340b57cec5SDimitry Andric
6350b57cec5SDimitry Andric template <class IntPtrT>
readName(NamedInstrProfRecord & Record)6360b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
6370b57cec5SDimitry Andric Record.Name = getName(Data->NameRef);
6380b57cec5SDimitry Andric return success();
6390b57cec5SDimitry Andric }
6400b57cec5SDimitry Andric
6410b57cec5SDimitry Andric template <class IntPtrT>
readFuncHash(NamedInstrProfRecord & Record)6420b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
6430b57cec5SDimitry Andric Record.Hash = swap(Data->FuncHash);
6440b57cec5SDimitry Andric return success();
6450b57cec5SDimitry Andric }
6460b57cec5SDimitry Andric
6470b57cec5SDimitry Andric template <class IntPtrT>
readRawCounts(InstrProfRecord & Record)6480b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawCounts(
6490b57cec5SDimitry Andric InstrProfRecord &Record) {
6500b57cec5SDimitry Andric uint32_t NumCounters = swap(Data->NumCounters);
6510b57cec5SDimitry Andric if (NumCounters == 0)
652349cc55cSDimitry Andric return error(instrprof_error::malformed, "number of counters is zero");
6530b57cec5SDimitry Andric
65404eeddc0SDimitry Andric ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
65504eeddc0SDimitry Andric if (CounterBaseOffset < 0)
656349cc55cSDimitry Andric return error(
657349cc55cSDimitry Andric instrprof_error::malformed,
65804eeddc0SDimitry Andric ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
659349cc55cSDimitry Andric
66004eeddc0SDimitry Andric if (CounterBaseOffset >= CountersEnd - CountersStart)
6610eae32dcSDimitry Andric return error(instrprof_error::malformed,
66204eeddc0SDimitry Andric ("counter offset " + Twine(CounterBaseOffset) +
66304eeddc0SDimitry Andric " is greater than the maximum counter offset " +
66404eeddc0SDimitry Andric Twine(CountersEnd - CountersStart - 1))
665349cc55cSDimitry Andric .str());
666349cc55cSDimitry Andric
66704eeddc0SDimitry Andric uint64_t MaxNumCounters =
66804eeddc0SDimitry Andric (CountersEnd - (CountersStart + CounterBaseOffset)) /
66904eeddc0SDimitry Andric getCounterTypeSize();
67004eeddc0SDimitry Andric if (NumCounters > MaxNumCounters)
671349cc55cSDimitry Andric return error(instrprof_error::malformed,
67204eeddc0SDimitry Andric ("number of counters " + Twine(NumCounters) +
673349cc55cSDimitry Andric " is greater than the maximum number of counters " +
67404eeddc0SDimitry Andric Twine(MaxNumCounters))
675349cc55cSDimitry Andric .str());
6768bcb0991SDimitry Andric
6770b57cec5SDimitry Andric Record.Counts.clear();
67804eeddc0SDimitry Andric Record.Counts.reserve(NumCounters);
67904eeddc0SDimitry Andric for (uint32_t I = 0; I < NumCounters; I++) {
6801fd87a68SDimitry Andric const char *Ptr =
6811fd87a68SDimitry Andric CountersStart + CounterBaseOffset + I * getCounterTypeSize();
682fe013be4SDimitry Andric if (I == 0 && hasTemporalProfile()) {
683fe013be4SDimitry Andric uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
684fe013be4SDimitry Andric if (TimestampValue != 0 &&
685fe013be4SDimitry Andric TimestampValue != std::numeric_limits<uint64_t>::max()) {
686fe013be4SDimitry Andric TemporalProfTimestamps.emplace_back(TimestampValue,
687fe013be4SDimitry Andric swap(Data->NameRef));
688fe013be4SDimitry Andric TemporalProfTraceStreamSize = 1;
689fe013be4SDimitry Andric }
690fe013be4SDimitry Andric if (hasSingleByteCoverage()) {
691fe013be4SDimitry Andric // In coverage mode, getCounterTypeSize() returns 1 byte but our
692fe013be4SDimitry Andric // timestamp field has size uint64_t. Increment I so that the next
693fe013be4SDimitry Andric // iteration of this for loop points to the byte after the timestamp
694fe013be4SDimitry Andric // field, i.e., I += 8.
695fe013be4SDimitry Andric I += 7;
696fe013be4SDimitry Andric }
697fe013be4SDimitry Andric continue;
698fe013be4SDimitry Andric }
6991fd87a68SDimitry Andric if (hasSingleByteCoverage()) {
7001fd87a68SDimitry Andric // A value of zero signifies the block is covered.
7011fd87a68SDimitry Andric Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
7021fd87a68SDimitry Andric } else {
703c9157d92SDimitry Andric uint64_t CounterValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
704c9157d92SDimitry Andric if (CounterValue > MaxCounterValue && Warn)
705c9157d92SDimitry Andric Warn(make_error<InstrProfError>(
706c9157d92SDimitry Andric instrprof_error::counter_value_too_large, Twine(CounterValue)));
707c9157d92SDimitry Andric
708c9157d92SDimitry Andric Record.Counts.push_back(CounterValue);
70904eeddc0SDimitry Andric }
7101fd87a68SDimitry Andric }
7110b57cec5SDimitry Andric
7120b57cec5SDimitry Andric return success();
7130b57cec5SDimitry Andric }
7140b57cec5SDimitry Andric
7150b57cec5SDimitry Andric template <class IntPtrT>
readRawBitmapBytes(InstrProfRecord & Record)716c9157d92SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) {
717c9157d92SDimitry Andric uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
718c9157d92SDimitry Andric
719c9157d92SDimitry Andric Record.BitmapBytes.clear();
720c9157d92SDimitry Andric Record.BitmapBytes.reserve(NumBitmapBytes);
721c9157d92SDimitry Andric
722c9157d92SDimitry Andric // It's possible MCDC is either not enabled or only used for some functions
723c9157d92SDimitry Andric // and not others. So if we record 0 bytes, just move on.
724c9157d92SDimitry Andric if (NumBitmapBytes == 0)
725c9157d92SDimitry Andric return success();
726c9157d92SDimitry Andric
727c9157d92SDimitry Andric // BitmapDelta decreases as we advance to the next data record.
728c9157d92SDimitry Andric ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
729c9157d92SDimitry Andric if (BitmapOffset < 0)
730c9157d92SDimitry Andric return error(
731c9157d92SDimitry Andric instrprof_error::malformed,
732c9157d92SDimitry Andric ("bitmap offset " + Twine(BitmapOffset) + " is negative").str());
733c9157d92SDimitry Andric
734c9157d92SDimitry Andric if (BitmapOffset >= BitmapEnd - BitmapStart)
735c9157d92SDimitry Andric return error(instrprof_error::malformed,
736c9157d92SDimitry Andric ("bitmap offset " + Twine(BitmapOffset) +
737c9157d92SDimitry Andric " is greater than the maximum bitmap offset " +
738c9157d92SDimitry Andric Twine(BitmapEnd - BitmapStart - 1))
739c9157d92SDimitry Andric .str());
740c9157d92SDimitry Andric
741c9157d92SDimitry Andric uint64_t MaxNumBitmapBytes =
742c9157d92SDimitry Andric (BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t);
743c9157d92SDimitry Andric if (NumBitmapBytes > MaxNumBitmapBytes)
744c9157d92SDimitry Andric return error(instrprof_error::malformed,
745c9157d92SDimitry Andric ("number of bitmap bytes " + Twine(NumBitmapBytes) +
746c9157d92SDimitry Andric " is greater than the maximum number of bitmap bytes " +
747c9157d92SDimitry Andric Twine(MaxNumBitmapBytes))
748c9157d92SDimitry Andric .str());
749c9157d92SDimitry Andric
750c9157d92SDimitry Andric for (uint32_t I = 0; I < NumBitmapBytes; I++) {
751c9157d92SDimitry Andric const char *Ptr = BitmapStart + BitmapOffset + I;
752c9157d92SDimitry Andric Record.BitmapBytes.push_back(swap(*Ptr));
753c9157d92SDimitry Andric }
754c9157d92SDimitry Andric
755c9157d92SDimitry Andric return success();
756c9157d92SDimitry Andric }
757c9157d92SDimitry Andric
758c9157d92SDimitry Andric template <class IntPtrT>
readValueProfilingData(InstrProfRecord & Record)7590b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
7600b57cec5SDimitry Andric InstrProfRecord &Record) {
7610b57cec5SDimitry Andric Record.clearValueData();
7620b57cec5SDimitry Andric CurValueDataSize = 0;
7630b57cec5SDimitry Andric // Need to match the logic in value profile dumper code in compiler-rt:
7640b57cec5SDimitry Andric uint32_t NumValueKinds = 0;
7650b57cec5SDimitry Andric for (uint32_t I = 0; I < IPVK_Last + 1; I++)
7660b57cec5SDimitry Andric NumValueKinds += (Data->NumValueSites[I] != 0);
7670b57cec5SDimitry Andric
7680b57cec5SDimitry Andric if (!NumValueKinds)
7690b57cec5SDimitry Andric return success();
7700b57cec5SDimitry Andric
7710b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
7720b57cec5SDimitry Andric ValueProfData::getValueProfData(
7730b57cec5SDimitry Andric ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
7740b57cec5SDimitry Andric getDataEndianness());
7750b57cec5SDimitry Andric
7760b57cec5SDimitry Andric if (Error E = VDataPtrOrErr.takeError())
7770b57cec5SDimitry Andric return E;
7780b57cec5SDimitry Andric
7790b57cec5SDimitry Andric // Note that besides deserialization, this also performs the conversion for
7800b57cec5SDimitry Andric // indirect call targets. The function pointers from the raw profile are
7810b57cec5SDimitry Andric // remapped into function name hashes.
7820b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
7830b57cec5SDimitry Andric CurValueDataSize = VDataPtrOrErr.get()->getSize();
7840b57cec5SDimitry Andric return success();
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric
7870b57cec5SDimitry Andric template <class IntPtrT>
readNextRecord(NamedInstrProfRecord & Record)7880b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
789bdd1243dSDimitry Andric // Keep reading profiles that consist of only headers and no profile data and
790bdd1243dSDimitry Andric // counters.
791bdd1243dSDimitry Andric while (atEnd())
7920b57cec5SDimitry Andric // At this point, ValueDataStart field points to the next header.
7930b57cec5SDimitry Andric if (Error E = readNextHeader(getNextHeaderPos()))
7940b57cec5SDimitry Andric return error(std::move(E));
7950b57cec5SDimitry Andric
796fe013be4SDimitry Andric // Read name and set it in Record.
7970b57cec5SDimitry Andric if (Error E = readName(Record))
7980b57cec5SDimitry Andric return error(std::move(E));
7990b57cec5SDimitry Andric
8000b57cec5SDimitry Andric // Read FuncHash and set it in Record.
8010b57cec5SDimitry Andric if (Error E = readFuncHash(Record))
8020b57cec5SDimitry Andric return error(std::move(E));
8030b57cec5SDimitry Andric
8040b57cec5SDimitry Andric // Read raw counts and set Record.
8050b57cec5SDimitry Andric if (Error E = readRawCounts(Record))
8060b57cec5SDimitry Andric return error(std::move(E));
8070b57cec5SDimitry Andric
808c9157d92SDimitry Andric // Read raw bitmap bytes and set Record.
809c9157d92SDimitry Andric if (Error E = readRawBitmapBytes(Record))
810c9157d92SDimitry Andric return error(std::move(E));
811c9157d92SDimitry Andric
8120b57cec5SDimitry Andric // Read value data and set Record.
8130b57cec5SDimitry Andric if (Error E = readValueProfilingData(Record))
8140b57cec5SDimitry Andric return error(std::move(E));
8150b57cec5SDimitry Andric
8160b57cec5SDimitry Andric // Iterate.
8170b57cec5SDimitry Andric advanceData();
8180b57cec5SDimitry Andric return success();
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric
821bdd1243dSDimitry Andric template <class IntPtrT>
readBinaryIds(std::vector<llvm::object::BuildID> & BinaryIds)822bdd1243dSDimitry Andric Error RawInstrProfReader<IntPtrT>::readBinaryIds(
823bdd1243dSDimitry Andric std::vector<llvm::object::BuildID> &BinaryIds) {
824c9157d92SDimitry Andric BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(),
825c9157d92SDimitry Andric this->BinaryIds.end());
826c9157d92SDimitry Andric return Error::success();
827349cc55cSDimitry Andric }
828349cc55cSDimitry Andric
829fe6060f1SDimitry Andric template <class IntPtrT>
printBinaryIds(raw_ostream & OS)830fe6060f1SDimitry Andric Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
831c9157d92SDimitry Andric if (!BinaryIds.empty())
832c9157d92SDimitry Andric printBinaryIdsInternal(OS, BinaryIds);
833c9157d92SDimitry Andric return Error::success();
834fe6060f1SDimitry Andric }
835fe6060f1SDimitry Andric
8360b57cec5SDimitry Andric namespace llvm {
8370b57cec5SDimitry Andric
8380b57cec5SDimitry Andric template class RawInstrProfReader<uint32_t>;
8390b57cec5SDimitry Andric template class RawInstrProfReader<uint64_t>;
8400b57cec5SDimitry Andric
8410b57cec5SDimitry Andric } // end namespace llvm
8420b57cec5SDimitry Andric
8430b57cec5SDimitry Andric InstrProfLookupTrait::hash_value_type
ComputeHash(StringRef K)8440b57cec5SDimitry Andric InstrProfLookupTrait::ComputeHash(StringRef K) {
8450b57cec5SDimitry Andric return IndexedInstrProf::ComputeHash(HashType, K);
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric
8480b57cec5SDimitry Andric using data_type = InstrProfLookupTrait::data_type;
8490b57cec5SDimitry Andric using offset_type = InstrProfLookupTrait::offset_type;
8500b57cec5SDimitry Andric
readValueProfilingData(const unsigned char * & D,const unsigned char * const End)8510b57cec5SDimitry Andric bool InstrProfLookupTrait::readValueProfilingData(
8520b57cec5SDimitry Andric const unsigned char *&D, const unsigned char *const End) {
8530b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
8540b57cec5SDimitry Andric ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
8550b57cec5SDimitry Andric
8560b57cec5SDimitry Andric if (VDataPtrOrErr.takeError())
8570b57cec5SDimitry Andric return false;
8580b57cec5SDimitry Andric
8590b57cec5SDimitry Andric VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
8600b57cec5SDimitry Andric D += VDataPtrOrErr.get()->TotalSize;
8610b57cec5SDimitry Andric
8620b57cec5SDimitry Andric return true;
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric
ReadData(StringRef K,const unsigned char * D,offset_type N)8650b57cec5SDimitry Andric data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
8660b57cec5SDimitry Andric offset_type N) {
8670b57cec5SDimitry Andric using namespace support;
8680b57cec5SDimitry Andric
8690b57cec5SDimitry Andric // Check if the data is corrupt. If so, don't try to read it.
8700b57cec5SDimitry Andric if (N % sizeof(uint64_t))
8710b57cec5SDimitry Andric return data_type();
8720b57cec5SDimitry Andric
8730b57cec5SDimitry Andric DataBuffer.clear();
8740b57cec5SDimitry Andric std::vector<uint64_t> CounterBuffer;
875c9157d92SDimitry Andric std::vector<uint8_t> BitmapByteBuffer;
8760b57cec5SDimitry Andric
8770b57cec5SDimitry Andric const unsigned char *End = D + N;
8780b57cec5SDimitry Andric while (D < End) {
8790b57cec5SDimitry Andric // Read hash.
8800b57cec5SDimitry Andric if (D + sizeof(uint64_t) >= End)
8810b57cec5SDimitry Andric return data_type();
882c9157d92SDimitry Andric uint64_t Hash =
883c9157d92SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
8840b57cec5SDimitry Andric
8850b57cec5SDimitry Andric // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
8860b57cec5SDimitry Andric uint64_t CountsSize = N / sizeof(uint64_t) - 1;
8870b57cec5SDimitry Andric // If format version is different then read the number of counters.
8880b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
8890b57cec5SDimitry Andric if (D + sizeof(uint64_t) > End)
8900b57cec5SDimitry Andric return data_type();
891c9157d92SDimitry Andric CountsSize =
892c9157d92SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
8930b57cec5SDimitry Andric }
8940b57cec5SDimitry Andric // Read counter values.
8950b57cec5SDimitry Andric if (D + CountsSize * sizeof(uint64_t) > End)
8960b57cec5SDimitry Andric return data_type();
8970b57cec5SDimitry Andric
8980b57cec5SDimitry Andric CounterBuffer.clear();
8990b57cec5SDimitry Andric CounterBuffer.reserve(CountsSize);
9000b57cec5SDimitry Andric for (uint64_t J = 0; J < CountsSize; ++J)
901c9157d92SDimitry Andric CounterBuffer.push_back(
902c9157d92SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D));
9030b57cec5SDimitry Andric
904c9157d92SDimitry Andric // Read bitmap bytes for GET_VERSION(FormatVersion) > 10.
905c9157d92SDimitry Andric if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) {
906c9157d92SDimitry Andric uint64_t BitmapBytes = 0;
907c9157d92SDimitry Andric if (D + sizeof(uint64_t) > End)
908c9157d92SDimitry Andric return data_type();
909c9157d92SDimitry Andric BitmapBytes =
910c9157d92SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
911c9157d92SDimitry Andric // Read bitmap byte values.
912c9157d92SDimitry Andric if (D + BitmapBytes * sizeof(uint8_t) > End)
913c9157d92SDimitry Andric return data_type();
914c9157d92SDimitry Andric BitmapByteBuffer.clear();
915c9157d92SDimitry Andric BitmapByteBuffer.reserve(BitmapBytes);
916c9157d92SDimitry Andric for (uint64_t J = 0; J < BitmapBytes; ++J)
917c9157d92SDimitry Andric BitmapByteBuffer.push_back(static_cast<uint8_t>(
918c9157d92SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
919c9157d92SDimitry Andric D)));
920c9157d92SDimitry Andric }
921c9157d92SDimitry Andric
922c9157d92SDimitry Andric DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer),
923c9157d92SDimitry Andric std::move(BitmapByteBuffer));
9240b57cec5SDimitry Andric
9250b57cec5SDimitry Andric // Read value profiling data.
9260b57cec5SDimitry Andric if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
9270b57cec5SDimitry Andric !readValueProfilingData(D, End)) {
9280b57cec5SDimitry Andric DataBuffer.clear();
9290b57cec5SDimitry Andric return data_type();
9300b57cec5SDimitry Andric }
9310b57cec5SDimitry Andric }
9320b57cec5SDimitry Andric return DataBuffer;
9330b57cec5SDimitry Andric }
9340b57cec5SDimitry Andric
9350b57cec5SDimitry Andric template <typename HashTableImpl>
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)9360b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords(
9370b57cec5SDimitry Andric StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) {
9380b57cec5SDimitry Andric auto Iter = HashTable->find(FuncName);
9390b57cec5SDimitry Andric if (Iter == HashTable->end())
9400b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::unknown_function);
9410b57cec5SDimitry Andric
9420b57cec5SDimitry Andric Data = (*Iter);
9430b57cec5SDimitry Andric if (Data.empty())
944349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed,
945349cc55cSDimitry Andric "profile data is empty");
9460b57cec5SDimitry Andric
9470b57cec5SDimitry Andric return Error::success();
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric
9500b57cec5SDimitry Andric template <typename HashTableImpl>
getRecords(ArrayRef<NamedInstrProfRecord> & Data)9510b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords(
9520b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) {
9530b57cec5SDimitry Andric if (atEnd())
9540b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::eof);
9550b57cec5SDimitry Andric
9560b57cec5SDimitry Andric Data = *RecordIterator;
9570b57cec5SDimitry Andric
9580b57cec5SDimitry Andric if (Data.empty())
959349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed,
960349cc55cSDimitry Andric "profile data is empty");
9610b57cec5SDimitry Andric
9620b57cec5SDimitry Andric return Error::success();
9630b57cec5SDimitry Andric }
9640b57cec5SDimitry Andric
9650b57cec5SDimitry Andric template <typename HashTableImpl>
InstrProfReaderIndex(const unsigned char * Buckets,const unsigned char * const Payload,const unsigned char * const Base,IndexedInstrProf::HashT HashType,uint64_t Version)9660b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
9670b57cec5SDimitry Andric const unsigned char *Buckets, const unsigned char *const Payload,
9680b57cec5SDimitry Andric const unsigned char *const Base, IndexedInstrProf::HashT HashType,
9690b57cec5SDimitry Andric uint64_t Version) {
9700b57cec5SDimitry Andric FormatVersion = Version;
9710b57cec5SDimitry Andric HashTable.reset(HashTableImpl::Create(
9720b57cec5SDimitry Andric Buckets, Payload, Base,
9730b57cec5SDimitry Andric typename HashTableImpl::InfoType(HashType, Version)));
9740b57cec5SDimitry Andric RecordIterator = HashTable->data_begin();
9750b57cec5SDimitry Andric }
9760b57cec5SDimitry Andric
9771fd87a68SDimitry Andric template <typename HashTableImpl>
getProfileKind() const9781fd87a68SDimitry Andric InstrProfKind InstrProfReaderIndex<HashTableImpl>::getProfileKind() const {
9791fd87a68SDimitry Andric return getProfileKindFromVersion(FormatVersion);
9801fd87a68SDimitry Andric }
9811fd87a68SDimitry Andric
9820b57cec5SDimitry Andric namespace {
9830b57cec5SDimitry Andric /// A remapper that does not apply any remappings.
9840b57cec5SDimitry Andric class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
9850b57cec5SDimitry Andric InstrProfReaderIndexBase &Underlying;
9860b57cec5SDimitry Andric
9870b57cec5SDimitry Andric public:
InstrProfReaderNullRemapper(InstrProfReaderIndexBase & Underlying)9880b57cec5SDimitry Andric InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
9890b57cec5SDimitry Andric : Underlying(Underlying) {}
9900b57cec5SDimitry Andric
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)9910b57cec5SDimitry Andric Error getRecords(StringRef FuncName,
9920b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override {
9930b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data);
9940b57cec5SDimitry Andric }
9950b57cec5SDimitry Andric };
996349cc55cSDimitry Andric } // namespace
9970b57cec5SDimitry Andric
9980b57cec5SDimitry Andric /// A remapper that applies remappings based on a symbol remapping file.
9990b57cec5SDimitry Andric template <typename HashTableImpl>
10000b57cec5SDimitry Andric class llvm::InstrProfReaderItaniumRemapper
10010b57cec5SDimitry Andric : public InstrProfReaderRemapper {
10020b57cec5SDimitry Andric public:
InstrProfReaderItaniumRemapper(std::unique_ptr<MemoryBuffer> RemapBuffer,InstrProfReaderIndex<HashTableImpl> & Underlying)10030b57cec5SDimitry Andric InstrProfReaderItaniumRemapper(
10040b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer,
10050b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying)
10060b57cec5SDimitry Andric : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
10070b57cec5SDimitry Andric }
10080b57cec5SDimitry Andric
10090b57cec5SDimitry Andric /// Extract the original function name from a PGO function name.
extractName(StringRef Name)10100b57cec5SDimitry Andric static StringRef extractName(StringRef Name) {
1011e710425bSDimitry Andric // We can have multiple pieces separated by kGlobalIdentifierDelimiter (
1012e710425bSDimitry Andric // semicolon now and colon in older profiles); there can be pieces both
1013e710425bSDimitry Andric // before and after the mangled name. Find the first part that starts with
1014e710425bSDimitry Andric // '_Z'; we'll assume that's the mangled name we want.
10150b57cec5SDimitry Andric std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
10160b57cec5SDimitry Andric while (true) {
1017e710425bSDimitry Andric Parts = Parts.second.split(kGlobalIdentifierDelimiter);
1018c9157d92SDimitry Andric if (Parts.first.starts_with("_Z"))
10190b57cec5SDimitry Andric return Parts.first;
10200b57cec5SDimitry Andric if (Parts.second.empty())
10210b57cec5SDimitry Andric return Name;
10220b57cec5SDimitry Andric }
10230b57cec5SDimitry Andric }
10240b57cec5SDimitry Andric
10250b57cec5SDimitry Andric /// Given a mangled name extracted from a PGO function name, and a new
10260b57cec5SDimitry Andric /// form for that mangled name, reconstitute the name.
reconstituteName(StringRef OrigName,StringRef ExtractedName,StringRef Replacement,SmallVectorImpl<char> & Out)10270b57cec5SDimitry Andric static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
10280b57cec5SDimitry Andric StringRef Replacement,
10290b57cec5SDimitry Andric SmallVectorImpl<char> &Out) {
10300b57cec5SDimitry Andric Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
10310b57cec5SDimitry Andric Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
10320b57cec5SDimitry Andric Out.insert(Out.end(), Replacement.begin(), Replacement.end());
10330b57cec5SDimitry Andric Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
10340b57cec5SDimitry Andric }
10350b57cec5SDimitry Andric
populateRemappings()10360b57cec5SDimitry Andric Error populateRemappings() override {
10370b57cec5SDimitry Andric if (Error E = Remappings.read(*RemapBuffer))
10380b57cec5SDimitry Andric return E;
10390b57cec5SDimitry Andric for (StringRef Name : Underlying.HashTable->keys()) {
10400b57cec5SDimitry Andric StringRef RealName = extractName(Name);
10410b57cec5SDimitry Andric if (auto Key = Remappings.insert(RealName)) {
10420b57cec5SDimitry Andric // FIXME: We could theoretically map the same equivalence class to
10430b57cec5SDimitry Andric // multiple names in the profile data. If that happens, we should
10440b57cec5SDimitry Andric // return NamedInstrProfRecords from all of them.
10450b57cec5SDimitry Andric MappedNames.insert({Key, RealName});
10460b57cec5SDimitry Andric }
10470b57cec5SDimitry Andric }
10480b57cec5SDimitry Andric return Error::success();
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)10510b57cec5SDimitry Andric Error getRecords(StringRef FuncName,
10520b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> &Data) override {
10530b57cec5SDimitry Andric StringRef RealName = extractName(FuncName);
10540b57cec5SDimitry Andric if (auto Key = Remappings.lookup(RealName)) {
10550b57cec5SDimitry Andric StringRef Remapped = MappedNames.lookup(Key);
10560b57cec5SDimitry Andric if (!Remapped.empty()) {
10570b57cec5SDimitry Andric if (RealName.begin() == FuncName.begin() &&
10580b57cec5SDimitry Andric RealName.end() == FuncName.end())
10590b57cec5SDimitry Andric FuncName = Remapped;
10600b57cec5SDimitry Andric else {
10610b57cec5SDimitry Andric // Try rebuilding the name from the given remapping.
10620b57cec5SDimitry Andric SmallString<256> Reconstituted;
10630b57cec5SDimitry Andric reconstituteName(FuncName, RealName, Remapped, Reconstituted);
10640b57cec5SDimitry Andric Error E = Underlying.getRecords(Reconstituted, Data);
10650b57cec5SDimitry Andric if (!E)
10660b57cec5SDimitry Andric return E;
10670b57cec5SDimitry Andric
10680b57cec5SDimitry Andric // If we failed because the name doesn't exist, fall back to asking
10690b57cec5SDimitry Andric // about the original name.
10700b57cec5SDimitry Andric if (Error Unhandled = handleErrors(
10710b57cec5SDimitry Andric std::move(E), [](std::unique_ptr<InstrProfError> Err) {
10720b57cec5SDimitry Andric return Err->get() == instrprof_error::unknown_function
10730b57cec5SDimitry Andric ? Error::success()
10740b57cec5SDimitry Andric : Error(std::move(Err));
10750b57cec5SDimitry Andric }))
10760b57cec5SDimitry Andric return Unhandled;
10770b57cec5SDimitry Andric }
10780b57cec5SDimitry Andric }
10790b57cec5SDimitry Andric }
10800b57cec5SDimitry Andric return Underlying.getRecords(FuncName, Data);
10810b57cec5SDimitry Andric }
10820b57cec5SDimitry Andric
10830b57cec5SDimitry Andric private:
10840b57cec5SDimitry Andric /// The memory buffer containing the remapping configuration. Remappings
10850b57cec5SDimitry Andric /// holds pointers into this buffer.
10860b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> RemapBuffer;
10870b57cec5SDimitry Andric
10880b57cec5SDimitry Andric /// The mangling remapper.
10890b57cec5SDimitry Andric SymbolRemappingReader Remappings;
10900b57cec5SDimitry Andric
10910b57cec5SDimitry Andric /// Mapping from mangled name keys to the name used for the key in the
10920b57cec5SDimitry Andric /// profile data.
10930b57cec5SDimitry Andric /// FIXME: Can we store a location within the on-disk hash table instead of
10940b57cec5SDimitry Andric /// redoing lookup?
10950b57cec5SDimitry Andric DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
10960b57cec5SDimitry Andric
10970b57cec5SDimitry Andric /// The real profile data reader.
10980b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl> &Underlying;
10990b57cec5SDimitry Andric };
11000b57cec5SDimitry Andric
hasFormat(const MemoryBuffer & DataBuffer)11010b57cec5SDimitry Andric bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
11020b57cec5SDimitry Andric using namespace support;
11030b57cec5SDimitry Andric
11040b57cec5SDimitry Andric if (DataBuffer.getBufferSize() < 8)
11050b57cec5SDimitry Andric return false;
1106c9157d92SDimitry Andric uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(
1107c9157d92SDimitry Andric DataBuffer.getBufferStart());
11080b57cec5SDimitry Andric // Verify that it's magical.
11090b57cec5SDimitry Andric return Magic == IndexedInstrProf::Magic;
11100b57cec5SDimitry Andric }
11110b57cec5SDimitry Andric
11120b57cec5SDimitry Andric const unsigned char *
readSummary(IndexedInstrProf::ProfVersion Version,const unsigned char * Cur,bool UseCS)11130b57cec5SDimitry Andric IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
11140b57cec5SDimitry Andric const unsigned char *Cur, bool UseCS) {
11150b57cec5SDimitry Andric using namespace IndexedInstrProf;
11160b57cec5SDimitry Andric using namespace support;
11170b57cec5SDimitry Andric
11180b57cec5SDimitry Andric if (Version >= IndexedInstrProf::Version4) {
11190b57cec5SDimitry Andric const IndexedInstrProf::Summary *SummaryInLE =
11200b57cec5SDimitry Andric reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
1121c9157d92SDimitry Andric uint64_t NFields = endian::byte_swap<uint64_t, llvm::endianness::little>(
1122c9157d92SDimitry Andric SummaryInLE->NumSummaryFields);
1123c9157d92SDimitry Andric uint64_t NEntries = endian::byte_swap<uint64_t, llvm::endianness::little>(
1124c9157d92SDimitry Andric SummaryInLE->NumCutoffEntries);
11250b57cec5SDimitry Andric uint32_t SummarySize =
11260b57cec5SDimitry Andric IndexedInstrProf::Summary::getSize(NFields, NEntries);
11270b57cec5SDimitry Andric std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
11280b57cec5SDimitry Andric IndexedInstrProf::allocSummary(SummarySize);
11290b57cec5SDimitry Andric
11300b57cec5SDimitry Andric const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
11310b57cec5SDimitry Andric uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
11320b57cec5SDimitry Andric for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
1133c9157d92SDimitry Andric Dst[I] = endian::byte_swap<uint64_t, llvm::endianness::little>(Src[I]);
11340b57cec5SDimitry Andric
11350b57cec5SDimitry Andric SummaryEntryVector DetailedSummary;
11360b57cec5SDimitry Andric for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
11370b57cec5SDimitry Andric const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
11380b57cec5SDimitry Andric DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
11390b57cec5SDimitry Andric Ent.NumBlocks);
11400b57cec5SDimitry Andric }
11410b57cec5SDimitry Andric std::unique_ptr<llvm::ProfileSummary> &Summary =
11420b57cec5SDimitry Andric UseCS ? this->CS_Summary : this->Summary;
11430b57cec5SDimitry Andric
11440b57cec5SDimitry Andric // initialize InstrProfSummary using the SummaryData from disk.
11458bcb0991SDimitry Andric Summary = std::make_unique<ProfileSummary>(
11460b57cec5SDimitry Andric UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr,
11470b57cec5SDimitry Andric DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
11480b57cec5SDimitry Andric SummaryData->get(Summary::MaxBlockCount),
11490b57cec5SDimitry Andric SummaryData->get(Summary::MaxInternalBlockCount),
11500b57cec5SDimitry Andric SummaryData->get(Summary::MaxFunctionCount),
11510b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumBlocks),
11520b57cec5SDimitry Andric SummaryData->get(Summary::TotalNumFunctions));
11530b57cec5SDimitry Andric return Cur + SummarySize;
11540b57cec5SDimitry Andric } else {
11558bcb0991SDimitry Andric // The older versions do not support a profile summary. This just computes
11568bcb0991SDimitry Andric // an empty summary, which will not result in accurate hot/cold detection.
11578bcb0991SDimitry Andric // We would need to call addRecord for all NamedInstrProfRecords to get the
11588bcb0991SDimitry Andric // correct summary. However, this version is old (prior to early 2016) and
11598bcb0991SDimitry Andric // has not been supporting an accurate summary for several years.
11600b57cec5SDimitry Andric InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
11618bcb0991SDimitry Andric Summary = Builder.getSummary();
11620b57cec5SDimitry Andric return Cur;
11630b57cec5SDimitry Andric }
11640b57cec5SDimitry Andric }
11650b57cec5SDimitry Andric
readHeader()11660b57cec5SDimitry Andric Error IndexedInstrProfReader::readHeader() {
11670b57cec5SDimitry Andric using namespace support;
11680b57cec5SDimitry Andric
11690b57cec5SDimitry Andric const unsigned char *Start =
11700b57cec5SDimitry Andric (const unsigned char *)DataBuffer->getBufferStart();
11710b57cec5SDimitry Andric const unsigned char *Cur = Start;
11720b57cec5SDimitry Andric if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
11730b57cec5SDimitry Andric return error(instrprof_error::truncated);
11740b57cec5SDimitry Andric
117581ad6265SDimitry Andric auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
117681ad6265SDimitry Andric if (!HeaderOr)
117781ad6265SDimitry Andric return HeaderOr.takeError();
11780b57cec5SDimitry Andric
117981ad6265SDimitry Andric const IndexedInstrProf::Header *Header = &HeaderOr.get();
118081ad6265SDimitry Andric Cur += Header->size();
11810b57cec5SDimitry Andric
118281ad6265SDimitry Andric Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
11830b57cec5SDimitry Andric /* UseCS */ false);
118481ad6265SDimitry Andric if (Header->formatVersion() & VARIANT_MASK_CSIR_PROF)
1185bdd1243dSDimitry Andric Cur =
1186bdd1243dSDimitry Andric readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
11870b57cec5SDimitry Andric /* UseCS */ true);
11880b57cec5SDimitry Andric // Read the hash type and start offset.
11890b57cec5SDimitry Andric IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
1190c9157d92SDimitry Andric endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashType));
11910b57cec5SDimitry Andric if (HashType > IndexedInstrProf::HashT::Last)
11920b57cec5SDimitry Andric return error(instrprof_error::unsupported_hash_type);
11930b57cec5SDimitry Andric
1194c9157d92SDimitry Andric uint64_t HashOffset =
1195c9157d92SDimitry Andric endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashOffset);
11960b57cec5SDimitry Andric
119781ad6265SDimitry Andric // The hash table with profile counts comes next.
119881ad6265SDimitry Andric auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
119981ad6265SDimitry Andric Start + HashOffset, Cur, Start, HashType, Header->formatVersion());
120081ad6265SDimitry Andric
1201bdd1243dSDimitry Andric // The MemProfOffset field in the header is only valid when the format
1202bdd1243dSDimitry Andric // version is higher than 8 (when it was introduced).
120381ad6265SDimitry Andric if (GET_VERSION(Header->formatVersion()) >= 8 &&
120481ad6265SDimitry Andric Header->formatVersion() & VARIANT_MASK_MEMPROF) {
120581ad6265SDimitry Andric uint64_t MemProfOffset =
1206c9157d92SDimitry Andric endian::byte_swap<uint64_t, llvm::endianness::little>(
1207c9157d92SDimitry Andric Header->MemProfOffset);
120881ad6265SDimitry Andric
120981ad6265SDimitry Andric const unsigned char *Ptr = Start + MemProfOffset;
121081ad6265SDimitry Andric // The value returned from RecordTableGenerator.Emit.
121181ad6265SDimitry Andric const uint64_t RecordTableOffset =
1212c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1213c9157d92SDimitry Andric unaligned>(Ptr);
1214bdd1243dSDimitry Andric // The offset in the stream right before invoking
1215bdd1243dSDimitry Andric // FrameTableGenerator.Emit.
121681ad6265SDimitry Andric const uint64_t FramePayloadOffset =
1217c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1218c9157d92SDimitry Andric unaligned>(Ptr);
121981ad6265SDimitry Andric // The value returned from FrameTableGenerator.Emit.
122081ad6265SDimitry Andric const uint64_t FrameTableOffset =
1221c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1222c9157d92SDimitry Andric unaligned>(Ptr);
122381ad6265SDimitry Andric
122481ad6265SDimitry Andric // Read the schema.
122581ad6265SDimitry Andric auto SchemaOr = memprof::readMemProfSchema(Ptr);
122681ad6265SDimitry Andric if (!SchemaOr)
122781ad6265SDimitry Andric return SchemaOr.takeError();
122881ad6265SDimitry Andric Schema = SchemaOr.get();
122981ad6265SDimitry Andric
123081ad6265SDimitry Andric // Now initialize the table reader with a pointer into data buffer.
123181ad6265SDimitry Andric MemProfRecordTable.reset(MemProfRecordHashTable::Create(
123281ad6265SDimitry Andric /*Buckets=*/Start + RecordTableOffset,
123381ad6265SDimitry Andric /*Payload=*/Ptr,
123481ad6265SDimitry Andric /*Base=*/Start, memprof::RecordLookupTrait(Schema)));
123581ad6265SDimitry Andric
123681ad6265SDimitry Andric // Initialize the frame table reader with the payload and bucket offsets.
123781ad6265SDimitry Andric MemProfFrameTable.reset(MemProfFrameHashTable::Create(
123881ad6265SDimitry Andric /*Buckets=*/Start + FrameTableOffset,
123981ad6265SDimitry Andric /*Payload=*/Start + FramePayloadOffset,
124081ad6265SDimitry Andric /*Base=*/Start, memprof::FrameLookupTrait()));
124181ad6265SDimitry Andric }
12420b57cec5SDimitry Andric
1243bdd1243dSDimitry Andric // BinaryIdOffset field in the header is only valid when the format version
1244bdd1243dSDimitry Andric // is higher than 9 (when it was introduced).
1245bdd1243dSDimitry Andric if (GET_VERSION(Header->formatVersion()) >= 9) {
1246bdd1243dSDimitry Andric uint64_t BinaryIdOffset =
1247c9157d92SDimitry Andric endian::byte_swap<uint64_t, llvm::endianness::little>(
1248c9157d92SDimitry Andric Header->BinaryIdOffset);
1249bdd1243dSDimitry Andric const unsigned char *Ptr = Start + BinaryIdOffset;
1250bdd1243dSDimitry Andric // Read binary ids size.
1251c9157d92SDimitry Andric BinaryIdsSize =
1252c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1253c9157d92SDimitry Andric unaligned>(Ptr);
1254bdd1243dSDimitry Andric if (BinaryIdsSize % sizeof(uint64_t))
1255bdd1243dSDimitry Andric return error(instrprof_error::bad_header);
1256bdd1243dSDimitry Andric // Set the binary ids start.
1257bdd1243dSDimitry Andric BinaryIdsStart = Ptr;
1258bdd1243dSDimitry Andric if (BinaryIdsStart > (const unsigned char *)DataBuffer->getBufferEnd())
1259bdd1243dSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed,
1260bdd1243dSDimitry Andric "corrupted binary ids");
1261bdd1243dSDimitry Andric }
1262bdd1243dSDimitry Andric
1263fe013be4SDimitry Andric if (GET_VERSION(Header->formatVersion()) >= 10 &&
1264fe013be4SDimitry Andric Header->formatVersion() & VARIANT_MASK_TEMPORAL_PROF) {
1265fe013be4SDimitry Andric uint64_t TemporalProfTracesOffset =
1266c9157d92SDimitry Andric endian::byte_swap<uint64_t, llvm::endianness::little>(
1267c9157d92SDimitry Andric Header->TemporalProfTracesOffset);
1268fe013be4SDimitry Andric const unsigned char *Ptr = Start + TemporalProfTracesOffset;
1269fe013be4SDimitry Andric const auto *PtrEnd = (const unsigned char *)DataBuffer->getBufferEnd();
1270fe013be4SDimitry Andric // Expect at least two 64 bit fields: NumTraces, and TraceStreamSize
1271fe013be4SDimitry Andric if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1272fe013be4SDimitry Andric return error(instrprof_error::truncated);
1273fe013be4SDimitry Andric const uint64_t NumTraces =
1274c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1275c9157d92SDimitry Andric unaligned>(Ptr);
1276fe013be4SDimitry Andric TemporalProfTraceStreamSize =
1277c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1278c9157d92SDimitry Andric unaligned>(Ptr);
1279fe013be4SDimitry Andric for (unsigned i = 0; i < NumTraces; i++) {
1280fe013be4SDimitry Andric // Expect at least two 64 bit fields: Weight and NumFunctions
1281fe013be4SDimitry Andric if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1282fe013be4SDimitry Andric return error(instrprof_error::truncated);
1283fe013be4SDimitry Andric TemporalProfTraceTy Trace;
1284fe013be4SDimitry Andric Trace.Weight =
1285c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1286c9157d92SDimitry Andric unaligned>(Ptr);
1287fe013be4SDimitry Andric const uint64_t NumFunctions =
1288c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1289c9157d92SDimitry Andric unaligned>(Ptr);
1290fe013be4SDimitry Andric // Expect at least NumFunctions 64 bit fields
1291fe013be4SDimitry Andric if (Ptr + NumFunctions * sizeof(uint64_t) > PtrEnd)
1292fe013be4SDimitry Andric return error(instrprof_error::truncated);
1293fe013be4SDimitry Andric for (unsigned j = 0; j < NumFunctions; j++) {
1294fe013be4SDimitry Andric const uint64_t NameRef =
1295c9157d92SDimitry Andric support::endian::readNext<uint64_t, llvm::endianness::little,
1296c9157d92SDimitry Andric unaligned>(Ptr);
1297fe013be4SDimitry Andric Trace.FunctionNameRefs.push_back(NameRef);
1298fe013be4SDimitry Andric }
1299fe013be4SDimitry Andric TemporalProfTraces.push_back(std::move(Trace));
1300fe013be4SDimitry Andric }
1301fe013be4SDimitry Andric }
1302fe013be4SDimitry Andric
13030b57cec5SDimitry Andric // Load the remapping table now if requested.
13040b57cec5SDimitry Andric if (RemappingBuffer) {
1305bdd1243dSDimitry Andric Remapper =
1306bdd1243dSDimitry Andric std::make_unique<InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
13070b57cec5SDimitry Andric std::move(RemappingBuffer), *IndexPtr);
13080b57cec5SDimitry Andric if (Error E = Remapper->populateRemappings())
13090b57cec5SDimitry Andric return E;
13100b57cec5SDimitry Andric } else {
13118bcb0991SDimitry Andric Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
13120b57cec5SDimitry Andric }
13130b57cec5SDimitry Andric Index = std::move(IndexPtr);
13140b57cec5SDimitry Andric
13150b57cec5SDimitry Andric return success();
13160b57cec5SDimitry Andric }
13170b57cec5SDimitry Andric
getSymtab()13180b57cec5SDimitry Andric InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
131981ad6265SDimitry Andric if (Symtab)
132081ad6265SDimitry Andric return *Symtab;
13210b57cec5SDimitry Andric
13228bcb0991SDimitry Andric std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
132381ad6265SDimitry Andric if (Error E = Index->populateSymtab(*NewSymtab)) {
1324fe013be4SDimitry Andric auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1325fe013be4SDimitry Andric consumeError(error(ErrCode, Msg));
13260b57cec5SDimitry Andric }
13270b57cec5SDimitry Andric
13280b57cec5SDimitry Andric Symtab = std::move(NewSymtab);
132981ad6265SDimitry Andric return *Symtab;
13300b57cec5SDimitry Andric }
13310b57cec5SDimitry Andric
getInstrProfRecord(StringRef FuncName,uint64_t FuncHash,StringRef DeprecatedFuncName,uint64_t * MismatchedFuncSum)1332fcaf7f86SDimitry Andric Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(
1333c9157d92SDimitry Andric StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName,
1334c9157d92SDimitry Andric uint64_t *MismatchedFuncSum) {
13350b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data;
1336fcaf7f86SDimitry Andric uint64_t FuncSum = 0;
1337c9157d92SDimitry Andric auto Err = Remapper->getRecords(FuncName, Data);
1338c9157d92SDimitry Andric if (Err) {
1339c9157d92SDimitry Andric // If we don't find FuncName, try DeprecatedFuncName to handle profiles
1340c9157d92SDimitry Andric // built by older compilers.
1341c9157d92SDimitry Andric auto Err2 =
1342c9157d92SDimitry Andric handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
1343c9157d92SDimitry Andric if (IE.get() != instrprof_error::unknown_function)
1344c9157d92SDimitry Andric return make_error<InstrProfError>(IE);
1345c9157d92SDimitry Andric if (auto Err = Remapper->getRecords(DeprecatedFuncName, Data))
1346c9157d92SDimitry Andric return Err;
1347c9157d92SDimitry Andric return Error::success();
1348c9157d92SDimitry Andric });
1349c9157d92SDimitry Andric if (Err2)
1350c9157d92SDimitry Andric return std::move(Err2);
1351c9157d92SDimitry Andric }
13520b57cec5SDimitry Andric // Found it. Look for counters with the right hash.
1353fcaf7f86SDimitry Andric
1354fcaf7f86SDimitry Andric // A flag to indicate if the records are from the same type
1355fcaf7f86SDimitry Andric // of profile (i.e cs vs nocs).
1356fcaf7f86SDimitry Andric bool CSBitMatch = false;
1357fcaf7f86SDimitry Andric auto getFuncSum = [](const std::vector<uint64_t> &Counts) {
1358fcaf7f86SDimitry Andric uint64_t ValueSum = 0;
1359bdd1243dSDimitry Andric for (uint64_t CountValue : Counts) {
1360fcaf7f86SDimitry Andric if (CountValue == (uint64_t)-1)
1361fcaf7f86SDimitry Andric continue;
1362fcaf7f86SDimitry Andric // Handle overflow -- if that happens, return max.
1363fcaf7f86SDimitry Andric if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1364fcaf7f86SDimitry Andric return std::numeric_limits<uint64_t>::max();
1365fcaf7f86SDimitry Andric ValueSum += CountValue;
1366fcaf7f86SDimitry Andric }
1367fcaf7f86SDimitry Andric return ValueSum;
1368fcaf7f86SDimitry Andric };
1369fcaf7f86SDimitry Andric
13700eae32dcSDimitry Andric for (const NamedInstrProfRecord &I : Data) {
13710b57cec5SDimitry Andric // Check for a match and fill the vector if there is one.
13720eae32dcSDimitry Andric if (I.Hash == FuncHash)
13730eae32dcSDimitry Andric return std::move(I);
1374fcaf7f86SDimitry Andric if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) ==
1375fcaf7f86SDimitry Andric NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) {
1376fcaf7f86SDimitry Andric CSBitMatch = true;
1377fcaf7f86SDimitry Andric if (MismatchedFuncSum == nullptr)
1378fcaf7f86SDimitry Andric continue;
1379fcaf7f86SDimitry Andric FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
13800b57cec5SDimitry Andric }
1381fcaf7f86SDimitry Andric }
1382fcaf7f86SDimitry Andric if (CSBitMatch) {
1383fcaf7f86SDimitry Andric if (MismatchedFuncSum != nullptr)
1384fcaf7f86SDimitry Andric *MismatchedFuncSum = FuncSum;
13850b57cec5SDimitry Andric return error(instrprof_error::hash_mismatch);
13860b57cec5SDimitry Andric }
1387fcaf7f86SDimitry Andric return error(instrprof_error::unknown_function);
1388fcaf7f86SDimitry Andric }
13890b57cec5SDimitry Andric
139081ad6265SDimitry Andric Expected<memprof::MemProfRecord>
getMemProfRecord(const uint64_t FuncNameHash)139181ad6265SDimitry Andric IndexedInstrProfReader::getMemProfRecord(const uint64_t FuncNameHash) {
139281ad6265SDimitry Andric // TODO: Add memprof specific errors.
139381ad6265SDimitry Andric if (MemProfRecordTable == nullptr)
139481ad6265SDimitry Andric return make_error<InstrProfError>(instrprof_error::invalid_prof,
139581ad6265SDimitry Andric "no memprof data available in profile");
139681ad6265SDimitry Andric auto Iter = MemProfRecordTable->find(FuncNameHash);
139781ad6265SDimitry Andric if (Iter == MemProfRecordTable->end())
139881ad6265SDimitry Andric return make_error<InstrProfError>(
139981ad6265SDimitry Andric instrprof_error::unknown_function,
140081ad6265SDimitry Andric "memprof record not found for function hash " + Twine(FuncNameHash));
140181ad6265SDimitry Andric
140281ad6265SDimitry Andric // Setup a callback to convert from frame ids to frame using the on-disk
140381ad6265SDimitry Andric // FrameData hash table.
140481ad6265SDimitry Andric memprof::FrameId LastUnmappedFrameId = 0;
140581ad6265SDimitry Andric bool HasFrameMappingError = false;
140681ad6265SDimitry Andric auto IdToFrameCallback = [&](const memprof::FrameId Id) {
140781ad6265SDimitry Andric auto FrIter = MemProfFrameTable->find(Id);
140881ad6265SDimitry Andric if (FrIter == MemProfFrameTable->end()) {
140981ad6265SDimitry Andric LastUnmappedFrameId = Id;
141081ad6265SDimitry Andric HasFrameMappingError = true;
141181ad6265SDimitry Andric return memprof::Frame(0, 0, 0, false);
141281ad6265SDimitry Andric }
141381ad6265SDimitry Andric return *FrIter;
141481ad6265SDimitry Andric };
141581ad6265SDimitry Andric
141681ad6265SDimitry Andric memprof::MemProfRecord Record(*Iter, IdToFrameCallback);
141781ad6265SDimitry Andric
141881ad6265SDimitry Andric // Check that all frame ids were successfully converted to frames.
141981ad6265SDimitry Andric if (HasFrameMappingError) {
142081ad6265SDimitry Andric return make_error<InstrProfError>(instrprof_error::hash_mismatch,
142181ad6265SDimitry Andric "memprof frame not found for frame id " +
142281ad6265SDimitry Andric Twine(LastUnmappedFrameId));
142381ad6265SDimitry Andric }
142481ad6265SDimitry Andric return Record;
142581ad6265SDimitry Andric }
142681ad6265SDimitry Andric
getFunctionCounts(StringRef FuncName,uint64_t FuncHash,std::vector<uint64_t> & Counts)14270b57cec5SDimitry Andric Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
14280b57cec5SDimitry Andric uint64_t FuncHash,
14290b57cec5SDimitry Andric std::vector<uint64_t> &Counts) {
14300b57cec5SDimitry Andric Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
14310b57cec5SDimitry Andric if (Error E = Record.takeError())
14320b57cec5SDimitry Andric return error(std::move(E));
14330b57cec5SDimitry Andric
14340b57cec5SDimitry Andric Counts = Record.get().Counts;
14350b57cec5SDimitry Andric return success();
14360b57cec5SDimitry Andric }
14370b57cec5SDimitry Andric
getFunctionBitmapBytes(StringRef FuncName,uint64_t FuncHash,std::vector<uint8_t> & BitmapBytes)1438c9157d92SDimitry Andric Error IndexedInstrProfReader::getFunctionBitmapBytes(
1439c9157d92SDimitry Andric StringRef FuncName, uint64_t FuncHash, std::vector<uint8_t> &BitmapBytes) {
1440c9157d92SDimitry Andric Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
1441c9157d92SDimitry Andric if (Error E = Record.takeError())
1442c9157d92SDimitry Andric return error(std::move(E));
1443c9157d92SDimitry Andric
1444c9157d92SDimitry Andric BitmapBytes = Record.get().BitmapBytes;
1445c9157d92SDimitry Andric return success();
1446c9157d92SDimitry Andric }
1447c9157d92SDimitry Andric
readNextRecord(NamedInstrProfRecord & Record)14480b57cec5SDimitry Andric Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
14490b57cec5SDimitry Andric ArrayRef<NamedInstrProfRecord> Data;
14500b57cec5SDimitry Andric
14510b57cec5SDimitry Andric Error E = Index->getRecords(Data);
14520b57cec5SDimitry Andric if (E)
14530b57cec5SDimitry Andric return error(std::move(E));
14540b57cec5SDimitry Andric
14550b57cec5SDimitry Andric Record = Data[RecordIndex++];
14560b57cec5SDimitry Andric if (RecordIndex >= Data.size()) {
14570b57cec5SDimitry Andric Index->advanceToNextKey();
14580b57cec5SDimitry Andric RecordIndex = 0;
14590b57cec5SDimitry Andric }
14600b57cec5SDimitry Andric return success();
14610b57cec5SDimitry Andric }
14620b57cec5SDimitry Andric
readBinaryIds(std::vector<llvm::object::BuildID> & BinaryIds)1463bdd1243dSDimitry Andric Error IndexedInstrProfReader::readBinaryIds(
1464bdd1243dSDimitry Andric std::vector<llvm::object::BuildID> &BinaryIds) {
1465bdd1243dSDimitry Andric return readBinaryIdsInternal(*DataBuffer, BinaryIdsSize, BinaryIdsStart,
1466c9157d92SDimitry Andric BinaryIds, llvm::endianness::little);
1467bdd1243dSDimitry Andric }
1468bdd1243dSDimitry Andric
printBinaryIds(raw_ostream & OS)1469bdd1243dSDimitry Andric Error IndexedInstrProfReader::printBinaryIds(raw_ostream &OS) {
1470c9157d92SDimitry Andric std::vector<llvm::object::BuildID> BinaryIds;
1471c9157d92SDimitry Andric if (Error E = readBinaryIds(BinaryIds))
1472c9157d92SDimitry Andric return E;
1473c9157d92SDimitry Andric printBinaryIdsInternal(OS, BinaryIds);
1474c9157d92SDimitry Andric return Error::success();
1475bdd1243dSDimitry Andric }
1476bdd1243dSDimitry Andric
accumulateCounts(CountSumOrPercent & Sum,bool IsCS)14778bcb0991SDimitry Andric void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) {
14780b57cec5SDimitry Andric uint64_t NumFuncs = 0;
14790b57cec5SDimitry Andric for (const auto &Func : *this) {
14800b57cec5SDimitry Andric if (isIRLevelProfile()) {
14810b57cec5SDimitry Andric bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
14820b57cec5SDimitry Andric if (FuncIsCS != IsCS)
14830b57cec5SDimitry Andric continue;
14840b57cec5SDimitry Andric }
14858bcb0991SDimitry Andric Func.accumulateCounts(Sum);
14860b57cec5SDimitry Andric ++NumFuncs;
14870b57cec5SDimitry Andric }
14880b57cec5SDimitry Andric Sum.NumEntries = NumFuncs;
14890b57cec5SDimitry Andric }
1490