1e78d131aSEugene Zelenko //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===//
2f8d79198SJustin Bogner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f8d79198SJustin Bogner //
7f8d79198SJustin Bogner //===----------------------------------------------------------------------===//
8f8d79198SJustin Bogner //
9f8d79198SJustin Bogner // This file contains support for reading profiling data for clang's
10f8d79198SJustin Bogner // instrumentation based PGO and coverage.
11f8d79198SJustin Bogner //
12f8d79198SJustin Bogner //===----------------------------------------------------------------------===//
13f8d79198SJustin Bogner
146bda14b3SChandler Carruth #include "llvm/ProfileData/InstrProfReader.h"
15e78d131aSEugene Zelenko #include "llvm/ADT/ArrayRef.h"
16ceed4eb1SRichard Smith #include "llvm/ADT/DenseMap.h"
17d10c995bSSam McCall #include "llvm/ADT/StringExtras.h"
18e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h"
19e78d131aSEugene Zelenko #include "llvm/IR/ProfileSummary.h"
20e78d131aSEugene Zelenko #include "llvm/ProfileData/InstrProf.h"
210a418490SSnehasish Kumar #include "llvm/ProfileData/MemProf.h"
22e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h"
23e78d131aSEugene Zelenko #include "llvm/Support/Endian.h"
24e78d131aSEugene Zelenko #include "llvm/Support/Error.h"
25e78d131aSEugene Zelenko #include "llvm/Support/ErrorOr.h"
26e78d131aSEugene Zelenko #include "llvm/Support/MemoryBuffer.h"
27fd895bc8SGulfem Savrun Yeniceri #include "llvm/Support/SwapByteOrder.h"
28e50a3884SGulfem Savrun Yeniceri #include "llvm/Support/SymbolRemappingReader.h"
29e78d131aSEugene Zelenko #include <algorithm>
30e78d131aSEugene Zelenko #include <cstddef>
31e78d131aSEugene Zelenko #include <cstdint>
32e78d131aSEugene Zelenko #include <limits>
33e78d131aSEugene Zelenko #include <memory>
34e78d131aSEugene Zelenko #include <system_error>
35e78d131aSEugene Zelenko #include <utility>
36e78d131aSEugene Zelenko #include <vector>
37f8d79198SJustin Bogner
38f8d79198SJustin Bogner using namespace llvm;
39f8d79198SJustin Bogner
40186dcd4aSSnehasish Kumar // Extracts the variant information from the top 8 bits in the version and
41186dcd4aSSnehasish Kumar // returns an enum specifying the variants present.
getProfileKindFromVersion(uint64_t Version)42186dcd4aSSnehasish Kumar static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
43186dcd4aSSnehasish Kumar InstrProfKind ProfileKind = InstrProfKind::Unknown;
44186dcd4aSSnehasish Kumar if (Version & VARIANT_MASK_IR_PROF) {
45b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::IRInstrumentation;
46186dcd4aSSnehasish Kumar }
47186dcd4aSSnehasish Kumar if (Version & VARIANT_MASK_CSIR_PROF) {
48b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::ContextSensitive;
49186dcd4aSSnehasish Kumar }
50186dcd4aSSnehasish Kumar if (Version & VARIANT_MASK_INSTR_ENTRY) {
51b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
52186dcd4aSSnehasish Kumar }
53186dcd4aSSnehasish Kumar if (Version & VARIANT_MASK_BYTE_COVERAGE) {
54186dcd4aSSnehasish Kumar ProfileKind |= InstrProfKind::SingleByteCoverage;
55186dcd4aSSnehasish Kumar }
56186dcd4aSSnehasish Kumar if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
57186dcd4aSSnehasish Kumar ProfileKind |= InstrProfKind::FunctionEntryOnly;
58186dcd4aSSnehasish Kumar }
590a418490SSnehasish Kumar if (Version & VARIANT_MASK_MEMPROF) {
600a418490SSnehasish Kumar ProfileKind |= InstrProfKind::MemProf;
610a418490SSnehasish Kumar }
62186dcd4aSSnehasish Kumar return ProfileKind;
63186dcd4aSSnehasish Kumar }
64186dcd4aSSnehasish Kumar
659152fd17SVedant Kumar static Expected<std::unique_ptr<MemoryBuffer>>
setupMemoryBuffer(const Twine & Path)660da23a27SBenjamin Kramer setupMemoryBuffer(const Twine &Path) {
67adf21f2aSRafael Espindola ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
68e71994a2SJonathan Crowther MemoryBuffer::getFileOrSTDIN(Path, /*IsText=*/true);
69adf21f2aSRafael Espindola if (std::error_code EC = BufferOrErr.getError())
709152fd17SVedant Kumar return errorCodeToError(EC);
712b6c537bSJustin Bogner return std::move(BufferOrErr.get());
72b7aa2630SJustin Bogner }
73b7aa2630SJustin Bogner
initializeReader(InstrProfReader & Reader)749152fd17SVedant Kumar static Error initializeReader(InstrProfReader &Reader) {
75b7aa2630SJustin Bogner return Reader.readHeader();
76b7aa2630SJustin Bogner }
77b7aa2630SJustin Bogner
789152fd17SVedant Kumar Expected<std::unique_ptr<InstrProfReader>>
create(const Twine & Path,const InstrProfCorrelator * Correlator)7965d7fd02SEllis Hoag InstrProfReader::create(const Twine &Path,
8065d7fd02SEllis Hoag const InstrProfCorrelator *Correlator) {
81b7aa2630SJustin Bogner // Set up the buffer to read.
82fcd55607SDiego Novillo auto BufferOrError = setupMemoryBuffer(Path);
839152fd17SVedant Kumar if (Error E = BufferOrError.takeError())
84c55cf4afSBill Wendling return std::move(E);
8565d7fd02SEllis Hoag return InstrProfReader::create(std::move(BufferOrError.get()), Correlator);
862b6c537bSJustin Bogner }
87f8d79198SJustin Bogner
889152fd17SVedant Kumar Expected<std::unique_ptr<InstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,const InstrProfCorrelator * Correlator)8965d7fd02SEllis Hoag InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
9065d7fd02SEllis Hoag const InstrProfCorrelator *Correlator) {
9165d7fd02SEllis Hoag // Sanity check the buffer.
92d6c15b66SVedant Kumar if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max())
939152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::too_large);
942b6c537bSJustin Bogner
952c684cfdSRong Xu if (Buffer->getBufferSize() == 0)
962c684cfdSRong Xu return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
972c684cfdSRong Xu
98fcd55607SDiego Novillo std::unique_ptr<InstrProfReader> Result;
9909a67f45SDuncan P. N. Exon Smith // Create the reader.
100b7aa2630SJustin Bogner if (IndexedInstrProfReader::hasFormat(*Buffer))
101b7aa2630SJustin Bogner Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
102b7aa2630SJustin Bogner else if (RawInstrProfReader64::hasFormat(*Buffer))
10365d7fd02SEllis Hoag Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator));
1044680361dSDuncan P. N. Exon Smith else if (RawInstrProfReader32::hasFormat(*Buffer))
10565d7fd02SEllis Hoag Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator));
1064f823667SNathan Slingerland else if (TextInstrProfReader::hasFormat(*Buffer))
107911ced6bSNathan Slingerland Result.reset(new TextInstrProfReader(std::move(Buffer)));
1084f823667SNathan Slingerland else
1099152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::unrecognized_format);
11009a67f45SDuncan P. N. Exon Smith
111b7aa2630SJustin Bogner // Initialize the reader and return the result.
1129152fd17SVedant Kumar if (Error E = initializeReader(*Result))
113c55cf4afSBill Wendling return std::move(E);
114fcd55607SDiego Novillo
115c55cf4afSBill Wendling return std::move(Result);
116b7aa2630SJustin Bogner }
117b7aa2630SJustin Bogner
1189152fd17SVedant Kumar Expected<std::unique_ptr<IndexedInstrProfReader>>
create(const Twine & Path,const Twine & RemappingPath)119ceed4eb1SRichard Smith IndexedInstrProfReader::create(const Twine &Path, const Twine &RemappingPath) {
120b7aa2630SJustin Bogner // Set up the buffer to read.
121fcd55607SDiego Novillo auto BufferOrError = setupMemoryBuffer(Path);
1229152fd17SVedant Kumar if (Error E = BufferOrError.takeError())
123c55cf4afSBill Wendling return std::move(E);
124ceed4eb1SRichard Smith
125ceed4eb1SRichard Smith // Set up the remapping buffer if requested.
126ceed4eb1SRichard Smith std::unique_ptr<MemoryBuffer> RemappingBuffer;
127ceed4eb1SRichard Smith std::string RemappingPathStr = RemappingPath.str();
128ceed4eb1SRichard Smith if (!RemappingPathStr.empty()) {
129ceed4eb1SRichard Smith auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr);
130ceed4eb1SRichard Smith if (Error E = RemappingBufferOrError.takeError())
131c55cf4afSBill Wendling return std::move(E);
132ceed4eb1SRichard Smith RemappingBuffer = std::move(RemappingBufferOrError.get());
133ceed4eb1SRichard Smith }
134ceed4eb1SRichard Smith
135ceed4eb1SRichard Smith return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
136ceed4eb1SRichard Smith std::move(RemappingBuffer));
1372b6c537bSJustin Bogner }
138b7aa2630SJustin Bogner
1399152fd17SVedant Kumar Expected<std::unique_ptr<IndexedInstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<MemoryBuffer> RemappingBuffer)140ceed4eb1SRichard Smith IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
141ceed4eb1SRichard Smith std::unique_ptr<MemoryBuffer> RemappingBuffer) {
142d6c15b66SVedant Kumar if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max())
1439152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::too_large);
144ab89ed7dSJustin Bogner
145b7aa2630SJustin Bogner // Create the reader.
146b7aa2630SJustin Bogner if (!IndexedInstrProfReader::hasFormat(*Buffer))
1479152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::bad_magic);
1480eaee545SJonas Devlieghere auto Result = std::make_unique<IndexedInstrProfReader>(
149ceed4eb1SRichard Smith std::move(Buffer), std::move(RemappingBuffer));
150b7aa2630SJustin Bogner
151b7aa2630SJustin Bogner // Initialize the reader and return the result.
1529152fd17SVedant Kumar if (Error E = initializeReader(*Result))
153c55cf4afSBill Wendling return std::move(E);
154ab89ed7dSJustin Bogner
155c55cf4afSBill Wendling return std::move(Result);
156f8d79198SJustin Bogner }
157f8d79198SJustin Bogner
hasFormat(const MemoryBuffer & Buffer)1584f823667SNathan Slingerland bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
1594f823667SNathan Slingerland // Verify that this really looks like plain ASCII text by checking a
1604f823667SNathan Slingerland // 'reasonable' number of characters (up to profile magic size).
1614f823667SNathan Slingerland size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
1624f823667SNathan Slingerland StringRef buffer = Buffer.getBufferStart();
1632491dd11SVedant Kumar return count == 0 ||
1642491dd11SVedant Kumar std::all_of(buffer.begin(), buffer.begin() + count,
165d10c995bSSam McCall [](char c) { return isPrint(c) || isSpace(c); });
1664f823667SNathan Slingerland }
1674f823667SNathan Slingerland
16833c76c0cSRong Xu // Read the profile variant flag from the header: ":FE" means this is a FE
16933c76c0cSRong Xu // generated profile. ":IR" means this is an IR level profile. Other strings
17033c76c0cSRong Xu // with a leading ':' will be reported an error format.
readHeader()1719152fd17SVedant Kumar Error TextInstrProfReader::readHeader() {
172a716cc5cSXinliang David Li Symtab.reset(new InstrProfSymtab());
17350da55a5SRong Xu
17450da55a5SRong Xu while (Line->startswith(":")) {
17550da55a5SRong Xu StringRef Str = Line->substr(1);
17642f74e82SMartin Storsjö if (Str.equals_insensitive("ir"))
177b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::IRInstrumentation;
17842f74e82SMartin Storsjö else if (Str.equals_insensitive("fe"))
179b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::FrontendInstrumentation;
18042f74e82SMartin Storsjö else if (Str.equals_insensitive("csir")) {
181b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::IRInstrumentation;
182b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::ContextSensitive;
18342f74e82SMartin Storsjö } else if (Str.equals_insensitive("entry_first"))
184b6817999SSnehasish Kumar ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
18542f74e82SMartin Storsjö else if (Str.equals_insensitive("not_entry_first"))
186b6817999SSnehasish Kumar ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
18750da55a5SRong Xu else
1889152fd17SVedant Kumar return error(instrprof_error::bad_header);
18933c76c0cSRong Xu ++Line;
19050da55a5SRong Xu }
191a716cc5cSXinliang David Li return success();
192a716cc5cSXinliang David Li }
193a716cc5cSXinliang David Li
1949152fd17SVedant Kumar Error
readValueProfileData(InstrProfRecord & Record)195e3bf4fd3SXinliang David Li TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
196e3bf4fd3SXinliang David Li
197e3bf4fd3SXinliang David Li #define CHECK_LINE_END(Line) \
198e3bf4fd3SXinliang David Li if (Line.is_at_end()) \
199e3bf4fd3SXinliang David Li return error(instrprof_error::truncated);
200e3bf4fd3SXinliang David Li #define READ_NUM(Str, Dst) \
201e3bf4fd3SXinliang David Li if ((Str).getAsInteger(10, (Dst))) \
202e3bf4fd3SXinliang David Li return error(instrprof_error::malformed);
203e3bf4fd3SXinliang David Li #define VP_READ_ADVANCE(Val) \
204e3bf4fd3SXinliang David Li CHECK_LINE_END(Line); \
205e3bf4fd3SXinliang David Li uint32_t Val; \
206e3bf4fd3SXinliang David Li READ_NUM((*Line), (Val)); \
207e3bf4fd3SXinliang David Li Line++;
208e3bf4fd3SXinliang David Li
209e3bf4fd3SXinliang David Li if (Line.is_at_end())
210e3bf4fd3SXinliang David Li return success();
211a716cc5cSXinliang David Li
212e3bf4fd3SXinliang David Li uint32_t NumValueKinds;
213e3bf4fd3SXinliang David Li if (Line->getAsInteger(10, NumValueKinds)) {
214e3bf4fd3SXinliang David Li // No value profile data
215e3bf4fd3SXinliang David Li return success();
216e3bf4fd3SXinliang David Li }
217e3bf4fd3SXinliang David Li if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
218ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed,
219ee88b8d6SGulfem Savrun Yeniceri "number of value kinds is invalid");
220e3bf4fd3SXinliang David Li Line++;
221e3bf4fd3SXinliang David Li
222e3bf4fd3SXinliang David Li for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
223e3bf4fd3SXinliang David Li VP_READ_ADVANCE(ValueKind);
224e3bf4fd3SXinliang David Li if (ValueKind > IPVK_Last)
225ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed, "value kind is invalid");
226ee88b8d6SGulfem Savrun Yeniceri ;
227e3bf4fd3SXinliang David Li VP_READ_ADVANCE(NumValueSites);
228e3bf4fd3SXinliang David Li if (!NumValueSites)
229e3bf4fd3SXinliang David Li continue;
230e3bf4fd3SXinliang David Li
231e3bf4fd3SXinliang David Li Record.reserveSites(VK, NumValueSites);
232e3bf4fd3SXinliang David Li for (uint32_t S = 0; S < NumValueSites; S++) {
233e3bf4fd3SXinliang David Li VP_READ_ADVANCE(NumValueData);
234e3bf4fd3SXinliang David Li
235e3bf4fd3SXinliang David Li std::vector<InstrProfValueData> CurrentValues;
236e3bf4fd3SXinliang David Li for (uint32_t V = 0; V < NumValueData; V++) {
237e3bf4fd3SXinliang David Li CHECK_LINE_END(Line);
23835723644SRong Xu std::pair<StringRef, StringRef> VD = Line->rsplit(':');
239e3bf4fd3SXinliang David Li uint64_t TakenCount, Value;
240cbb11407SRong Xu if (ValueKind == IPVK_IndirectCallTarget) {
24129a21babSMircea Trofin if (InstrProfSymtab::isExternalSymbol(VD.first)) {
24229a21babSMircea Trofin Value = 0;
24329a21babSMircea Trofin } else {
244b5794ca9SVedant Kumar if (Error E = Symtab->addFuncName(VD.first))
245b5794ca9SVedant Kumar return E;
246a716cc5cSXinliang David Li Value = IndexedInstrProf::ComputeHash(VD.first);
24729a21babSMircea Trofin }
248a716cc5cSXinliang David Li } else {
249e3bf4fd3SXinliang David Li READ_NUM(VD.first, Value);
250e3bf4fd3SXinliang David Li }
251a716cc5cSXinliang David Li READ_NUM(VD.second, TakenCount);
252e3bf4fd3SXinliang David Li CurrentValues.push_back({Value, TakenCount});
253e3bf4fd3SXinliang David Li Line++;
254e3bf4fd3SXinliang David Li }
255cbb11407SRong Xu Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData,
256cbb11407SRong Xu nullptr);
257e3bf4fd3SXinliang David Li }
258e3bf4fd3SXinliang David Li }
259e3bf4fd3SXinliang David Li return success();
260e3bf4fd3SXinliang David Li
261e3bf4fd3SXinliang David Li #undef CHECK_LINE_END
262e3bf4fd3SXinliang David Li #undef READ_NUM
263e3bf4fd3SXinliang David Li #undef VP_READ_ADVANCE
264e3bf4fd3SXinliang David Li }
265e3bf4fd3SXinliang David Li
readNextRecord(NamedInstrProfRecord & Record)266cf9d52c6SDavid Blaikie Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
267cf36a366SJustin Bogner // Skip empty lines and comments.
268cf36a366SJustin Bogner while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
269f8d79198SJustin Bogner ++Line;
270f8d79198SJustin Bogner // If we hit EOF while looking for a name, we're done.
271a716cc5cSXinliang David Li if (Line.is_at_end()) {
272f8d79198SJustin Bogner return error(instrprof_error::eof);
273a716cc5cSXinliang David Li }
274f8d79198SJustin Bogner
275f8d79198SJustin Bogner // Read the function name.
276f8d79198SJustin Bogner Record.Name = *Line++;
277b5794ca9SVedant Kumar if (Error E = Symtab->addFuncName(Record.Name))
27829a21babSMircea Trofin return error(std::move(E));
279f8d79198SJustin Bogner
280f8d79198SJustin Bogner // Read the function hash.
281f8d79198SJustin Bogner if (Line.is_at_end())
282f8d79198SJustin Bogner return error(instrprof_error::truncated);
283f95ca075SJustin Bogner if ((Line++)->getAsInteger(0, Record.Hash))
284ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed,
285ee88b8d6SGulfem Savrun Yeniceri "function hash is not a valid integer");
286f8d79198SJustin Bogner
287f8d79198SJustin Bogner // Read the number of counters.
288f8d79198SJustin Bogner uint64_t NumCounters;
289f8d79198SJustin Bogner if (Line.is_at_end())
290f8d79198SJustin Bogner return error(instrprof_error::truncated);
291f8d79198SJustin Bogner if ((Line++)->getAsInteger(10, NumCounters))
292ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed,
293ee88b8d6SGulfem Savrun Yeniceri "number of counters is not a valid integer");
294b59d7c73SJustin Bogner if (NumCounters == 0)
295ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed, "number of counters is zero");
296f8d79198SJustin Bogner
297f8d79198SJustin Bogner // Read each counter and fill our internal storage with the values.
2986241c2a6SRong Xu Record.Clear();
2993a7d44cbSJustin Bogner Record.Counts.reserve(NumCounters);
300f8d79198SJustin Bogner for (uint64_t I = 0; I < NumCounters; ++I) {
301f8d79198SJustin Bogner if (Line.is_at_end())
302f8d79198SJustin Bogner return error(instrprof_error::truncated);
303f8d79198SJustin Bogner uint64_t Count;
304f8d79198SJustin Bogner if ((Line++)->getAsInteger(10, Count))
305ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed, "count is invalid");
3063a7d44cbSJustin Bogner Record.Counts.push_back(Count);
307f8d79198SJustin Bogner }
308f8d79198SJustin Bogner
309e3bf4fd3SXinliang David Li // Check if value profile data exists and read it if so.
3109152fd17SVedant Kumar if (Error E = readValueProfileData(Record))
31129a21babSMircea Trofin return error(std::move(E));
312e3bf4fd3SXinliang David Li
313f8d79198SJustin Bogner return success();
314f8d79198SJustin Bogner }
31524b4b653SDuncan P. N. Exon Smith
3164680361dSDuncan P. N. Exon Smith template <class IntPtrT>
getProfileKind() const317186dcd4aSSnehasish Kumar InstrProfKind RawInstrProfReader<IntPtrT>::getProfileKind() const {
318186dcd4aSSnehasish Kumar return getProfileKindFromVersion(Version);
319186dcd4aSSnehasish Kumar }
320186dcd4aSSnehasish Kumar
321186dcd4aSSnehasish Kumar template <class IntPtrT>
hasFormat(const MemoryBuffer & DataBuffer)3224680361dSDuncan P. N. Exon Smith bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
323d7d83477SDuncan P. N. Exon Smith if (DataBuffer.getBufferSize() < sizeof(uint64_t))
3244680361dSDuncan P. N. Exon Smith return false;
325d7d83477SDuncan P. N. Exon Smith uint64_t Magic =
326d7d83477SDuncan P. N. Exon Smith *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
327dab183edSXinliang David Li return RawInstrProf::getMagic<IntPtrT>() == Magic ||
328dab183edSXinliang David Li sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic;
3294680361dSDuncan P. N. Exon Smith }
3304680361dSDuncan P. N. Exon Smith
3314680361dSDuncan P. N. Exon Smith template <class IntPtrT>
readHeader()3329152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readHeader() {
33309a67f45SDuncan P. N. Exon Smith if (!hasFormat(*DataBuffer))
33409a67f45SDuncan P. N. Exon Smith return error(instrprof_error::bad_magic);
335dab183edSXinliang David Li if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
336531bb481SDuncan P. N. Exon Smith return error(instrprof_error::bad_header);
337dab183edSXinliang David Li auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
338dab183edSXinliang David Li DataBuffer->getBufferStart());
339dab183edSXinliang David Li ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
34024b4b653SDuncan P. N. Exon Smith return readHeader(*Header);
34124b4b653SDuncan P. N. Exon Smith }
34224b4b653SDuncan P. N. Exon Smith
343a119f323SJustin Bogner template <class IntPtrT>
readNextHeader(const char * CurrentPos)3449152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
345a119f323SJustin Bogner const char *End = DataBuffer->getBufferEnd();
346a119f323SJustin Bogner // Skip zero padding between profiles.
347a119f323SJustin Bogner while (CurrentPos != End && *CurrentPos == 0)
348a119f323SJustin Bogner ++CurrentPos;
349a119f323SJustin Bogner // If there's nothing left, we're done.
350a119f323SJustin Bogner if (CurrentPos == End)
3519152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::eof);
352a119f323SJustin Bogner // If there isn't enough space for another header, this is probably just
353a119f323SJustin Bogner // garbage at the end of the file.
354dab183edSXinliang David Li if (CurrentPos + sizeof(RawInstrProf::Header) > End)
355ee88b8d6SGulfem Savrun Yeniceri return make_error<InstrProfError>(instrprof_error::malformed,
356ee88b8d6SGulfem Savrun Yeniceri "not enough space for another header");
35754b11282SJustin Bogner // The writer ensures each profile is padded to start at an aligned address.
358b2505005SBenjamin Kramer if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
359ee88b8d6SGulfem Savrun Yeniceri return make_error<InstrProfError>(instrprof_error::malformed,
360ee88b8d6SGulfem Savrun Yeniceri "insufficient padding");
361a119f323SJustin Bogner // The magic should have the same byte order as in the previous header.
362a119f323SJustin Bogner uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
363dab183edSXinliang David Li if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
3649152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::bad_magic);
365a119f323SJustin Bogner
366a119f323SJustin Bogner // There's another profile to read, so we need to process the header.
367dab183edSXinliang David Li auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
368a119f323SJustin Bogner return readHeader(*Header);
369a119f323SJustin Bogner }
370a119f323SJustin Bogner
3714680361dSDuncan P. N. Exon Smith template <class IntPtrT>
createSymtab(InstrProfSymtab & Symtab)3729152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
37365d7fd02SEllis Hoag if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart)))
3749152fd17SVedant Kumar return error(std::move(E));
375a716cc5cSXinliang David Li for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
376a716cc5cSXinliang David Li const IntPtrT FPtr = swap(I->FunctionPointer);
377a716cc5cSXinliang David Li if (!FPtr)
378a716cc5cSXinliang David Li continue;
379a82d6c0aSXinliang David Li Symtab.mapAddress(FPtr, I->NameRef);
380a716cc5cSXinliang David Li }
381e44482feSVedant Kumar return success();
382a716cc5cSXinliang David Li }
383a716cc5cSXinliang David Li
384a716cc5cSXinliang David Li template <class IntPtrT>
readHeader(const RawInstrProf::Header & Header)3859152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readHeader(
3869152fd17SVedant Kumar const RawInstrProf::Header &Header) {
38733c76c0cSRong Xu Version = swap(Header.Version);
38833c76c0cSRong Xu if (GET_VERSION(Version) != RawInstrProf::Version)
38924b4b653SDuncan P. N. Exon Smith return error(instrprof_error::unsupported_version);
39065d7fd02SEllis Hoag if (useDebugInfoCorrelate() && !Correlator)
39165d7fd02SEllis Hoag return error(instrprof_error::missing_debug_info_for_correlation);
39265d7fd02SEllis Hoag if (!useDebugInfoCorrelate() && Correlator)
39365d7fd02SEllis Hoag return error(instrprof_error::unexpected_debug_info_for_correlation);
39424b4b653SDuncan P. N. Exon Smith
39583302c84SPetr Hosek BinaryIdsSize = swap(Header.BinaryIdsSize);
396b9f547e8SLeonard Chan if (BinaryIdsSize % sizeof(uint64_t))
397b9f547e8SLeonard Chan return error(instrprof_error::bad_header);
398b9f547e8SLeonard Chan
39924b4b653SDuncan P. N. Exon Smith CountersDelta = swap(Header.CountersDelta);
40024b4b653SDuncan P. N. Exon Smith NamesDelta = swap(Header.NamesDelta);
40188d81770SEllis Hoag auto NumData = swap(Header.DataSize);
402d889d1efSVedant Kumar auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
40388d81770SEllis Hoag auto CountersSize = swap(Header.CountersSize) * getCounterTypeSize();
404d889d1efSVedant Kumar auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
40565d7fd02SEllis Hoag auto NamesSize = swap(Header.NamesSize);
4066fac1741SBetul Buyukkurt ValueKindLast = swap(Header.ValueKindLast);
4076fac1741SBetul Buyukkurt
408f2147375SEllis Hoag auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
4096fac1741SBetul Buyukkurt auto PaddingSize = getNumPaddingBytes(NamesSize);
41024b4b653SDuncan P. N. Exon Smith
411e50a3884SGulfem Savrun Yeniceri // Profile data starts after profile header and binary ids if exist.
412e50a3884SGulfem Savrun Yeniceri ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdsSize;
413f2147375SEllis Hoag ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
414f2147375SEllis Hoag ptrdiff_t NamesOffset =
415f2147375SEllis Hoag CountersOffset + CountersSize + PaddingBytesAfterCounters;
4166fac1741SBetul Buyukkurt ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
41724b4b653SDuncan P. N. Exon Smith
418a119f323SJustin Bogner auto *Start = reinterpret_cast<const char *>(&Header);
419188a7c5fSXinliang David Li if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
420531bb481SDuncan P. N. Exon Smith return error(instrprof_error::bad_header);
42124b4b653SDuncan P. N. Exon Smith
42265d7fd02SEllis Hoag if (Correlator) {
42365d7fd02SEllis Hoag // These sizes in the raw file are zero because we constructed them in the
42465d7fd02SEllis Hoag // Correlator.
42565d7fd02SEllis Hoag assert(DataSize == 0 && NamesSize == 0);
42665d7fd02SEllis Hoag assert(CountersDelta == 0 && NamesDelta == 0);
42765d7fd02SEllis Hoag Data = Correlator->getDataPointer();
42865d7fd02SEllis Hoag DataEnd = Data + Correlator->getDataSize();
429f1705952SEllis Hoag NamesStart = Correlator->getNamesPointer();
430f1705952SEllis Hoag NamesEnd = NamesStart + Correlator->getNamesSize();
43165d7fd02SEllis Hoag } else {
432dab183edSXinliang David Li Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
433dab183edSXinliang David Li Start + DataOffset);
434f2147375SEllis Hoag DataEnd = Data + NumData;
43565d7fd02SEllis Hoag NamesStart = Start + NamesOffset;
43665d7fd02SEllis Hoag NamesEnd = NamesStart + NamesSize;
43765d7fd02SEllis Hoag }
438e50a3884SGulfem Savrun Yeniceri
439e50a3884SGulfem Savrun Yeniceri // Binary ids start just after the header.
440e50a3884SGulfem Savrun Yeniceri BinaryIdsStart =
441e50a3884SGulfem Savrun Yeniceri reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
442f2147375SEllis Hoag CountersStart = Start + CountersOffset;
443f2147375SEllis Hoag CountersEnd = CountersStart + CountersSize;
4446fac1741SBetul Buyukkurt ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
44524b4b653SDuncan P. N. Exon Smith
446b9f547e8SLeonard Chan const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
447b9f547e8SLeonard Chan if (BinaryIdsStart + BinaryIdsSize > BufferEnd)
448b9f547e8SLeonard Chan return error(instrprof_error::bad_header);
449b9f547e8SLeonard Chan
4500eaee545SJonas Devlieghere std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
45114415a3aSKazu Hirata if (Error E = createSymtab(*NewSymtab))
4529152fd17SVedant Kumar return E;
453e44482feSVedant Kumar
454a716cc5cSXinliang David Li Symtab = std::move(NewSymtab);
45524b4b653SDuncan P. N. Exon Smith return success();
45624b4b653SDuncan P. N. Exon Smith }
45724b4b653SDuncan P. N. Exon Smith
4584680361dSDuncan P. N. Exon Smith template <class IntPtrT>
readName(NamedInstrProfRecord & Record)459cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
460a82d6c0aSXinliang David Li Record.Name = getName(Data->NameRef);
461cf4a128cSXinliang David Li return success();
462cf4a128cSXinliang David Li }
463cf4a128cSXinliang David Li
464cf4a128cSXinliang David Li template <class IntPtrT>
readFuncHash(NamedInstrProfRecord & Record)465cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
466cf4a128cSXinliang David Li Record.Hash = swap(Data->FuncHash);
467cf4a128cSXinliang David Li return success();
468cf4a128cSXinliang David Li }
469cf4a128cSXinliang David Li
470cf4a128cSXinliang David Li template <class IntPtrT>
readRawCounts(InstrProfRecord & Record)4719152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readRawCounts(
472cf4a128cSXinliang David Li InstrProfRecord &Record) {
473b59d7c73SJustin Bogner uint32_t NumCounters = swap(Data->NumCounters);
474b59d7c73SJustin Bogner if (NumCounters == 0)
475ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed, "number of counters is zero");
476cf4a128cSXinliang David Li
477f2147375SEllis Hoag ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
478f2147375SEllis Hoag if (CounterBaseOffset < 0)
479ee88b8d6SGulfem Savrun Yeniceri return error(
480ee88b8d6SGulfem Savrun Yeniceri instrprof_error::malformed,
481f2147375SEllis Hoag ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
482ee88b8d6SGulfem Savrun Yeniceri
483f2147375SEllis Hoag if (CounterBaseOffset >= CountersEnd - CountersStart)
48465d7fd02SEllis Hoag return error(instrprof_error::malformed,
485f2147375SEllis Hoag ("counter offset " + Twine(CounterBaseOffset) +
486f2147375SEllis Hoag " is greater than the maximum counter offset " +
487f2147375SEllis Hoag Twine(CountersEnd - CountersStart - 1))
488ee88b8d6SGulfem Savrun Yeniceri .str());
489ee88b8d6SGulfem Savrun Yeniceri
490f2147375SEllis Hoag uint64_t MaxNumCounters =
491f2147375SEllis Hoag (CountersEnd - (CountersStart + CounterBaseOffset)) /
492f2147375SEllis Hoag getCounterTypeSize();
493f2147375SEllis Hoag if (NumCounters > MaxNumCounters)
494ee88b8d6SGulfem Savrun Yeniceri return error(instrprof_error::malformed,
495f2147375SEllis Hoag ("number of counters " + Twine(NumCounters) +
496126e7611SGulfem Savrun Yeniceri " is greater than the maximum number of counters " +
497f2147375SEllis Hoag Twine(MaxNumCounters))
498ee88b8d6SGulfem Savrun Yeniceri .str());
49995fb23abSVedant Kumar
5003a7d44cbSJustin Bogner Record.Counts.clear();
501f2147375SEllis Hoag Record.Counts.reserve(NumCounters);
502f2147375SEllis Hoag for (uint32_t I = 0; I < NumCounters; I++) {
50311d30742SEllis Hoag const char *Ptr =
50411d30742SEllis Hoag CountersStart + CounterBaseOffset + I * getCounterTypeSize();
50511d30742SEllis Hoag if (hasSingleByteCoverage()) {
50611d30742SEllis Hoag // A value of zero signifies the block is covered.
50711d30742SEllis Hoag Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
50811d30742SEllis Hoag } else {
50911d30742SEllis Hoag const auto *CounterValue = reinterpret_cast<const uint64_t *>(Ptr);
510f2147375SEllis Hoag Record.Counts.push_back(swap(*CounterValue));
511f2147375SEllis Hoag }
51211d30742SEllis Hoag }
51324b4b653SDuncan P. N. Exon Smith
514cf4a128cSXinliang David Li return success();
515cf4a128cSXinliang David Li }
516cf4a128cSXinliang David Li
517cf4a128cSXinliang David Li template <class IntPtrT>
readValueProfilingData(InstrProfRecord & Record)5189152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
5199152fd17SVedant Kumar InstrProfRecord &Record) {
5206fac1741SBetul Buyukkurt Record.clearValueData();
521d922c26cSXinliang David Li CurValueDataSize = 0;
522d922c26cSXinliang David Li // Need to match the logic in value profile dumper code in compiler-rt:
523d922c26cSXinliang David Li uint32_t NumValueKinds = 0;
524d922c26cSXinliang David Li for (uint32_t I = 0; I < IPVK_Last + 1; I++)
525d922c26cSXinliang David Li NumValueKinds += (Data->NumValueSites[I] != 0);
526d922c26cSXinliang David Li
527d922c26cSXinliang David Li if (!NumValueKinds)
5286fac1741SBetul Buyukkurt return success();
5296fac1741SBetul Buyukkurt
5309152fd17SVedant Kumar Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
531188a7c5fSXinliang David Li ValueProfData::getValueProfData(
532188a7c5fSXinliang David Li ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
53301cb9bd7SXinliang David Li getDataEndianness());
5346fac1741SBetul Buyukkurt
5359152fd17SVedant Kumar if (Error E = VDataPtrOrErr.takeError())
5369152fd17SVedant Kumar return E;
5376fac1741SBetul Buyukkurt
5382f36f059SAdam Nemet // Note that besides deserialization, this also performs the conversion for
5392f36f059SAdam Nemet // indirect call targets. The function pointers from the raw profile are
5402f36f059SAdam Nemet // remapped into function name hashes.
541556f8f6aSMircea Trofin VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
542d922c26cSXinliang David Li CurValueDataSize = VDataPtrOrErr.get()->getSize();
5436fac1741SBetul Buyukkurt return success();
5446fac1741SBetul Buyukkurt }
5456fac1741SBetul Buyukkurt
5466fac1741SBetul Buyukkurt template <class IntPtrT>
readNextRecord(NamedInstrProfRecord & Record)547cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
548cf4a128cSXinliang David Li if (atEnd())
549188a7c5fSXinliang David Li // At this point, ValueDataStart field points to the next header.
5509152fd17SVedant Kumar if (Error E = readNextHeader(getNextHeaderPos()))
5515b63803dSMircea Trofin return error(std::move(E));
552cf4a128cSXinliang David Li
553cf4a128cSXinliang David Li // Read name ad set it in Record.
5549152fd17SVedant Kumar if (Error E = readName(Record))
5555b63803dSMircea Trofin return error(std::move(E));
556cf4a128cSXinliang David Li
557cf4a128cSXinliang David Li // Read FuncHash and set it in Record.
5589152fd17SVedant Kumar if (Error E = readFuncHash(Record))
5595b63803dSMircea Trofin return error(std::move(E));
560cf4a128cSXinliang David Li
561cf4a128cSXinliang David Li // Read raw counts and set Record.
5629152fd17SVedant Kumar if (Error E = readRawCounts(Record))
5635b63803dSMircea Trofin return error(std::move(E));
564cf4a128cSXinliang David Li
5656fac1741SBetul Buyukkurt // Read value data and set Record.
5669152fd17SVedant Kumar if (Error E = readValueProfilingData(Record))
5675b63803dSMircea Trofin return error(std::move(E));
5686fac1741SBetul Buyukkurt
56924b4b653SDuncan P. N. Exon Smith // Iterate.
570cf4a128cSXinliang David Li advanceData();
57124b4b653SDuncan P. N. Exon Smith return success();
57224b4b653SDuncan P. N. Exon Smith }
5734680361dSDuncan P. N. Exon Smith
RoundUp(size_t size,size_t align)574b9f547e8SLeonard Chan static size_t RoundUp(size_t size, size_t align) {
575b9f547e8SLeonard Chan return (size + align - 1) & ~(align - 1);
576b9f547e8SLeonard Chan }
577b9f547e8SLeonard Chan
578e50a3884SGulfem Savrun Yeniceri template <class IntPtrT>
printBinaryIds(raw_ostream & OS)579e50a3884SGulfem Savrun Yeniceri Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
580e50a3884SGulfem Savrun Yeniceri if (BinaryIdsSize == 0)
581e50a3884SGulfem Savrun Yeniceri return success();
582e50a3884SGulfem Savrun Yeniceri
583e50a3884SGulfem Savrun Yeniceri OS << "Binary IDs: \n";
584e50a3884SGulfem Savrun Yeniceri const uint8_t *BI = BinaryIdsStart;
585b9f547e8SLeonard Chan const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
586b9f547e8SLeonard Chan while (BI < BIEnd) {
587b9f547e8SLeonard Chan size_t Remaining = BIEnd - BI;
588b9f547e8SLeonard Chan
589b9f547e8SLeonard Chan // There should be enough left to read the binary ID size field.
590b9f547e8SLeonard Chan if (Remaining < sizeof(uint64_t))
591ee88b8d6SGulfem Savrun Yeniceri return make_error<InstrProfError>(
592ee88b8d6SGulfem Savrun Yeniceri instrprof_error::malformed,
593ee88b8d6SGulfem Savrun Yeniceri "not enough data to read binary id length");
594b9f547e8SLeonard Chan
595e50a3884SGulfem Savrun Yeniceri uint64_t BinaryIdLen = swap(*reinterpret_cast<const uint64_t *>(BI));
596b9f547e8SLeonard Chan
597b9f547e8SLeonard Chan // There should be enough left to read the binary ID size field, and the
598b9f547e8SLeonard Chan // binary ID.
599b9f547e8SLeonard Chan if (Remaining < sizeof(BinaryIdLen) + BinaryIdLen)
600ee88b8d6SGulfem Savrun Yeniceri return make_error<InstrProfError>(
601ee88b8d6SGulfem Savrun Yeniceri instrprof_error::malformed, "not enough data to read binary id data");
602b9f547e8SLeonard Chan
603e50a3884SGulfem Savrun Yeniceri // Increment by binary id length data type size.
604e50a3884SGulfem Savrun Yeniceri BI += sizeof(BinaryIdLen);
605e50a3884SGulfem Savrun Yeniceri if (BI > (const uint8_t *)DataBuffer->getBufferEnd())
606ee88b8d6SGulfem Savrun Yeniceri return make_error<InstrProfError>(
607ee88b8d6SGulfem Savrun Yeniceri instrprof_error::malformed,
608ee88b8d6SGulfem Savrun Yeniceri "binary id that is read is bigger than buffer size");
609e50a3884SGulfem Savrun Yeniceri
610e50a3884SGulfem Savrun Yeniceri for (uint64_t I = 0; I < BinaryIdLen; I++)
611e50a3884SGulfem Savrun Yeniceri OS << format("%02x", BI[I]);
612e50a3884SGulfem Savrun Yeniceri OS << "\n";
613e50a3884SGulfem Savrun Yeniceri
614b9f547e8SLeonard Chan // Increment by binary id data length, rounded to the next 8 bytes. This
615b9f547e8SLeonard Chan // accounts for the zero-padding after each build ID.
616b9f547e8SLeonard Chan BI += RoundUp(BinaryIdLen, sizeof(uint64_t));
617e50a3884SGulfem Savrun Yeniceri if (BI > (const uint8_t *)DataBuffer->getBufferEnd())
618e50a3884SGulfem Savrun Yeniceri return make_error<InstrProfError>(instrprof_error::malformed);
619e50a3884SGulfem Savrun Yeniceri }
620e50a3884SGulfem Savrun Yeniceri
621e50a3884SGulfem Savrun Yeniceri return success();
622e50a3884SGulfem Savrun Yeniceri }
623e50a3884SGulfem Savrun Yeniceri
6244680361dSDuncan P. N. Exon Smith namespace llvm {
625e78d131aSEugene Zelenko
6264680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint32_t>;
6274680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint64_t>;
628e78d131aSEugene Zelenko
629e78d131aSEugene Zelenko } // end namespace llvm
630b7aa2630SJustin Bogner
631b5d368e8SJustin Bogner InstrProfLookupTrait::hash_value_type
ComputeHash(StringRef K)632b5d368e8SJustin Bogner InstrProfLookupTrait::ComputeHash(StringRef K) {
633b5d368e8SJustin Bogner return IndexedInstrProf::ComputeHash(HashType, K);
634b5d368e8SJustin Bogner }
635b5d368e8SJustin Bogner
63672208a82SEugene Zelenko using data_type = InstrProfLookupTrait::data_type;
63772208a82SEugene Zelenko using offset_type = InstrProfLookupTrait::offset_type;
6383a7d44cbSJustin Bogner
readValueProfilingData(const unsigned char * & D,const unsigned char * const End)639be969c29SXinliang David Li bool InstrProfLookupTrait::readValueProfilingData(
6409e9a057aSJustin Bogner const unsigned char *&D, const unsigned char *const End) {
6419152fd17SVedant Kumar Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
64299556877SXinliang David Li ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
6439e9a057aSJustin Bogner
6449152fd17SVedant Kumar if (VDataPtrOrErr.takeError())
6459e9a057aSJustin Bogner return false;
6462004f003SXinliang David Li
647a716cc5cSXinliang David Li VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
648ee415895SXinliang David Li D += VDataPtrOrErr.get()->TotalSize;
6499e9a057aSJustin Bogner
6509e9a057aSJustin Bogner return true;
6519e9a057aSJustin Bogner }
6529e9a057aSJustin Bogner
ReadData(StringRef K,const unsigned char * D,offset_type N)6533a7d44cbSJustin Bogner data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
6543a7d44cbSJustin Bogner offset_type N) {
655e78d131aSEugene Zelenko using namespace support;
656e78d131aSEugene Zelenko
6573a7d44cbSJustin Bogner // Check if the data is corrupt. If so, don't try to read it.
6583a7d44cbSJustin Bogner if (N % sizeof(uint64_t))
6593a7d44cbSJustin Bogner return data_type();
6603a7d44cbSJustin Bogner
6613a7d44cbSJustin Bogner DataBuffer.clear();
6623a7d44cbSJustin Bogner std::vector<uint64_t> CounterBuffer;
6639e9a057aSJustin Bogner
6649e9a057aSJustin Bogner const unsigned char *End = D + N;
6659e9a057aSJustin Bogner while (D < End) {
666c758387eSXinliang David Li // Read hash.
6679e9a057aSJustin Bogner if (D + sizeof(uint64_t) >= End)
6689e9a057aSJustin Bogner return data_type();
6693a7d44cbSJustin Bogner uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
6703a7d44cbSJustin Bogner
67133c76c0cSRong Xu // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
6729e9a057aSJustin Bogner uint64_t CountsSize = N / sizeof(uint64_t) - 1;
673c758387eSXinliang David Li // If format version is different then read the number of counters.
67433c76c0cSRong Xu if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
6759e9a057aSJustin Bogner if (D + sizeof(uint64_t) > End)
6763a7d44cbSJustin Bogner return data_type();
6779e9a057aSJustin Bogner CountsSize = endian::readNext<uint64_t, little, unaligned>(D);
6789e9a057aSJustin Bogner }
679c758387eSXinliang David Li // Read counter values.
6809e9a057aSJustin Bogner if (D + CountsSize * sizeof(uint64_t) > End)
6813a7d44cbSJustin Bogner return data_type();
6823a7d44cbSJustin Bogner
6833a7d44cbSJustin Bogner CounterBuffer.clear();
6849e9a057aSJustin Bogner CounterBuffer.reserve(CountsSize);
6859e9a057aSJustin Bogner for (uint64_t J = 0; J < CountsSize; ++J)
6863a7d44cbSJustin Bogner CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
6873a7d44cbSJustin Bogner
6882004f003SXinliang David Li DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
6899e9a057aSJustin Bogner
690c758387eSXinliang David Li // Read value profiling data.
69133c76c0cSRong Xu if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
692a6b2c4f7SXinliang David Li !readValueProfilingData(D, End)) {
6939e9a057aSJustin Bogner DataBuffer.clear();
6949e9a057aSJustin Bogner return data_type();
6959e9a057aSJustin Bogner }
6963a7d44cbSJustin Bogner }
6973a7d44cbSJustin Bogner return DataBuffer;
6983a7d44cbSJustin Bogner }
6993a7d44cbSJustin Bogner
700a28306dbSXinliang David Li template <typename HashTableImpl>
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)7019152fd17SVedant Kumar Error InstrProfReaderIndex<HashTableImpl>::getRecords(
702cf9d52c6SDavid Blaikie StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) {
703a28306dbSXinliang David Li auto Iter = HashTable->find(FuncName);
704a28306dbSXinliang David Li if (Iter == HashTable->end())
7059152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::unknown_function);
706140f4c4fSXinliang David Li
707140f4c4fSXinliang David Li Data = (*Iter);
7084c3ab815SXinliang David Li if (Data.empty())
709ee88b8d6SGulfem Savrun Yeniceri return make_error<InstrProfError>(instrprof_error::malformed,
710ee88b8d6SGulfem Savrun Yeniceri "profile data is empty");
711140f4c4fSXinliang David Li
7129152fd17SVedant Kumar return Error::success();
713140f4c4fSXinliang David Li }
714140f4c4fSXinliang David Li
715a28306dbSXinliang David Li template <typename HashTableImpl>
getRecords(ArrayRef<NamedInstrProfRecord> & Data)7169152fd17SVedant Kumar Error InstrProfReaderIndex<HashTableImpl>::getRecords(
717cf9d52c6SDavid Blaikie ArrayRef<NamedInstrProfRecord> &Data) {
718a28306dbSXinliang David Li if (atEnd())
7199152fd17SVedant Kumar return make_error<InstrProfError>(instrprof_error::eof);
720140f4c4fSXinliang David Li
721140f4c4fSXinliang David Li Data = *RecordIterator;
722140f4c4fSXinliang David Li
7232d4803e8SXinliang David Li if (Data.empty())
724ee88b8d6SGulfem Savrun Yeniceri return make_error<InstrProfError>(instrprof_error::malformed,
725ee88b8d6SGulfem Savrun Yeniceri "profile data is empty");
726140f4c4fSXinliang David Li
7279152fd17SVedant Kumar return Error::success();
728140f4c4fSXinliang David Li }
729140f4c4fSXinliang David Li
730a28306dbSXinliang David Li template <typename HashTableImpl>
InstrProfReaderIndex(const unsigned char * Buckets,const unsigned char * const Payload,const unsigned char * const Base,IndexedInstrProf::HashT HashType,uint64_t Version)731a28306dbSXinliang David Li InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
732a28306dbSXinliang David Li const unsigned char *Buckets, const unsigned char *const Payload,
733a28306dbSXinliang David Li const unsigned char *const Base, IndexedInstrProf::HashT HashType,
734140f4c4fSXinliang David Li uint64_t Version) {
735140f4c4fSXinliang David Li FormatVersion = Version;
736a28306dbSXinliang David Li HashTable.reset(HashTableImpl::Create(
737a28306dbSXinliang David Li Buckets, Payload, Base,
738a28306dbSXinliang David Li typename HashTableImpl::InfoType(HashType, Version)));
739a28306dbSXinliang David Li RecordIterator = HashTable->data_begin();
740140f4c4fSXinliang David Li }
741140f4c4fSXinliang David Li
742186dcd4aSSnehasish Kumar template <typename HashTableImpl>
getProfileKind() const743186dcd4aSSnehasish Kumar InstrProfKind InstrProfReaderIndex<HashTableImpl>::getProfileKind() const {
744186dcd4aSSnehasish Kumar return getProfileKindFromVersion(FormatVersion);
745186dcd4aSSnehasish Kumar }
746186dcd4aSSnehasish Kumar
747ceed4eb1SRichard Smith namespace {
748ceed4eb1SRichard Smith /// A remapper that does not apply any remappings.
749ceed4eb1SRichard Smith class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
750ceed4eb1SRichard Smith InstrProfReaderIndexBase &Underlying;
751ceed4eb1SRichard Smith
752ceed4eb1SRichard Smith public:
InstrProfReaderNullRemapper(InstrProfReaderIndexBase & Underlying)753ceed4eb1SRichard Smith InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
754ceed4eb1SRichard Smith : Underlying(Underlying) {}
755ceed4eb1SRichard Smith
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)756ceed4eb1SRichard Smith Error getRecords(StringRef FuncName,
757ceed4eb1SRichard Smith ArrayRef<NamedInstrProfRecord> &Data) override {
758ceed4eb1SRichard Smith return Underlying.getRecords(FuncName, Data);
759ceed4eb1SRichard Smith }
760ceed4eb1SRichard Smith };
761ee88b8d6SGulfem Savrun Yeniceri } // namespace
762ceed4eb1SRichard Smith
763ceed4eb1SRichard Smith /// A remapper that applies remappings based on a symbol remapping file.
764ceed4eb1SRichard Smith template <typename HashTableImpl>
765ceed4eb1SRichard Smith class llvm::InstrProfReaderItaniumRemapper
766ceed4eb1SRichard Smith : public InstrProfReaderRemapper {
767ceed4eb1SRichard Smith public:
InstrProfReaderItaniumRemapper(std::unique_ptr<MemoryBuffer> RemapBuffer,InstrProfReaderIndex<HashTableImpl> & Underlying)768ceed4eb1SRichard Smith InstrProfReaderItaniumRemapper(
769ceed4eb1SRichard Smith std::unique_ptr<MemoryBuffer> RemapBuffer,
770ceed4eb1SRichard Smith InstrProfReaderIndex<HashTableImpl> &Underlying)
771ceed4eb1SRichard Smith : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
772ceed4eb1SRichard Smith }
773ceed4eb1SRichard Smith
774ceed4eb1SRichard Smith /// Extract the original function name from a PGO function name.
extractName(StringRef Name)775ceed4eb1SRichard Smith static StringRef extractName(StringRef Name) {
776ceed4eb1SRichard Smith // We can have multiple :-separated pieces; there can be pieces both
777ceed4eb1SRichard Smith // before and after the mangled name. Find the first part that starts
778ceed4eb1SRichard Smith // with '_Z'; we'll assume that's the mangled name we want.
779ceed4eb1SRichard Smith std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
780ceed4eb1SRichard Smith while (true) {
781ceed4eb1SRichard Smith Parts = Parts.second.split(':');
782ceed4eb1SRichard Smith if (Parts.first.startswith("_Z"))
783ceed4eb1SRichard Smith return Parts.first;
784ceed4eb1SRichard Smith if (Parts.second.empty())
785ceed4eb1SRichard Smith return Name;
786ceed4eb1SRichard Smith }
787ceed4eb1SRichard Smith }
788ceed4eb1SRichard Smith
789ceed4eb1SRichard Smith /// Given a mangled name extracted from a PGO function name, and a new
790ceed4eb1SRichard Smith /// form for that mangled name, reconstitute the name.
reconstituteName(StringRef OrigName,StringRef ExtractedName,StringRef Replacement,SmallVectorImpl<char> & Out)791ceed4eb1SRichard Smith static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
792ceed4eb1SRichard Smith StringRef Replacement,
793ceed4eb1SRichard Smith SmallVectorImpl<char> &Out) {
794ceed4eb1SRichard Smith Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
795ceed4eb1SRichard Smith Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
796ceed4eb1SRichard Smith Out.insert(Out.end(), Replacement.begin(), Replacement.end());
797ceed4eb1SRichard Smith Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
798ceed4eb1SRichard Smith }
799ceed4eb1SRichard Smith
populateRemappings()800ceed4eb1SRichard Smith Error populateRemappings() override {
801ceed4eb1SRichard Smith if (Error E = Remappings.read(*RemapBuffer))
802ceed4eb1SRichard Smith return E;
803ceed4eb1SRichard Smith for (StringRef Name : Underlying.HashTable->keys()) {
804ceed4eb1SRichard Smith StringRef RealName = extractName(Name);
805ceed4eb1SRichard Smith if (auto Key = Remappings.insert(RealName)) {
806ceed4eb1SRichard Smith // FIXME: We could theoretically map the same equivalence class to
807ceed4eb1SRichard Smith // multiple names in the profile data. If that happens, we should
808ceed4eb1SRichard Smith // return NamedInstrProfRecords from all of them.
809ceed4eb1SRichard Smith MappedNames.insert({Key, RealName});
810ceed4eb1SRichard Smith }
811ceed4eb1SRichard Smith }
812ceed4eb1SRichard Smith return Error::success();
813ceed4eb1SRichard Smith }
814ceed4eb1SRichard Smith
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)815ceed4eb1SRichard Smith Error getRecords(StringRef FuncName,
816ceed4eb1SRichard Smith ArrayRef<NamedInstrProfRecord> &Data) override {
817ceed4eb1SRichard Smith StringRef RealName = extractName(FuncName);
818ceed4eb1SRichard Smith if (auto Key = Remappings.lookup(RealName)) {
819ceed4eb1SRichard Smith StringRef Remapped = MappedNames.lookup(Key);
820ceed4eb1SRichard Smith if (!Remapped.empty()) {
821ceed4eb1SRichard Smith if (RealName.begin() == FuncName.begin() &&
822ceed4eb1SRichard Smith RealName.end() == FuncName.end())
823ceed4eb1SRichard Smith FuncName = Remapped;
824ceed4eb1SRichard Smith else {
825ceed4eb1SRichard Smith // Try rebuilding the name from the given remapping.
826ceed4eb1SRichard Smith SmallString<256> Reconstituted;
827ceed4eb1SRichard Smith reconstituteName(FuncName, RealName, Remapped, Reconstituted);
828ceed4eb1SRichard Smith Error E = Underlying.getRecords(Reconstituted, Data);
829ceed4eb1SRichard Smith if (!E)
830ceed4eb1SRichard Smith return E;
831ceed4eb1SRichard Smith
832ceed4eb1SRichard Smith // If we failed because the name doesn't exist, fall back to asking
833ceed4eb1SRichard Smith // about the original name.
834ceed4eb1SRichard Smith if (Error Unhandled = handleErrors(
835ceed4eb1SRichard Smith std::move(E), [](std::unique_ptr<InstrProfError> Err) {
836ceed4eb1SRichard Smith return Err->get() == instrprof_error::unknown_function
837ceed4eb1SRichard Smith ? Error::success()
838ceed4eb1SRichard Smith : Error(std::move(Err));
839ceed4eb1SRichard Smith }))
840ceed4eb1SRichard Smith return Unhandled;
841ceed4eb1SRichard Smith }
842ceed4eb1SRichard Smith }
843ceed4eb1SRichard Smith }
844ceed4eb1SRichard Smith return Underlying.getRecords(FuncName, Data);
845ceed4eb1SRichard Smith }
846ceed4eb1SRichard Smith
847ceed4eb1SRichard Smith private:
848ceed4eb1SRichard Smith /// The memory buffer containing the remapping configuration. Remappings
849ceed4eb1SRichard Smith /// holds pointers into this buffer.
850ceed4eb1SRichard Smith std::unique_ptr<MemoryBuffer> RemapBuffer;
851ceed4eb1SRichard Smith
852ceed4eb1SRichard Smith /// The mangling remapper.
853ceed4eb1SRichard Smith SymbolRemappingReader Remappings;
854ceed4eb1SRichard Smith
855ceed4eb1SRichard Smith /// Mapping from mangled name keys to the name used for the key in the
856ceed4eb1SRichard Smith /// profile data.
857ceed4eb1SRichard Smith /// FIXME: Can we store a location within the on-disk hash table instead of
858ceed4eb1SRichard Smith /// redoing lookup?
859ceed4eb1SRichard Smith DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
860ceed4eb1SRichard Smith
861ceed4eb1SRichard Smith /// The real profile data reader.
862ceed4eb1SRichard Smith InstrProfReaderIndex<HashTableImpl> &Underlying;
863ceed4eb1SRichard Smith };
864ceed4eb1SRichard Smith
hasFormat(const MemoryBuffer & DataBuffer)865b7aa2630SJustin Bogner bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
866e78d131aSEugene Zelenko using namespace support;
867e78d131aSEugene Zelenko
8684c3ab815SXinliang David Li if (DataBuffer.getBufferSize() < 8)
8694c3ab815SXinliang David Li return false;
870b7aa2630SJustin Bogner uint64_t Magic =
871b7aa2630SJustin Bogner endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
872c758387eSXinliang David Li // Verify that it's magical.
873b7aa2630SJustin Bogner return Magic == IndexedInstrProf::Magic;
874b7aa2630SJustin Bogner }
875b7aa2630SJustin Bogner
8766c93ee8dSXinliang David Li const unsigned char *
readSummary(IndexedInstrProf::ProfVersion Version,const unsigned char * Cur,bool UseCS)8776c93ee8dSXinliang David Li IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
878a6ff69f6SRong Xu const unsigned char *Cur, bool UseCS) {
879e5a17e3fSEaswaran Raman using namespace IndexedInstrProf;
8806c93ee8dSXinliang David Li using namespace support;
881e78d131aSEugene Zelenko
8826c93ee8dSXinliang David Li if (Version >= IndexedInstrProf::Version4) {
8836c93ee8dSXinliang David Li const IndexedInstrProf::Summary *SummaryInLE =
8846c93ee8dSXinliang David Li reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
8856c93ee8dSXinliang David Li uint64_t NFields =
8866c93ee8dSXinliang David Li endian::byte_swap<uint64_t, little>(SummaryInLE->NumSummaryFields);
8876c93ee8dSXinliang David Li uint64_t NEntries =
8886c93ee8dSXinliang David Li endian::byte_swap<uint64_t, little>(SummaryInLE->NumCutoffEntries);
8896c93ee8dSXinliang David Li uint32_t SummarySize =
8906c93ee8dSXinliang David Li IndexedInstrProf::Summary::getSize(NFields, NEntries);
8916c93ee8dSXinliang David Li std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
8926c93ee8dSXinliang David Li IndexedInstrProf::allocSummary(SummarySize);
8936c93ee8dSXinliang David Li
8946c93ee8dSXinliang David Li const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
8956c93ee8dSXinliang David Li uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
8966c93ee8dSXinliang David Li for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
8976c93ee8dSXinliang David Li Dst[I] = endian::byte_swap<uint64_t, little>(Src[I]);
8986c93ee8dSXinliang David Li
89972208a82SEugene Zelenko SummaryEntryVector DetailedSummary;
900e5a17e3fSEaswaran Raman for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
901e5a17e3fSEaswaran Raman const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
902e5a17e3fSEaswaran Raman DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
903e5a17e3fSEaswaran Raman Ent.NumBlocks);
904e5a17e3fSEaswaran Raman }
905a6ff69f6SRong Xu std::unique_ptr<llvm::ProfileSummary> &Summary =
906a6ff69f6SRong Xu UseCS ? this->CS_Summary : this->Summary;
907a6ff69f6SRong Xu
9084309570dSEaswaran Raman // initialize InstrProfSummary using the SummaryData from disk.
9090eaee545SJonas Devlieghere Summary = std::make_unique<ProfileSummary>(
910a6ff69f6SRong Xu UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr,
911a6ff69f6SRong Xu DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
912e5a17e3fSEaswaran Raman SummaryData->get(Summary::MaxBlockCount),
913e5a17e3fSEaswaran Raman SummaryData->get(Summary::MaxInternalBlockCount),
914e5a17e3fSEaswaran Raman SummaryData->get(Summary::MaxFunctionCount),
915e5a17e3fSEaswaran Raman SummaryData->get(Summary::TotalNumBlocks),
9167cefdb81SEaswaran Raman SummaryData->get(Summary::TotalNumFunctions));
9176c93ee8dSXinliang David Li return Cur + SummarySize;
9186c93ee8dSXinliang David Li } else {
919fd2044f2STeresa Johnson // The older versions do not support a profile summary. This just computes
920fd2044f2STeresa Johnson // an empty summary, which will not result in accurate hot/cold detection.
921fd2044f2STeresa Johnson // We would need to call addRecord for all NamedInstrProfRecords to get the
922fd2044f2STeresa Johnson // correct summary. However, this version is old (prior to early 2016) and
923fd2044f2STeresa Johnson // has not been supporting an accurate summary for several years.
924e5a17e3fSEaswaran Raman InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
925fd2044f2STeresa Johnson Summary = Builder.getSummary();
9266c93ee8dSXinliang David Li return Cur;
9276c93ee8dSXinliang David Li }
9286c93ee8dSXinliang David Li }
9296c93ee8dSXinliang David Li
readHeader()9309152fd17SVedant Kumar Error IndexedInstrProfReader::readHeader() {
931e78d131aSEugene Zelenko using namespace support;
932e78d131aSEugene Zelenko
933a7c9ed57SAaron Ballman const unsigned char *Start =
934a7c9ed57SAaron Ballman (const unsigned char *)DataBuffer->getBufferStart();
935b7aa2630SJustin Bogner const unsigned char *Cur = Start;
936a7c9ed57SAaron Ballman if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
937b7aa2630SJustin Bogner return error(instrprof_error::truncated);
938b7aa2630SJustin Bogner
939a3beb340SSnehasish Kumar auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
940a3beb340SSnehasish Kumar if (!HeaderOr)
941a3beb340SSnehasish Kumar return HeaderOr.takeError();
942dab183edSXinliang David Li
943a3beb340SSnehasish Kumar const IndexedInstrProf::Header *Header = &HeaderOr.get();
944a3beb340SSnehasish Kumar Cur += Header->size();
945b7aa2630SJustin Bogner
946a3beb340SSnehasish Kumar Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
947a6ff69f6SRong Xu /* UseCS */ false);
948a3beb340SSnehasish Kumar if (Header->formatVersion() & VARIANT_MASK_CSIR_PROF)
949a3beb340SSnehasish Kumar Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
950a6ff69f6SRong Xu /* UseCS */ true);
951b7aa2630SJustin Bogner
952b7aa2630SJustin Bogner // Read the hash type and start offset.
953b7aa2630SJustin Bogner IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
954dab183edSXinliang David Li endian::byte_swap<uint64_t, little>(Header->HashType));
955b7aa2630SJustin Bogner if (HashType > IndexedInstrProf::HashT::Last)
956b7aa2630SJustin Bogner return error(instrprof_error::unsupported_hash_type);
957dab183edSXinliang David Li
958dab183edSXinliang David Li uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset);
959b7aa2630SJustin Bogner
9600a418490SSnehasish Kumar // The hash table with profile counts comes next.
961a3beb340SSnehasish Kumar auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
962a3beb340SSnehasish Kumar Start + HashOffset, Cur, Start, HashType, Header->formatVersion());
963ceed4eb1SRichard Smith
9640a418490SSnehasish Kumar // The MemProfOffset field in the header is only valid when the format version
9650a418490SSnehasish Kumar // is higher than 8 (when it was introduced).
9660a418490SSnehasish Kumar if (GET_VERSION(Header->formatVersion()) >= 8 &&
9670a418490SSnehasish Kumar Header->formatVersion() & VARIANT_MASK_MEMPROF) {
9680a418490SSnehasish Kumar uint64_t MemProfOffset =
9690a418490SSnehasish Kumar endian::byte_swap<uint64_t, little>(Header->MemProfOffset);
9700a418490SSnehasish Kumar
9710a418490SSnehasish Kumar const unsigned char *Ptr = Start + MemProfOffset;
9726dd6a616SSnehasish Kumar // The value returned from RecordTableGenerator.Emit.
9736dd6a616SSnehasish Kumar const uint64_t RecordTableOffset =
9746dd6a616SSnehasish Kumar support::endian::readNext<uint64_t, little, unaligned>(Ptr);
9756dd6a616SSnehasish Kumar // The offset in the stream right before invoking FrameTableGenerator.Emit.
9766dd6a616SSnehasish Kumar const uint64_t FramePayloadOffset =
9776dd6a616SSnehasish Kumar support::endian::readNext<uint64_t, little, unaligned>(Ptr);
9786dd6a616SSnehasish Kumar // The value returned from FrameTableGenerator.Emit.
9796dd6a616SSnehasish Kumar const uint64_t FrameTableOffset =
9800a418490SSnehasish Kumar support::endian::readNext<uint64_t, little, unaligned>(Ptr);
9810a418490SSnehasish Kumar
9820a418490SSnehasish Kumar // Read the schema.
9830a418490SSnehasish Kumar auto SchemaOr = memprof::readMemProfSchema(Ptr);
9840a418490SSnehasish Kumar if (!SchemaOr)
9850a418490SSnehasish Kumar return SchemaOr.takeError();
9860a418490SSnehasish Kumar Schema = SchemaOr.get();
9870a418490SSnehasish Kumar
9880a418490SSnehasish Kumar // Now initialize the table reader with a pointer into data buffer.
9896dd6a616SSnehasish Kumar MemProfRecordTable.reset(MemProfRecordHashTable::Create(
9906dd6a616SSnehasish Kumar /*Buckets=*/Start + RecordTableOffset,
9910a418490SSnehasish Kumar /*Payload=*/Ptr,
9926dd6a616SSnehasish Kumar /*Base=*/Start, memprof::RecordLookupTrait(Schema)));
9936dd6a616SSnehasish Kumar
9946dd6a616SSnehasish Kumar // Initialize the frame table reader with the payload and bucket offsets.
9956dd6a616SSnehasish Kumar MemProfFrameTable.reset(MemProfFrameHashTable::Create(
9966dd6a616SSnehasish Kumar /*Buckets=*/Start + FrameTableOffset,
9976dd6a616SSnehasish Kumar /*Payload=*/Start + FramePayloadOffset,
9986dd6a616SSnehasish Kumar /*Base=*/Start, memprof::FrameLookupTrait()));
9990a418490SSnehasish Kumar }
10000a418490SSnehasish Kumar
1001ceed4eb1SRichard Smith // Load the remapping table now if requested.
1002ceed4eb1SRichard Smith if (RemappingBuffer) {
10030eaee545SJonas Devlieghere Remapper = std::make_unique<
1004ceed4eb1SRichard Smith InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
1005ceed4eb1SRichard Smith std::move(RemappingBuffer), *IndexPtr);
1006ceed4eb1SRichard Smith if (Error E = Remapper->populateRemappings())
1007ceed4eb1SRichard Smith return E;
1008ceed4eb1SRichard Smith } else {
10090eaee545SJonas Devlieghere Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
1010ceed4eb1SRichard Smith }
1011ceed4eb1SRichard Smith Index = std::move(IndexPtr);
1012ceed4eb1SRichard Smith
1013b7aa2630SJustin Bogner return success();
1014b7aa2630SJustin Bogner }
1015b7aa2630SJustin Bogner
getSymtab()1016a716cc5cSXinliang David Li InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
101714415a3aSKazu Hirata if (Symtab)
101814415a3aSKazu Hirata return *Symtab;
1019a716cc5cSXinliang David Li
10200eaee545SJonas Devlieghere std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
102114415a3aSKazu Hirata if (Error E = Index->populateSymtab(*NewSymtab)) {
1022b5794ca9SVedant Kumar consumeError(error(InstrProfError::take(std::move(E))));
1023b5794ca9SVedant Kumar }
1024a716cc5cSXinliang David Li
1025a716cc5cSXinliang David Li Symtab = std::move(NewSymtab);
102614415a3aSKazu Hirata return *Symtab;
1027a716cc5cSXinliang David Li }
1028a716cc5cSXinliang David Li
getInstrProfRecord(StringRef FuncName,uint64_t FuncHash,uint64_t * MismatchedFuncSum)1029*5e044329SRong Xu Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(
1030*5e044329SRong Xu StringRef FuncName, uint64_t FuncHash, uint64_t *MismatchedFuncSum) {
1031cf9d52c6SDavid Blaikie ArrayRef<NamedInstrProfRecord> Data;
1032*5e044329SRong Xu uint64_t FuncSum = 0;
1033ceed4eb1SRichard Smith Error Err = Remapper->getRecords(FuncName, Data);
10349152fd17SVedant Kumar if (Err)
1035c55cf4afSBill Wendling return std::move(Err);
1036821d7471SJustin Bogner // Found it. Look for counters with the right hash.
10374a40fa82SRong Xu
10384a40fa82SRong Xu // A flag to indicate if the records are from the same type
10394a40fa82SRong Xu // of profile (i.e cs vs nocs).
10404a40fa82SRong Xu bool CSBitMatch = false;
1041*5e044329SRong Xu auto getFuncSum = [](const std::vector<uint64_t> &Counts) {
1042*5e044329SRong Xu uint64_t ValueSum = 0;
1043*5e044329SRong Xu for (unsigned I = 0, S = Counts.size(); I < S; I++) {
1044*5e044329SRong Xu uint64_t CountValue = Counts[I];
1045*5e044329SRong Xu if (CountValue == (uint64_t)-1)
1046*5e044329SRong Xu continue;
1047*5e044329SRong Xu // Handle overflow -- if that happens, return max.
1048*5e044329SRong Xu if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1049*5e044329SRong Xu return std::numeric_limits<uint64_t>::max();
1050*5e044329SRong Xu ValueSum += CountValue;
1051*5e044329SRong Xu }
1052*5e044329SRong Xu return ValueSum;
1053*5e044329SRong Xu };
10544a40fa82SRong Xu
1055ccdd5bb2SKazu Hirata for (const NamedInstrProfRecord &I : Data) {
1056821d7471SJustin Bogner // Check for a match and fill the vector if there is one.
1057ccdd5bb2SKazu Hirata if (I.Hash == FuncHash)
1058ccdd5bb2SKazu Hirata return std::move(I);
10594a40fa82SRong Xu if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) ==
10604a40fa82SRong Xu NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) {
10614a40fa82SRong Xu CSBitMatch = true;
1062*5e044329SRong Xu if (MismatchedFuncSum == nullptr)
1063*5e044329SRong Xu continue;
1064*5e044329SRong Xu FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
1065821d7471SJustin Bogner }
10664a40fa82SRong Xu }
10674a40fa82SRong Xu if (CSBitMatch) {
1068*5e044329SRong Xu if (MismatchedFuncSum != nullptr)
1069*5e044329SRong Xu *MismatchedFuncSum = FuncSum;
1070821d7471SJustin Bogner return error(instrprof_error::hash_mismatch);
1071821d7471SJustin Bogner }
10724a40fa82SRong Xu return error(instrprof_error::unknown_function);
10734a40fa82SRong Xu }
1074b7aa2630SJustin Bogner
10756dd6a616SSnehasish Kumar Expected<memprof::MemProfRecord>
getMemProfRecord(const uint64_t FuncNameHash)10760a418490SSnehasish Kumar IndexedInstrProfReader::getMemProfRecord(const uint64_t FuncNameHash) {
10770a418490SSnehasish Kumar // TODO: Add memprof specific errors.
10786dd6a616SSnehasish Kumar if (MemProfRecordTable == nullptr)
10790a418490SSnehasish Kumar return make_error<InstrProfError>(instrprof_error::invalid_prof,
10800a418490SSnehasish Kumar "no memprof data available in profile");
10816dd6a616SSnehasish Kumar auto Iter = MemProfRecordTable->find(FuncNameHash);
10826dd6a616SSnehasish Kumar if (Iter == MemProfRecordTable->end())
108365529486STeresa Johnson return make_error<InstrProfError>(
108465529486STeresa Johnson instrprof_error::unknown_function,
108565529486STeresa Johnson "memprof record not found for function hash " + Twine(FuncNameHash));
10866dd6a616SSnehasish Kumar
10876dd6a616SSnehasish Kumar // Setup a callback to convert from frame ids to frame using the on-disk
10886dd6a616SSnehasish Kumar // FrameData hash table.
10896dd6a616SSnehasish Kumar memprof::FrameId LastUnmappedFrameId = 0;
10906dd6a616SSnehasish Kumar bool HasFrameMappingError = false;
10916dd6a616SSnehasish Kumar auto IdToFrameCallback = [&](const memprof::FrameId Id) {
10926dd6a616SSnehasish Kumar auto FrIter = MemProfFrameTable->find(Id);
10936dd6a616SSnehasish Kumar if (FrIter == MemProfFrameTable->end()) {
10946dd6a616SSnehasish Kumar LastUnmappedFrameId = Id;
10956dd6a616SSnehasish Kumar HasFrameMappingError = true;
10966dd6a616SSnehasish Kumar return memprof::Frame(0, 0, 0, false);
10976dd6a616SSnehasish Kumar }
10986dd6a616SSnehasish Kumar return *FrIter;
10996dd6a616SSnehasish Kumar };
11006dd6a616SSnehasish Kumar
11016dd6a616SSnehasish Kumar memprof::MemProfRecord Record(*Iter, IdToFrameCallback);
11026dd6a616SSnehasish Kumar
11036dd6a616SSnehasish Kumar // Check that all frame ids were successfully converted to frames.
11046dd6a616SSnehasish Kumar if (HasFrameMappingError) {
11056dd6a616SSnehasish Kumar return make_error<InstrProfError>(instrprof_error::hash_mismatch,
11066dd6a616SSnehasish Kumar "memprof frame not found for frame id " +
11076dd6a616SSnehasish Kumar Twine(LastUnmappedFrameId));
11086dd6a616SSnehasish Kumar }
11096dd6a616SSnehasish Kumar return Record;
11100a418490SSnehasish Kumar }
11110a418490SSnehasish Kumar
getFunctionCounts(StringRef FuncName,uint64_t FuncHash,std::vector<uint64_t> & Counts)11129152fd17SVedant Kumar Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
11139152fd17SVedant Kumar uint64_t FuncHash,
11146aa216c2SXinliang David Li std::vector<uint64_t> &Counts) {
11159152fd17SVedant Kumar Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
11169152fd17SVedant Kumar if (Error E = Record.takeError())
11179152fd17SVedant Kumar return error(std::move(E));
11182004f003SXinliang David Li
11192004f003SXinliang David Li Counts = Record.get().Counts;
11202004f003SXinliang David Li return success();
11212004f003SXinliang David Li }
11222004f003SXinliang David Li
readNextRecord(NamedInstrProfRecord & Record)1123cf9d52c6SDavid Blaikie Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
1124cf9d52c6SDavid Blaikie ArrayRef<NamedInstrProfRecord> Data;
1125140f4c4fSXinliang David Li
11269152fd17SVedant Kumar Error E = Index->getRecords(Data);
11279152fd17SVedant Kumar if (E)
11289152fd17SVedant Kumar return error(std::move(E));
1129140f4c4fSXinliang David Li
11303a7d44cbSJustin Bogner Record = Data[RecordIndex++];
11313a7d44cbSJustin Bogner if (RecordIndex >= Data.size()) {
1132a28306dbSXinliang David Li Index->advanceToNextKey();
11333a7d44cbSJustin Bogner RecordIndex = 0;
1134821d7471SJustin Bogner }
1135b7aa2630SJustin Bogner return success();
1136b7aa2630SJustin Bogner }
1137998b97f6SRong Xu
accumulateCounts(CountSumOrPercent & Sum,bool IsCS)1138e0fa2689SRong Xu void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) {
1139998b97f6SRong Xu uint64_t NumFuncs = 0;
1140998b97f6SRong Xu for (const auto &Func : *this) {
1141998b97f6SRong Xu if (isIRLevelProfile()) {
1142998b97f6SRong Xu bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
1143998b97f6SRong Xu if (FuncIsCS != IsCS)
1144998b97f6SRong Xu continue;
1145998b97f6SRong Xu }
1146e0fa2689SRong Xu Func.accumulateCounts(Sum);
1147998b97f6SRong Xu ++NumFuncs;
1148998b97f6SRong Xu }
1149998b97f6SRong Xu Sum.NumEntries = NumFuncs;
1150998b97f6SRong Xu }
1151