[mlir][linalg] Add support for masked vectorization of `tensor.insert_slice` (1/N...
[llvm-project.git] / llvm / lib / ProfileData / InstrProfReader.cpp
blobcac1760d3ef80d8cb26f71297345ed7f152bed18
1 //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains support for reading profiling data for clang's
10 // instrumentation based PGO and coverage.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ProfileData/InstrProfReader.h"
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/IR/ProfileSummary.h"
20 #include "llvm/ProfileData/InstrProf.h"
21 #include "llvm/ProfileData/MemProf.h"
22 #include "llvm/ProfileData/ProfileCommon.h"
23 #include "llvm/ProfileData/SymbolRemappingReader.h"
24 #include "llvm/Support/Endian.h"
25 #include "llvm/Support/Error.h"
26 #include "llvm/Support/ErrorOr.h"
27 #include "llvm/Support/FormatVariadic.h"
28 #include "llvm/Support/MemoryBuffer.h"
29 #include "llvm/Support/VirtualFileSystem.h"
30 #include <algorithm>
31 #include <cstddef>
32 #include <cstdint>
33 #include <limits>
34 #include <memory>
35 #include <optional>
36 #include <system_error>
37 #include <utility>
38 #include <vector>
40 using namespace llvm;
42 // Extracts the variant information from the top 32 bits in the version and
43 // returns an enum specifying the variants present.
44 static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
45 InstrProfKind ProfileKind = InstrProfKind::Unknown;
46 if (Version & VARIANT_MASK_IR_PROF) {
47 ProfileKind |= InstrProfKind::IRInstrumentation;
49 if (Version & VARIANT_MASK_CSIR_PROF) {
50 ProfileKind |= InstrProfKind::ContextSensitive;
52 if (Version & VARIANT_MASK_INSTR_ENTRY) {
53 ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
55 if (Version & VARIANT_MASK_INSTR_LOOP_ENTRIES) {
56 ProfileKind |= InstrProfKind::LoopEntriesInstrumentation;
58 if (Version & VARIANT_MASK_BYTE_COVERAGE) {
59 ProfileKind |= InstrProfKind::SingleByteCoverage;
61 if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
62 ProfileKind |= InstrProfKind::FunctionEntryOnly;
64 if (Version & VARIANT_MASK_MEMPROF) {
65 ProfileKind |= InstrProfKind::MemProf;
67 if (Version & VARIANT_MASK_TEMPORAL_PROF) {
68 ProfileKind |= InstrProfKind::TemporalProfile;
70 return ProfileKind;
73 static Expected<std::unique_ptr<MemoryBuffer>>
74 setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) {
75 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
76 : FS.getBufferForFile(Filename);
77 if (std::error_code EC = BufferOrErr.getError())
78 return errorCodeToError(EC);
79 return std::move(BufferOrErr.get());
82 static Error initializeReader(InstrProfReader &Reader) {
83 return Reader.readHeader();
86 /// Read a list of binary ids from a profile that consist of
87 /// a. uint64_t binary id length
88 /// b. uint8_t binary id data
89 /// c. uint8_t padding (if necessary)
90 /// This function is shared between raw and indexed profiles.
91 /// Raw profiles are in host-endian format, and indexed profiles are in
92 /// little-endian format. So, this function takes an argument indicating the
93 /// associated endian format to read the binary ids correctly.
94 static Error
95 readBinaryIdsInternal(const MemoryBuffer &DataBuffer,
96 ArrayRef<uint8_t> BinaryIdsBuffer,
97 std::vector<llvm::object::BuildID> &BinaryIds,
98 const llvm::endianness Endian) {
99 using namespace support;
101 const uint64_t BinaryIdsSize = BinaryIdsBuffer.size();
102 const uint8_t *BinaryIdsStart = BinaryIdsBuffer.data();
104 if (BinaryIdsSize == 0)
105 return Error::success();
107 const uint8_t *BI = BinaryIdsStart;
108 const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
109 const uint8_t *End =
110 reinterpret_cast<const uint8_t *>(DataBuffer.getBufferEnd());
112 while (BI < BIEnd) {
113 size_t Remaining = BIEnd - BI;
114 // There should be enough left to read the binary id length.
115 if (Remaining < sizeof(uint64_t))
116 return make_error<InstrProfError>(
117 instrprof_error::malformed,
118 "not enough data to read binary id length");
120 uint64_t BILen = endian::readNext<uint64_t>(BI, Endian);
121 if (BILen == 0)
122 return make_error<InstrProfError>(instrprof_error::malformed,
123 "binary id length is 0");
125 Remaining = BIEnd - BI;
126 // There should be enough left to read the binary id data.
127 if (Remaining < alignToPowerOf2(BILen, sizeof(uint64_t)))
128 return make_error<InstrProfError>(
129 instrprof_error::malformed, "not enough data to read binary id data");
131 // Add binary id to the binary ids list.
132 BinaryIds.push_back(object::BuildID(BI, BI + BILen));
134 // Increment by binary id data length, which aligned to the size of uint64.
135 BI += alignToPowerOf2(BILen, sizeof(uint64_t));
136 if (BI > End)
137 return make_error<InstrProfError>(
138 instrprof_error::malformed,
139 "binary id section is greater than buffer size");
142 return Error::success();
145 static void printBinaryIdsInternal(raw_ostream &OS,
146 ArrayRef<llvm::object::BuildID> BinaryIds) {
147 OS << "Binary IDs: \n";
148 for (const auto &BI : BinaryIds) {
149 for (auto I : BI)
150 OS << format("%02x", I);
151 OS << "\n";
155 Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
156 const Twine &Path, vfs::FileSystem &FS,
157 const InstrProfCorrelator *Correlator,
158 const object::BuildIDFetcher *BIDFetcher,
159 const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
160 std::function<void(Error)> Warn) {
161 // Set up the buffer to read.
162 auto BufferOrError = setupMemoryBuffer(Path, FS);
163 if (Error E = BufferOrError.takeError())
164 return std::move(E);
165 return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
166 BIDFetcher, BIDFetcherCorrelatorKind, Warn);
169 Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
170 std::unique_ptr<MemoryBuffer> Buffer, const InstrProfCorrelator *Correlator,
171 const object::BuildIDFetcher *BIDFetcher,
172 const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
173 std::function<void(Error)> Warn) {
174 if (Buffer->getBufferSize() == 0)
175 return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
177 std::unique_ptr<InstrProfReader> Result;
178 // Create the reader.
179 if (IndexedInstrProfReader::hasFormat(*Buffer))
180 Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
181 else if (RawInstrProfReader64::hasFormat(*Buffer))
182 Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator,
183 BIDFetcher, BIDFetcherCorrelatorKind,
184 Warn));
185 else if (RawInstrProfReader32::hasFormat(*Buffer))
186 Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator,
187 BIDFetcher, BIDFetcherCorrelatorKind,
188 Warn));
189 else if (TextInstrProfReader::hasFormat(*Buffer))
190 Result.reset(new TextInstrProfReader(std::move(Buffer)));
191 else
192 return make_error<InstrProfError>(instrprof_error::unrecognized_format);
194 // Initialize the reader and return the result.
195 if (Error E = initializeReader(*Result))
196 return std::move(E);
198 return std::move(Result);
201 Expected<std::unique_ptr<IndexedInstrProfReader>>
202 IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
203 const Twine &RemappingPath) {
204 // Set up the buffer to read.
205 auto BufferOrError = setupMemoryBuffer(Path, FS);
206 if (Error E = BufferOrError.takeError())
207 return std::move(E);
209 // Set up the remapping buffer if requested.
210 std::unique_ptr<MemoryBuffer> RemappingBuffer;
211 std::string RemappingPathStr = RemappingPath.str();
212 if (!RemappingPathStr.empty()) {
213 auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS);
214 if (Error E = RemappingBufferOrError.takeError())
215 return std::move(E);
216 RemappingBuffer = std::move(RemappingBufferOrError.get());
219 return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
220 std::move(RemappingBuffer));
223 Expected<std::unique_ptr<IndexedInstrProfReader>>
224 IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
225 std::unique_ptr<MemoryBuffer> RemappingBuffer) {
226 // Create the reader.
227 if (!IndexedInstrProfReader::hasFormat(*Buffer))
228 return make_error<InstrProfError>(instrprof_error::bad_magic);
229 auto Result = std::make_unique<IndexedInstrProfReader>(
230 std::move(Buffer), std::move(RemappingBuffer));
232 // Initialize the reader and return the result.
233 if (Error E = initializeReader(*Result))
234 return std::move(E);
236 return std::move(Result);
239 bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
240 // Verify that this really looks like plain ASCII text by checking a
241 // 'reasonable' number of characters (up to profile magic size).
242 size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
243 StringRef buffer = Buffer.getBufferStart();
244 return count == 0 ||
245 std::all_of(buffer.begin(), buffer.begin() + count,
246 [](char c) { return isPrint(c) || isSpace(c); });
249 // Read the profile variant flag from the header: ":FE" means this is a FE
250 // generated profile. ":IR" means this is an IR level profile. Other strings
251 // with a leading ':' will be reported an error format.
252 Error TextInstrProfReader::readHeader() {
253 Symtab.reset(new InstrProfSymtab());
255 while (Line->starts_with(":")) {
256 StringRef Str = Line->substr(1);
257 if (Str.equals_insensitive("ir"))
258 ProfileKind |= InstrProfKind::IRInstrumentation;
259 else if (Str.equals_insensitive("fe"))
260 ProfileKind |= InstrProfKind::FrontendInstrumentation;
261 else if (Str.equals_insensitive("csir")) {
262 ProfileKind |= InstrProfKind::IRInstrumentation;
263 ProfileKind |= InstrProfKind::ContextSensitive;
264 } else if (Str.equals_insensitive("entry_first"))
265 ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
266 else if (Str.equals_insensitive("not_entry_first"))
267 ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
268 else if (Str.equals_insensitive("instrument_loop_entries"))
269 ProfileKind |= InstrProfKind::LoopEntriesInstrumentation;
270 else if (Str.equals_insensitive("single_byte_coverage"))
271 ProfileKind |= InstrProfKind::SingleByteCoverage;
272 else if (Str.equals_insensitive("temporal_prof_traces")) {
273 ProfileKind |= InstrProfKind::TemporalProfile;
274 if (auto Err = readTemporalProfTraceData())
275 return error(std::move(Err));
276 } else
277 return error(instrprof_error::bad_header);
278 ++Line;
280 return success();
283 /// Temporal profile trace data is stored in the header immediately after
284 /// ":temporal_prof_traces". The first integer is the number of traces, the
285 /// second integer is the stream size, then the following lines are the actual
286 /// traces which consist of a weight and a comma separated list of function
287 /// names.
288 Error TextInstrProfReader::readTemporalProfTraceData() {
289 if ((++Line).is_at_end())
290 return error(instrprof_error::eof);
292 uint32_t NumTraces;
293 if (Line->getAsInteger(0, NumTraces))
294 return error(instrprof_error::malformed);
296 if ((++Line).is_at_end())
297 return error(instrprof_error::eof);
299 if (Line->getAsInteger(0, TemporalProfTraceStreamSize))
300 return error(instrprof_error::malformed);
302 for (uint32_t i = 0; i < NumTraces; i++) {
303 if ((++Line).is_at_end())
304 return error(instrprof_error::eof);
306 TemporalProfTraceTy Trace;
307 if (Line->getAsInteger(0, Trace.Weight))
308 return error(instrprof_error::malformed);
310 if ((++Line).is_at_end())
311 return error(instrprof_error::eof);
313 SmallVector<StringRef> FuncNames;
314 Line->split(FuncNames, ",", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
315 for (auto &FuncName : FuncNames)
316 Trace.FunctionNameRefs.push_back(
317 IndexedInstrProf::ComputeHash(FuncName.trim()));
318 TemporalProfTraces.push_back(std::move(Trace));
320 return success();
323 Error
324 TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
326 #define CHECK_LINE_END(Line) \
327 if (Line.is_at_end()) \
328 return error(instrprof_error::truncated);
329 #define READ_NUM(Str, Dst) \
330 if ((Str).getAsInteger(10, (Dst))) \
331 return error(instrprof_error::malformed);
332 #define VP_READ_ADVANCE(Val) \
333 CHECK_LINE_END(Line); \
334 uint32_t Val; \
335 READ_NUM((*Line), (Val)); \
336 Line++;
338 if (Line.is_at_end())
339 return success();
341 uint32_t NumValueKinds;
342 if (Line->getAsInteger(10, NumValueKinds)) {
343 // No value profile data
344 return success();
346 if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
347 return error(instrprof_error::malformed,
348 "number of value kinds is invalid");
349 Line++;
351 for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
352 VP_READ_ADVANCE(ValueKind);
353 if (ValueKind > IPVK_Last)
354 return error(instrprof_error::malformed, "value kind is invalid");
356 VP_READ_ADVANCE(NumValueSites);
357 if (!NumValueSites)
358 continue;
360 Record.reserveSites(VK, NumValueSites);
361 for (uint32_t S = 0; S < NumValueSites; S++) {
362 VP_READ_ADVANCE(NumValueData);
364 std::vector<InstrProfValueData> CurrentValues;
365 for (uint32_t V = 0; V < NumValueData; V++) {
366 CHECK_LINE_END(Line);
367 std::pair<StringRef, StringRef> VD = Line->rsplit(':');
368 uint64_t TakenCount, Value;
369 if (ValueKind == IPVK_IndirectCallTarget) {
370 if (InstrProfSymtab::isExternalSymbol(VD.first)) {
371 Value = 0;
372 } else {
373 if (Error E = Symtab->addFuncName(VD.first))
374 return E;
375 Value = IndexedInstrProf::ComputeHash(VD.first);
377 } else if (ValueKind == IPVK_VTableTarget) {
378 if (InstrProfSymtab::isExternalSymbol(VD.first))
379 Value = 0;
380 else {
381 if (Error E = Symtab->addVTableName(VD.first))
382 return E;
383 Value = IndexedInstrProf::ComputeHash(VD.first);
385 } else {
386 READ_NUM(VD.first, Value);
388 READ_NUM(VD.second, TakenCount);
389 CurrentValues.push_back({Value, TakenCount});
390 Line++;
392 assert(CurrentValues.size() == NumValueData);
393 Record.addValueData(ValueKind, S, CurrentValues, nullptr);
396 return success();
398 #undef CHECK_LINE_END
399 #undef READ_NUM
400 #undef VP_READ_ADVANCE
403 Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
404 // Skip empty lines and comments.
405 while (!Line.is_at_end() && (Line->empty() || Line->starts_with("#")))
406 ++Line;
407 // If we hit EOF while looking for a name, we're done.
408 if (Line.is_at_end()) {
409 return error(instrprof_error::eof);
412 // Read the function name.
413 Record.Name = *Line++;
414 if (Error E = Symtab->addFuncName(Record.Name))
415 return error(std::move(E));
417 // Read the function hash.
418 if (Line.is_at_end())
419 return error(instrprof_error::truncated);
420 if ((Line++)->getAsInteger(0, Record.Hash))
421 return error(instrprof_error::malformed,
422 "function hash is not a valid integer");
424 // Read the number of counters.
425 uint64_t NumCounters;
426 if (Line.is_at_end())
427 return error(instrprof_error::truncated);
428 if ((Line++)->getAsInteger(10, NumCounters))
429 return error(instrprof_error::malformed,
430 "number of counters is not a valid integer");
431 if (NumCounters == 0)
432 return error(instrprof_error::malformed, "number of counters is zero");
434 // Read each counter and fill our internal storage with the values.
435 Record.Clear();
436 Record.Counts.reserve(NumCounters);
437 for (uint64_t I = 0; I < NumCounters; ++I) {
438 if (Line.is_at_end())
439 return error(instrprof_error::truncated);
440 uint64_t Count;
441 if ((Line++)->getAsInteger(10, Count))
442 return error(instrprof_error::malformed, "count is invalid");
443 Record.Counts.push_back(Count);
446 // Bitmap byte information is indicated with special character.
447 if (Line->starts_with("$")) {
448 Record.BitmapBytes.clear();
449 // Read the number of bitmap bytes.
450 uint64_t NumBitmapBytes;
451 if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes))
452 return error(instrprof_error::malformed,
453 "number of bitmap bytes is not a valid integer");
454 if (NumBitmapBytes != 0) {
455 // Read each bitmap and fill our internal storage with the values.
456 Record.BitmapBytes.reserve(NumBitmapBytes);
457 for (uint8_t I = 0; I < NumBitmapBytes; ++I) {
458 if (Line.is_at_end())
459 return error(instrprof_error::truncated);
460 uint8_t BitmapByte;
461 if ((Line++)->getAsInteger(0, BitmapByte))
462 return error(instrprof_error::malformed,
463 "bitmap byte is not a valid integer");
464 Record.BitmapBytes.push_back(BitmapByte);
469 // Check if value profile data exists and read it if so.
470 if (Error E = readValueProfileData(Record))
471 return error(std::move(E));
473 return success();
476 template <class IntPtrT>
477 InstrProfKind RawInstrProfReader<IntPtrT>::getProfileKind() const {
478 return getProfileKindFromVersion(Version);
481 template <class IntPtrT>
482 SmallVector<TemporalProfTraceTy> &
483 RawInstrProfReader<IntPtrT>::getTemporalProfTraces(
484 std::optional<uint64_t> Weight) {
485 if (TemporalProfTimestamps.empty()) {
486 assert(TemporalProfTraces.empty());
487 return TemporalProfTraces;
489 // Sort functions by their timestamps to build the trace.
490 std::sort(TemporalProfTimestamps.begin(), TemporalProfTimestamps.end());
491 TemporalProfTraceTy Trace;
492 if (Weight)
493 Trace.Weight = *Weight;
494 for (auto &[TimestampValue, NameRef] : TemporalProfTimestamps)
495 Trace.FunctionNameRefs.push_back(NameRef);
496 TemporalProfTraces = {std::move(Trace)};
497 return TemporalProfTraces;
500 template <class IntPtrT>
501 bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
502 if (DataBuffer.getBufferSize() < sizeof(uint64_t))
503 return false;
504 uint64_t Magic =
505 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
506 return RawInstrProf::getMagic<IntPtrT>() == Magic ||
507 llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic;
510 template <class IntPtrT>
511 Error RawInstrProfReader<IntPtrT>::readHeader() {
512 if (!hasFormat(*DataBuffer))
513 return error(instrprof_error::bad_magic);
514 if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
515 return error(instrprof_error::bad_header);
516 auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
517 DataBuffer->getBufferStart());
518 ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
519 return readHeader(*Header);
522 template <class IntPtrT>
523 Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
524 const char *End = DataBuffer->getBufferEnd();
525 // Skip zero padding between profiles.
526 while (CurrentPos != End && *CurrentPos == 0)
527 ++CurrentPos;
528 // If there's nothing left, we're done.
529 if (CurrentPos == End)
530 return make_error<InstrProfError>(instrprof_error::eof);
531 // If there isn't enough space for another header, this is probably just
532 // garbage at the end of the file.
533 if (CurrentPos + sizeof(RawInstrProf::Header) > End)
534 return make_error<InstrProfError>(instrprof_error::malformed,
535 "not enough space for another header");
536 // The writer ensures each profile is padded to start at an aligned address.
537 if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
538 return make_error<InstrProfError>(instrprof_error::malformed,
539 "insufficient padding");
540 // The magic should have the same byte order as in the previous header.
541 uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
542 if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
543 return make_error<InstrProfError>(instrprof_error::bad_magic);
545 // There's another profile to read, so we need to process the header.
546 auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
547 return readHeader(*Header);
550 template <class IntPtrT>
551 Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
552 if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart),
553 StringRef(VNamesStart, VNamesEnd - VNamesStart)))
554 return error(std::move(E));
555 for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
556 const IntPtrT FPtr = swap(I->FunctionPointer);
557 if (!FPtr)
558 continue;
559 Symtab.mapAddress(FPtr, swap(I->NameRef));
562 if (VTableBegin != nullptr && VTableEnd != nullptr) {
563 for (const RawInstrProf::VTableProfileData<IntPtrT> *I = VTableBegin;
564 I != VTableEnd; ++I) {
565 const IntPtrT VPtr = swap(I->VTablePointer);
566 if (!VPtr)
567 continue;
568 // Map both begin and end address to the name hash, since the instrumented
569 // address could be somewhere in the middle.
570 // VPtr is of type uint32_t or uint64_t so 'VPtr + I->VTableSize' marks
571 // the end of vtable address.
572 Symtab.mapVTableAddress(VPtr, VPtr + swap(I->VTableSize),
573 swap(I->VTableNameHash));
576 return success();
579 template <class IntPtrT>
580 Error RawInstrProfReader<IntPtrT>::readHeader(
581 const RawInstrProf::Header &Header) {
582 Version = swap(Header.Version);
583 if (GET_VERSION(Version) != RawInstrProf::Version)
584 return error(instrprof_error::raw_profile_version_mismatch,
585 ("Profile uses raw profile format version = " +
586 Twine(GET_VERSION(Version)) +
587 "; expected version = " + Twine(RawInstrProf::Version) +
588 "\nPLEASE update this tool to version in the raw profile, or "
589 "regenerate raw profile with expected version.")
590 .str());
592 uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
593 // Binary id start just after the header if exists.
594 const uint8_t *BinaryIdStart =
595 reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
596 const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
597 const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
598 if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
599 return error(instrprof_error::bad_header);
600 ArrayRef<uint8_t> BinaryIdsBuffer(BinaryIdStart, BinaryIdSize);
601 if (!BinaryIdsBuffer.empty()) {
602 if (Error Err = readBinaryIdsInternal(*DataBuffer, BinaryIdsBuffer,
603 BinaryIds, getDataEndianness()))
604 return Err;
607 CountersDelta = swap(Header.CountersDelta);
608 BitmapDelta = swap(Header.BitmapDelta);
609 NamesDelta = swap(Header.NamesDelta);
610 auto NumData = swap(Header.NumData);
611 auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
612 auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize();
613 auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
614 auto NumBitmapBytes = swap(Header.NumBitmapBytes);
615 auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes);
616 auto NamesSize = swap(Header.NamesSize);
617 auto VTableNameSize = swap(Header.VNamesSize);
618 auto NumVTables = swap(Header.NumVTables);
619 ValueKindLast = swap(Header.ValueKindLast);
621 auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
622 auto PaddingBytesAfterNames = getNumPaddingBytes(NamesSize);
623 auto PaddingBytesAfterVTableNames = getNumPaddingBytes(VTableNameSize);
625 auto VTableSectionSize =
626 NumVTables * sizeof(RawInstrProf::VTableProfileData<IntPtrT>);
627 auto PaddingBytesAfterVTableProfData = getNumPaddingBytes(VTableSectionSize);
629 // Profile data starts after profile header and binary ids if exist.
630 ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdSize;
631 ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
632 ptrdiff_t BitmapOffset =
633 CountersOffset + CountersSize + PaddingBytesAfterCounters;
634 ptrdiff_t NamesOffset =
635 BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes;
636 ptrdiff_t VTableProfDataOffset =
637 NamesOffset + NamesSize + PaddingBytesAfterNames;
638 ptrdiff_t VTableNameOffset = VTableProfDataOffset + VTableSectionSize +
639 PaddingBytesAfterVTableProfData;
640 ptrdiff_t ValueDataOffset =
641 VTableNameOffset + VTableNameSize + PaddingBytesAfterVTableNames;
643 auto *Start = reinterpret_cast<const char *>(&Header);
644 if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
645 return error(instrprof_error::bad_header);
647 if (BIDFetcher) {
648 std::vector<object::BuildID> BinaryIDs;
649 if (Error E = readBinaryIds(BinaryIDs))
650 return E;
651 if (auto E = InstrProfCorrelator::get("", BIDFetcherCorrelatorKind,
652 BIDFetcher, BinaryIDs)
653 .moveInto(BIDFetcherCorrelator)) {
654 return E;
656 if (auto Err = BIDFetcherCorrelator->correlateProfileData(0))
657 return Err;
660 if (Correlator) {
661 // These sizes in the raw file are zero because we constructed them in the
662 // Correlator.
663 if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 &&
664 NamesDelta == 0))
665 return error(instrprof_error::unexpected_correlation_info);
666 Data = Correlator->getDataPointer();
667 DataEnd = Data + Correlator->getDataSize();
668 NamesStart = Correlator->getNamesPointer();
669 NamesEnd = NamesStart + Correlator->getNamesSize();
670 } else if (BIDFetcherCorrelator) {
671 InstrProfCorrelatorImpl<IntPtrT> *BIDFetcherCorrelatorImpl =
672 dyn_cast_or_null<InstrProfCorrelatorImpl<IntPtrT>>(
673 BIDFetcherCorrelator.get());
674 Data = BIDFetcherCorrelatorImpl->getDataPointer();
675 DataEnd = Data + BIDFetcherCorrelatorImpl->getDataSize();
676 NamesStart = BIDFetcherCorrelatorImpl->getNamesPointer();
677 NamesEnd = NamesStart + BIDFetcherCorrelatorImpl->getNamesSize();
678 } else {
679 Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
680 Start + DataOffset);
681 DataEnd = Data + NumData;
682 VTableBegin =
683 reinterpret_cast<const RawInstrProf::VTableProfileData<IntPtrT> *>(
684 Start + VTableProfDataOffset);
685 VTableEnd = VTableBegin + NumVTables;
686 NamesStart = Start + NamesOffset;
687 NamesEnd = NamesStart + NamesSize;
688 VNamesStart = Start + VTableNameOffset;
689 VNamesEnd = VNamesStart + VTableNameSize;
692 CountersStart = Start + CountersOffset;
693 CountersEnd = CountersStart + CountersSize;
694 BitmapStart = Start + BitmapOffset;
695 BitmapEnd = BitmapStart + NumBitmapBytes;
696 ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
698 std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
699 if (Error E = createSymtab(*NewSymtab))
700 return E;
702 Symtab = std::move(NewSymtab);
703 return success();
706 template <class IntPtrT>
707 Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
708 Record.Name = getName(Data->NameRef);
709 return success();
712 template <class IntPtrT>
713 Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
714 Record.Hash = swap(Data->FuncHash);
715 return success();
718 template <class IntPtrT>
719 Error RawInstrProfReader<IntPtrT>::readRawCounts(
720 InstrProfRecord &Record) {
721 uint32_t NumCounters = swap(Data->NumCounters);
722 if (NumCounters == 0)
723 return error(instrprof_error::malformed, "number of counters is zero");
725 ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
726 if (CounterBaseOffset < 0)
727 return error(
728 instrprof_error::malformed,
729 ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
731 if (CounterBaseOffset >= CountersEnd - CountersStart)
732 return error(instrprof_error::malformed,
733 ("counter offset " + Twine(CounterBaseOffset) +
734 " is greater than the maximum counter offset " +
735 Twine(CountersEnd - CountersStart - 1))
736 .str());
738 uint64_t MaxNumCounters =
739 (CountersEnd - (CountersStart + CounterBaseOffset)) /
740 getCounterTypeSize();
741 if (NumCounters > MaxNumCounters)
742 return error(instrprof_error::malformed,
743 ("number of counters " + Twine(NumCounters) +
744 " is greater than the maximum number of counters " +
745 Twine(MaxNumCounters))
746 .str());
748 Record.Counts.clear();
749 Record.Counts.reserve(NumCounters);
750 for (uint32_t I = 0; I < NumCounters; I++) {
751 const char *Ptr =
752 CountersStart + CounterBaseOffset + I * getCounterTypeSize();
753 if (I == 0 && hasTemporalProfile()) {
754 uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
755 if (TimestampValue != 0 &&
756 TimestampValue != std::numeric_limits<uint64_t>::max()) {
757 TemporalProfTimestamps.emplace_back(TimestampValue,
758 swap(Data->NameRef));
759 TemporalProfTraceStreamSize = 1;
761 if (hasSingleByteCoverage()) {
762 // In coverage mode, getCounterTypeSize() returns 1 byte but our
763 // timestamp field has size uint64_t. Increment I so that the next
764 // iteration of this for loop points to the byte after the timestamp
765 // field, i.e., I += 8.
766 I += 7;
768 continue;
770 if (hasSingleByteCoverage()) {
771 // A value of zero signifies the block is covered.
772 Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
773 } else {
774 uint64_t CounterValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
775 if (CounterValue > MaxCounterValue && Warn)
776 Warn(make_error<InstrProfError>(
777 instrprof_error::counter_value_too_large, Twine(CounterValue)));
779 Record.Counts.push_back(CounterValue);
783 return success();
786 template <class IntPtrT>
787 Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) {
788 uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
790 Record.BitmapBytes.clear();
791 Record.BitmapBytes.reserve(NumBitmapBytes);
793 // It's possible MCDC is either not enabled or only used for some functions
794 // and not others. So if we record 0 bytes, just move on.
795 if (NumBitmapBytes == 0)
796 return success();
798 // BitmapDelta decreases as we advance to the next data record.
799 ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
800 if (BitmapOffset < 0)
801 return error(
802 instrprof_error::malformed,
803 ("bitmap offset " + Twine(BitmapOffset) + " is negative").str());
805 if (BitmapOffset >= BitmapEnd - BitmapStart)
806 return error(instrprof_error::malformed,
807 ("bitmap offset " + Twine(BitmapOffset) +
808 " is greater than the maximum bitmap offset " +
809 Twine(BitmapEnd - BitmapStart - 1))
810 .str());
812 uint64_t MaxNumBitmapBytes =
813 (BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t);
814 if (NumBitmapBytes > MaxNumBitmapBytes)
815 return error(instrprof_error::malformed,
816 ("number of bitmap bytes " + Twine(NumBitmapBytes) +
817 " is greater than the maximum number of bitmap bytes " +
818 Twine(MaxNumBitmapBytes))
819 .str());
821 for (uint32_t I = 0; I < NumBitmapBytes; I++) {
822 const char *Ptr = BitmapStart + BitmapOffset + I;
823 Record.BitmapBytes.push_back(swap(*Ptr));
826 return success();
829 template <class IntPtrT>
830 Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
831 InstrProfRecord &Record) {
832 Record.clearValueData();
833 CurValueDataSize = 0;
834 // Need to match the logic in value profile dumper code in compiler-rt:
835 uint32_t NumValueKinds = 0;
836 for (uint32_t I = 0; I < IPVK_Last + 1; I++)
837 NumValueKinds += (Data->NumValueSites[I] != 0);
839 if (!NumValueKinds)
840 return success();
842 Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
843 ValueProfData::getValueProfData(
844 ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
845 getDataEndianness());
847 if (Error E = VDataPtrOrErr.takeError())
848 return E;
850 // Note that besides deserialization, this also performs the conversion for
851 // indirect call targets. The function pointers from the raw profile are
852 // remapped into function name hashes.
853 VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
854 CurValueDataSize = VDataPtrOrErr.get()->getSize();
855 return success();
858 template <class IntPtrT>
859 Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
860 // Keep reading profiles that consist of only headers and no profile data and
861 // counters.
862 while (atEnd())
863 // At this point, ValueDataStart field points to the next header.
864 if (Error E = readNextHeader(getNextHeaderPos()))
865 return error(std::move(E));
867 // Read name and set it in Record.
868 if (Error E = readName(Record))
869 return error(std::move(E));
871 // Read FuncHash and set it in Record.
872 if (Error E = readFuncHash(Record))
873 return error(std::move(E));
875 // Read raw counts and set Record.
876 if (Error E = readRawCounts(Record))
877 return error(std::move(E));
879 // Read raw bitmap bytes and set Record.
880 if (Error E = readRawBitmapBytes(Record))
881 return error(std::move(E));
883 // Read value data and set Record.
884 if (Error E = readValueProfilingData(Record))
885 return error(std::move(E));
887 // Iterate.
888 advanceData();
889 return success();
892 template <class IntPtrT>
893 Error RawInstrProfReader<IntPtrT>::readBinaryIds(
894 std::vector<llvm::object::BuildID> &BinaryIds) {
895 BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(),
896 this->BinaryIds.end());
897 return Error::success();
900 template <class IntPtrT>
901 Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
902 if (!BinaryIds.empty())
903 printBinaryIdsInternal(OS, BinaryIds);
904 return Error::success();
907 namespace llvm {
909 template class RawInstrProfReader<uint32_t>;
910 template class RawInstrProfReader<uint64_t>;
912 } // end namespace llvm
914 InstrProfLookupTrait::hash_value_type
915 InstrProfLookupTrait::ComputeHash(StringRef K) {
916 return IndexedInstrProf::ComputeHash(HashType, K);
919 using data_type = InstrProfLookupTrait::data_type;
920 using offset_type = InstrProfLookupTrait::offset_type;
922 bool InstrProfLookupTrait::readValueProfilingData(
923 const unsigned char *&D, const unsigned char *const End) {
924 Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
925 ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
927 if (VDataPtrOrErr.takeError())
928 return false;
930 VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
931 D += VDataPtrOrErr.get()->TotalSize;
933 return true;
936 data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
937 offset_type N) {
938 using namespace support;
940 // Check if the data is corrupt. If so, don't try to read it.
941 if (N % sizeof(uint64_t))
942 return data_type();
944 DataBuffer.clear();
945 std::vector<uint64_t> CounterBuffer;
946 std::vector<uint8_t> BitmapByteBuffer;
948 const unsigned char *End = D + N;
949 while (D < End) {
950 // Read hash.
951 if (D + sizeof(uint64_t) >= End)
952 return data_type();
953 uint64_t Hash = endian::readNext<uint64_t, llvm::endianness::little>(D);
955 // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
956 uint64_t CountsSize = N / sizeof(uint64_t) - 1;
957 // If format version is different then read the number of counters.
958 if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
959 if (D + sizeof(uint64_t) > End)
960 return data_type();
961 CountsSize = endian::readNext<uint64_t, llvm::endianness::little>(D);
963 // Read counter values.
964 if (D + CountsSize * sizeof(uint64_t) > End)
965 return data_type();
967 CounterBuffer.clear();
968 CounterBuffer.reserve(CountsSize);
969 for (uint64_t J = 0; J < CountsSize; ++J)
970 CounterBuffer.push_back(
971 endian::readNext<uint64_t, llvm::endianness::little>(D));
973 // Read bitmap bytes for GET_VERSION(FormatVersion) > 10.
974 if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) {
975 uint64_t BitmapBytes = 0;
976 if (D + sizeof(uint64_t) > End)
977 return data_type();
978 BitmapBytes = endian::readNext<uint64_t, llvm::endianness::little>(D);
979 // Read bitmap byte values.
980 if (D + BitmapBytes * sizeof(uint8_t) > End)
981 return data_type();
982 BitmapByteBuffer.clear();
983 BitmapByteBuffer.reserve(BitmapBytes);
984 for (uint64_t J = 0; J < BitmapBytes; ++J)
985 BitmapByteBuffer.push_back(static_cast<uint8_t>(
986 endian::readNext<uint64_t, llvm::endianness::little>(D)));
989 DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer),
990 std::move(BitmapByteBuffer));
992 // Read value profiling data.
993 if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
994 !readValueProfilingData(D, End)) {
995 DataBuffer.clear();
996 return data_type();
999 return DataBuffer;
1002 template <typename HashTableImpl>
1003 Error InstrProfReaderIndex<HashTableImpl>::getRecords(
1004 StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) {
1005 auto Iter = HashTable->find(FuncName);
1006 if (Iter == HashTable->end())
1007 return make_error<InstrProfError>(instrprof_error::unknown_function);
1009 Data = (*Iter);
1010 if (Data.empty())
1011 return make_error<InstrProfError>(instrprof_error::malformed,
1012 "profile data is empty");
1014 return Error::success();
1017 template <typename HashTableImpl>
1018 Error InstrProfReaderIndex<HashTableImpl>::getRecords(
1019 ArrayRef<NamedInstrProfRecord> &Data) {
1020 if (atEnd())
1021 return make_error<InstrProfError>(instrprof_error::eof);
1023 Data = *RecordIterator;
1025 if (Data.empty())
1026 return make_error<InstrProfError>(instrprof_error::malformed,
1027 "profile data is empty");
1029 return Error::success();
1032 template <typename HashTableImpl>
1033 InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
1034 const unsigned char *Buckets, const unsigned char *const Payload,
1035 const unsigned char *const Base, IndexedInstrProf::HashT HashType,
1036 uint64_t Version) {
1037 FormatVersion = Version;
1038 HashTable.reset(HashTableImpl::Create(
1039 Buckets, Payload, Base,
1040 typename HashTableImpl::InfoType(HashType, Version)));
1041 RecordIterator = HashTable->data_begin();
1044 template <typename HashTableImpl>
1045 InstrProfKind InstrProfReaderIndex<HashTableImpl>::getProfileKind() const {
1046 return getProfileKindFromVersion(FormatVersion);
1049 namespace {
1050 /// A remapper that does not apply any remappings.
1051 class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
1052 InstrProfReaderIndexBase &Underlying;
1054 public:
1055 InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
1056 : Underlying(Underlying) {}
1058 Error getRecords(StringRef FuncName,
1059 ArrayRef<NamedInstrProfRecord> &Data) override {
1060 return Underlying.getRecords(FuncName, Data);
1063 } // namespace
1065 /// A remapper that applies remappings based on a symbol remapping file.
1066 template <typename HashTableImpl>
1067 class llvm::InstrProfReaderItaniumRemapper
1068 : public InstrProfReaderRemapper {
1069 public:
1070 InstrProfReaderItaniumRemapper(
1071 std::unique_ptr<MemoryBuffer> RemapBuffer,
1072 InstrProfReaderIndex<HashTableImpl> &Underlying)
1073 : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
1076 /// Extract the original function name from a PGO function name.
1077 static StringRef extractName(StringRef Name) {
1078 // We can have multiple pieces separated by kGlobalIdentifierDelimiter (
1079 // semicolon now and colon in older profiles); there can be pieces both
1080 // before and after the mangled name. Find the first part that starts with
1081 // '_Z'; we'll assume that's the mangled name we want.
1082 std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
1083 while (true) {
1084 Parts = Parts.second.split(GlobalIdentifierDelimiter);
1085 if (Parts.first.starts_with("_Z"))
1086 return Parts.first;
1087 if (Parts.second.empty())
1088 return Name;
1092 /// Given a mangled name extracted from a PGO function name, and a new
1093 /// form for that mangled name, reconstitute the name.
1094 static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
1095 StringRef Replacement,
1096 SmallVectorImpl<char> &Out) {
1097 Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
1098 Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
1099 Out.insert(Out.end(), Replacement.begin(), Replacement.end());
1100 Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
1103 Error populateRemappings() override {
1104 if (Error E = Remappings.read(*RemapBuffer))
1105 return E;
1106 for (StringRef Name : Underlying.HashTable->keys()) {
1107 StringRef RealName = extractName(Name);
1108 if (auto Key = Remappings.insert(RealName)) {
1109 // FIXME: We could theoretically map the same equivalence class to
1110 // multiple names in the profile data. If that happens, we should
1111 // return NamedInstrProfRecords from all of them.
1112 MappedNames.insert({Key, RealName});
1115 return Error::success();
1118 Error getRecords(StringRef FuncName,
1119 ArrayRef<NamedInstrProfRecord> &Data) override {
1120 StringRef RealName = extractName(FuncName);
1121 if (auto Key = Remappings.lookup(RealName)) {
1122 StringRef Remapped = MappedNames.lookup(Key);
1123 if (!Remapped.empty()) {
1124 if (RealName.begin() == FuncName.begin() &&
1125 RealName.end() == FuncName.end())
1126 FuncName = Remapped;
1127 else {
1128 // Try rebuilding the name from the given remapping.
1129 SmallString<256> Reconstituted;
1130 reconstituteName(FuncName, RealName, Remapped, Reconstituted);
1131 Error E = Underlying.getRecords(Reconstituted, Data);
1132 if (!E)
1133 return E;
1135 // If we failed because the name doesn't exist, fall back to asking
1136 // about the original name.
1137 if (Error Unhandled = handleErrors(
1138 std::move(E), [](std::unique_ptr<InstrProfError> Err) {
1139 return Err->get() == instrprof_error::unknown_function
1140 ? Error::success()
1141 : Error(std::move(Err));
1143 return Unhandled;
1147 return Underlying.getRecords(FuncName, Data);
1150 private:
1151 /// The memory buffer containing the remapping configuration. Remappings
1152 /// holds pointers into this buffer.
1153 std::unique_ptr<MemoryBuffer> RemapBuffer;
1155 /// The mangling remapper.
1156 SymbolRemappingReader Remappings;
1158 /// Mapping from mangled name keys to the name used for the key in the
1159 /// profile data.
1160 /// FIXME: Can we store a location within the on-disk hash table instead of
1161 /// redoing lookup?
1162 DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
1164 /// The real profile data reader.
1165 InstrProfReaderIndex<HashTableImpl> &Underlying;
1168 bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
1169 using namespace support;
1171 if (DataBuffer.getBufferSize() < 8)
1172 return false;
1173 uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(
1174 DataBuffer.getBufferStart());
1175 // Verify that it's magical.
1176 return Magic == IndexedInstrProf::Magic;
1179 const unsigned char *
1180 IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
1181 const unsigned char *Cur, bool UseCS) {
1182 using namespace IndexedInstrProf;
1183 using namespace support;
1185 if (Version >= IndexedInstrProf::Version4) {
1186 const IndexedInstrProf::Summary *SummaryInLE =
1187 reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
1188 uint64_t NFields = endian::byte_swap<uint64_t, llvm::endianness::little>(
1189 SummaryInLE->NumSummaryFields);
1190 uint64_t NEntries = endian::byte_swap<uint64_t, llvm::endianness::little>(
1191 SummaryInLE->NumCutoffEntries);
1192 uint32_t SummarySize =
1193 IndexedInstrProf::Summary::getSize(NFields, NEntries);
1194 std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
1195 IndexedInstrProf::allocSummary(SummarySize);
1197 const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
1198 uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
1199 for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
1200 Dst[I] = endian::byte_swap<uint64_t, llvm::endianness::little>(Src[I]);
1202 SummaryEntryVector DetailedSummary;
1203 for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
1204 const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
1205 DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
1206 Ent.NumBlocks);
1208 std::unique_ptr<llvm::ProfileSummary> &Summary =
1209 UseCS ? this->CS_Summary : this->Summary;
1211 // initialize InstrProfSummary using the SummaryData from disk.
1212 Summary = std::make_unique<ProfileSummary>(
1213 UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr,
1214 DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
1215 SummaryData->get(Summary::MaxBlockCount),
1216 SummaryData->get(Summary::MaxInternalBlockCount),
1217 SummaryData->get(Summary::MaxFunctionCount),
1218 SummaryData->get(Summary::TotalNumBlocks),
1219 SummaryData->get(Summary::TotalNumFunctions));
1220 return Cur + SummarySize;
1221 } else {
1222 // The older versions do not support a profile summary. This just computes
1223 // an empty summary, which will not result in accurate hot/cold detection.
1224 // We would need to call addRecord for all NamedInstrProfRecords to get the
1225 // correct summary. However, this version is old (prior to early 2016) and
1226 // has not been supporting an accurate summary for several years.
1227 InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
1228 Summary = Builder.getSummary();
1229 return Cur;
1233 Error IndexedMemProfReader::deserializeV2(const unsigned char *Start,
1234 const unsigned char *Ptr) {
1235 // The value returned from RecordTableGenerator.Emit.
1236 const uint64_t RecordTableOffset =
1237 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1238 // The offset in the stream right before invoking
1239 // FrameTableGenerator.Emit.
1240 const uint64_t FramePayloadOffset =
1241 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1242 // The value returned from FrameTableGenerator.Emit.
1243 const uint64_t FrameTableOffset =
1244 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1246 // The offset in the stream right before invoking
1247 // CallStackTableGenerator.Emit.
1248 uint64_t CallStackPayloadOffset = 0;
1249 // The value returned from CallStackTableGenerator.Emit.
1250 uint64_t CallStackTableOffset = 0;
1251 if (Version >= memprof::Version2) {
1252 CallStackPayloadOffset =
1253 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1254 CallStackTableOffset =
1255 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1258 // Read the schema.
1259 auto SchemaOr = memprof::readMemProfSchema(Ptr);
1260 if (!SchemaOr)
1261 return SchemaOr.takeError();
1262 Schema = SchemaOr.get();
1264 // Now initialize the table reader with a pointer into data buffer.
1265 MemProfRecordTable.reset(MemProfRecordHashTable::Create(
1266 /*Buckets=*/Start + RecordTableOffset,
1267 /*Payload=*/Ptr,
1268 /*Base=*/Start, memprof::RecordLookupTrait(Version, Schema)));
1270 // Initialize the frame table reader with the payload and bucket offsets.
1271 MemProfFrameTable.reset(MemProfFrameHashTable::Create(
1272 /*Buckets=*/Start + FrameTableOffset,
1273 /*Payload=*/Start + FramePayloadOffset,
1274 /*Base=*/Start));
1276 if (Version >= memprof::Version2)
1277 MemProfCallStackTable.reset(MemProfCallStackHashTable::Create(
1278 /*Buckets=*/Start + CallStackTableOffset,
1279 /*Payload=*/Start + CallStackPayloadOffset,
1280 /*Base=*/Start));
1282 return Error::success();
1285 Error IndexedMemProfReader::deserializeV3(const unsigned char *Start,
1286 const unsigned char *Ptr) {
1287 // The offset in the stream right before invoking
1288 // CallStackTableGenerator.Emit.
1289 const uint64_t CallStackPayloadOffset =
1290 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1291 // The offset in the stream right before invoking RecordTableGenerator.Emit.
1292 const uint64_t RecordPayloadOffset =
1293 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1294 // The value returned from RecordTableGenerator.Emit.
1295 const uint64_t RecordTableOffset =
1296 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1298 // Read the schema.
1299 auto SchemaOr = memprof::readMemProfSchema(Ptr);
1300 if (!SchemaOr)
1301 return SchemaOr.takeError();
1302 Schema = SchemaOr.get();
1304 FrameBase = Ptr;
1305 CallStackBase = Start + CallStackPayloadOffset;
1307 // Compute the number of elements in the radix tree array. Since we use this
1308 // to reserve enough bits in a BitVector, it's totally OK if we overestimate
1309 // this number a little bit because of padding just before the next section.
1310 RadixTreeSize = (RecordPayloadOffset - CallStackPayloadOffset) /
1311 sizeof(memprof::LinearFrameId);
1313 // Now initialize the table reader with a pointer into data buffer.
1314 MemProfRecordTable.reset(MemProfRecordHashTable::Create(
1315 /*Buckets=*/Start + RecordTableOffset,
1316 /*Payload=*/Start + RecordPayloadOffset,
1317 /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version3, Schema)));
1319 return Error::success();
1322 Error IndexedMemProfReader::deserialize(const unsigned char *Start,
1323 uint64_t MemProfOffset) {
1324 const unsigned char *Ptr = Start + MemProfOffset;
1326 // Read the MemProf version number.
1327 const uint64_t FirstWord =
1328 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1330 if (FirstWord == memprof::Version2 || FirstWord == memprof::Version3) {
1331 // Everything is good. We can proceed to deserialize the rest.
1332 Version = static_cast<memprof::IndexedVersion>(FirstWord);
1333 } else {
1334 return make_error<InstrProfError>(
1335 instrprof_error::unsupported_version,
1336 formatv("MemProf version {} not supported; "
1337 "requires version between {} and {}, inclusive",
1338 FirstWord, memprof::MinimumSupportedVersion,
1339 memprof::MaximumSupportedVersion));
1342 switch (Version) {
1343 case memprof::Version2:
1344 if (Error E = deserializeV2(Start, Ptr))
1345 return E;
1346 break;
1347 case memprof::Version3:
1348 if (Error E = deserializeV3(Start, Ptr))
1349 return E;
1350 break;
1353 return Error::success();
1356 Error IndexedInstrProfReader::readHeader() {
1357 using namespace support;
1359 const unsigned char *Start =
1360 (const unsigned char *)DataBuffer->getBufferStart();
1361 const unsigned char *Cur = Start;
1362 if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
1363 return error(instrprof_error::truncated);
1365 auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
1366 if (!HeaderOr)
1367 return HeaderOr.takeError();
1369 const IndexedInstrProf::Header *Header = &HeaderOr.get();
1370 Cur += Header->size();
1372 Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur,
1373 /* UseCS */ false);
1374 if (Header->Version & VARIANT_MASK_CSIR_PROF)
1375 Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur,
1376 /* UseCS */ true);
1377 // Read the hash type and start offset.
1378 IndexedInstrProf::HashT HashType =
1379 static_cast<IndexedInstrProf::HashT>(Header->HashType);
1380 if (HashType > IndexedInstrProf::HashT::Last)
1381 return error(instrprof_error::unsupported_hash_type);
1383 // The hash table with profile counts comes next.
1384 auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
1385 Start + Header->HashOffset, Cur, Start, HashType, Header->Version);
1387 // The MemProfOffset field in the header is only valid when the format
1388 // version is higher than 8 (when it was introduced).
1389 if (Header->getIndexedProfileVersion() >= 8 &&
1390 Header->Version & VARIANT_MASK_MEMPROF) {
1391 if (Error E = MemProfReader.deserialize(Start, Header->MemProfOffset))
1392 return E;
1395 // BinaryIdOffset field in the header is only valid when the format version
1396 // is higher than 9 (when it was introduced).
1397 if (Header->getIndexedProfileVersion() >= 9) {
1398 const unsigned char *Ptr = Start + Header->BinaryIdOffset;
1399 // Read binary ids size.
1400 uint64_t BinaryIdsSize =
1401 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1402 if (BinaryIdsSize % sizeof(uint64_t))
1403 return error(instrprof_error::bad_header);
1404 // Set the binary ids start.
1405 BinaryIdsBuffer = ArrayRef<uint8_t>(Ptr, BinaryIdsSize);
1406 if (Ptr > (const unsigned char *)DataBuffer->getBufferEnd())
1407 return make_error<InstrProfError>(instrprof_error::malformed,
1408 "corrupted binary ids");
1411 if (Header->getIndexedProfileVersion() >= 12) {
1412 const unsigned char *Ptr = Start + Header->VTableNamesOffset;
1414 uint64_t CompressedVTableNamesLen =
1415 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1417 // Writer first writes the length of compressed string, and then the actual
1418 // content.
1419 const char *VTableNamePtr = (const char *)Ptr;
1420 if (VTableNamePtr > (const char *)DataBuffer->getBufferEnd())
1421 return make_error<InstrProfError>(instrprof_error::truncated);
1423 VTableName = StringRef(VTableNamePtr, CompressedVTableNamesLen);
1426 if (Header->getIndexedProfileVersion() >= 10 &&
1427 Header->Version & VARIANT_MASK_TEMPORAL_PROF) {
1428 const unsigned char *Ptr = Start + Header->TemporalProfTracesOffset;
1429 const auto *PtrEnd = (const unsigned char *)DataBuffer->getBufferEnd();
1430 // Expect at least two 64 bit fields: NumTraces, and TraceStreamSize
1431 if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1432 return error(instrprof_error::truncated);
1433 const uint64_t NumTraces =
1434 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1435 TemporalProfTraceStreamSize =
1436 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1437 for (unsigned i = 0; i < NumTraces; i++) {
1438 // Expect at least two 64 bit fields: Weight and NumFunctions
1439 if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1440 return error(instrprof_error::truncated);
1441 TemporalProfTraceTy Trace;
1442 Trace.Weight =
1443 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1444 const uint64_t NumFunctions =
1445 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1446 // Expect at least NumFunctions 64 bit fields
1447 if (Ptr + NumFunctions * sizeof(uint64_t) > PtrEnd)
1448 return error(instrprof_error::truncated);
1449 for (unsigned j = 0; j < NumFunctions; j++) {
1450 const uint64_t NameRef =
1451 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1452 Trace.FunctionNameRefs.push_back(NameRef);
1454 TemporalProfTraces.push_back(std::move(Trace));
1458 // Load the remapping table now if requested.
1459 if (RemappingBuffer) {
1460 Remapper =
1461 std::make_unique<InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
1462 std::move(RemappingBuffer), *IndexPtr);
1463 if (Error E = Remapper->populateRemappings())
1464 return E;
1465 } else {
1466 Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
1468 Index = std::move(IndexPtr);
1470 return success();
1473 InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
1474 if (Symtab)
1475 return *Symtab;
1477 auto NewSymtab = std::make_unique<InstrProfSymtab>();
1479 if (Error E = NewSymtab->initVTableNamesFromCompressedStrings(VTableName)) {
1480 auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1481 consumeError(error(ErrCode, Msg));
1484 // finalizeSymtab is called inside populateSymtab.
1485 if (Error E = Index->populateSymtab(*NewSymtab)) {
1486 auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1487 consumeError(error(ErrCode, Msg));
1490 Symtab = std::move(NewSymtab);
1491 return *Symtab;
1494 Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(
1495 StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName,
1496 uint64_t *MismatchedFuncSum) {
1497 ArrayRef<NamedInstrProfRecord> Data;
1498 uint64_t FuncSum = 0;
1499 auto Err = Remapper->getRecords(FuncName, Data);
1500 if (Err) {
1501 // If we don't find FuncName, try DeprecatedFuncName to handle profiles
1502 // built by older compilers.
1503 auto Err2 =
1504 handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
1505 if (IE.get() != instrprof_error::unknown_function)
1506 return make_error<InstrProfError>(IE);
1507 if (auto Err = Remapper->getRecords(DeprecatedFuncName, Data))
1508 return Err;
1509 return Error::success();
1511 if (Err2)
1512 return std::move(Err2);
1514 // Found it. Look for counters with the right hash.
1516 // A flag to indicate if the records are from the same type
1517 // of profile (i.e cs vs nocs).
1518 bool CSBitMatch = false;
1519 auto getFuncSum = [](ArrayRef<uint64_t> Counts) {
1520 uint64_t ValueSum = 0;
1521 for (uint64_t CountValue : Counts) {
1522 if (CountValue == (uint64_t)-1)
1523 continue;
1524 // Handle overflow -- if that happens, return max.
1525 if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1526 return std::numeric_limits<uint64_t>::max();
1527 ValueSum += CountValue;
1529 return ValueSum;
1532 for (const NamedInstrProfRecord &I : Data) {
1533 // Check for a match and fill the vector if there is one.
1534 if (I.Hash == FuncHash)
1535 return std::move(I);
1536 if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) ==
1537 NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) {
1538 CSBitMatch = true;
1539 if (MismatchedFuncSum == nullptr)
1540 continue;
1541 FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
1544 if (CSBitMatch) {
1545 if (MismatchedFuncSum != nullptr)
1546 *MismatchedFuncSum = FuncSum;
1547 return error(instrprof_error::hash_mismatch);
1549 return error(instrprof_error::unknown_function);
1552 static Expected<memprof::MemProfRecord>
1553 getMemProfRecordV2(const memprof::IndexedMemProfRecord &IndexedRecord,
1554 MemProfFrameHashTable &MemProfFrameTable,
1555 MemProfCallStackHashTable &MemProfCallStackTable) {
1556 memprof::FrameIdConverter<MemProfFrameHashTable> FrameIdConv(
1557 MemProfFrameTable);
1559 memprof::CallStackIdConverter<MemProfCallStackHashTable> CSIdConv(
1560 MemProfCallStackTable, FrameIdConv);
1562 memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv);
1564 // Check that all call stack ids were successfully converted to call stacks.
1565 if (CSIdConv.LastUnmappedId) {
1566 return make_error<InstrProfError>(
1567 instrprof_error::hash_mismatch,
1568 "memprof call stack not found for call stack id " +
1569 Twine(*CSIdConv.LastUnmappedId));
1572 // Check that all frame ids were successfully converted to frames.
1573 if (FrameIdConv.LastUnmappedId) {
1574 return make_error<InstrProfError>(instrprof_error::hash_mismatch,
1575 "memprof frame not found for frame id " +
1576 Twine(*FrameIdConv.LastUnmappedId));
1579 return Record;
1582 static Expected<memprof::MemProfRecord>
1583 getMemProfRecordV3(const memprof::IndexedMemProfRecord &IndexedRecord,
1584 const unsigned char *FrameBase,
1585 const unsigned char *CallStackBase) {
1586 memprof::LinearFrameIdConverter FrameIdConv(FrameBase);
1587 memprof::LinearCallStackIdConverter CSIdConv(CallStackBase, FrameIdConv);
1588 memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv);
1589 return Record;
1592 Expected<memprof::MemProfRecord>
1593 IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const {
1594 // TODO: Add memprof specific errors.
1595 if (MemProfRecordTable == nullptr)
1596 return make_error<InstrProfError>(instrprof_error::invalid_prof,
1597 "no memprof data available in profile");
1598 auto Iter = MemProfRecordTable->find(FuncNameHash);
1599 if (Iter == MemProfRecordTable->end())
1600 return make_error<InstrProfError>(
1601 instrprof_error::unknown_function,
1602 "memprof record not found for function hash " + Twine(FuncNameHash));
1604 const memprof::IndexedMemProfRecord &IndexedRecord = *Iter;
1605 switch (Version) {
1606 case memprof::Version2:
1607 assert(MemProfFrameTable && "MemProfFrameTable must be available");
1608 assert(MemProfCallStackTable && "MemProfCallStackTable must be available");
1609 return getMemProfRecordV2(IndexedRecord, *MemProfFrameTable,
1610 *MemProfCallStackTable);
1611 case memprof::Version3:
1612 assert(!MemProfFrameTable && "MemProfFrameTable must not be available");
1613 assert(!MemProfCallStackTable &&
1614 "MemProfCallStackTable must not be available");
1615 assert(FrameBase && "FrameBase must be available");
1616 assert(CallStackBase && "CallStackBase must be available");
1617 return getMemProfRecordV3(IndexedRecord, FrameBase, CallStackBase);
1620 return make_error<InstrProfError>(
1621 instrprof_error::unsupported_version,
1622 formatv("MemProf version {} not supported; "
1623 "requires version between {} and {}, inclusive",
1624 Version, memprof::MinimumSupportedVersion,
1625 memprof::MaximumSupportedVersion));
1628 DenseMap<uint64_t, SmallVector<memprof::CallEdgeTy, 0>>
1629 IndexedMemProfReader::getMemProfCallerCalleePairs() const {
1630 assert(MemProfRecordTable);
1631 assert(Version == memprof::Version3);
1633 memprof::LinearFrameIdConverter FrameIdConv(FrameBase);
1634 memprof::CallerCalleePairExtractor Extractor(CallStackBase, FrameIdConv,
1635 RadixTreeSize);
1637 // The set of linear call stack IDs that we need to traverse from. We expect
1638 // the set to be dense, so we use a BitVector.
1639 BitVector Worklist(RadixTreeSize);
1641 // Collect the set of linear call stack IDs. Since we expect a lot of
1642 // duplicates, we first collect them in the form of a bit vector before
1643 // processing them.
1644 for (const memprof::IndexedMemProfRecord &IndexedRecord :
1645 MemProfRecordTable->data()) {
1646 for (const memprof::IndexedAllocationInfo &IndexedAI :
1647 IndexedRecord.AllocSites)
1648 Worklist.set(IndexedAI.CSId);
1651 // Collect caller-callee pairs for each linear call stack ID in Worklist.
1652 for (unsigned CS : Worklist.set_bits())
1653 Extractor(CS);
1655 DenseMap<uint64_t, SmallVector<memprof::CallEdgeTy, 0>> Pairs =
1656 std::move(Extractor.CallerCalleePairs);
1658 // Sort each call list by the source location.
1659 for (auto &[CallerGUID, CallList] : Pairs) {
1660 llvm::sort(CallList);
1661 CallList.erase(llvm::unique(CallList), CallList.end());
1664 return Pairs;
1667 memprof::AllMemProfData IndexedMemProfReader::getAllMemProfData() const {
1668 memprof::AllMemProfData AllMemProfData;
1669 AllMemProfData.HeapProfileRecords.reserve(
1670 MemProfRecordTable->getNumEntries());
1671 for (uint64_t Key : MemProfRecordTable->keys()) {
1672 auto Record = getMemProfRecord(Key);
1673 if (Record.takeError())
1674 continue;
1675 memprof::GUIDMemProfRecordPair Pair;
1676 Pair.GUID = Key;
1677 Pair.Record = std::move(*Record);
1678 AllMemProfData.HeapProfileRecords.push_back(std::move(Pair));
1680 return AllMemProfData;
1683 Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
1684 uint64_t FuncHash,
1685 std::vector<uint64_t> &Counts) {
1686 Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
1687 if (Error E = Record.takeError())
1688 return error(std::move(E));
1690 Counts = Record.get().Counts;
1691 return success();
1694 Error IndexedInstrProfReader::getFunctionBitmap(StringRef FuncName,
1695 uint64_t FuncHash,
1696 BitVector &Bitmap) {
1697 Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
1698 if (Error E = Record.takeError())
1699 return error(std::move(E));
1701 const auto &BitmapBytes = Record.get().BitmapBytes;
1702 size_t I = 0, E = BitmapBytes.size();
1703 Bitmap.resize(E * CHAR_BIT);
1704 BitVector::apply(
1705 [&](auto X) {
1706 using XTy = decltype(X);
1707 alignas(XTy) uint8_t W[sizeof(X)];
1708 size_t N = std::min(E - I, sizeof(W));
1709 std::memset(W, 0, sizeof(W));
1710 std::memcpy(W, &BitmapBytes[I], N);
1711 I += N;
1712 return support::endian::read<XTy, llvm::endianness::little,
1713 support::aligned>(W);
1715 Bitmap, Bitmap);
1716 assert(I == E);
1718 return success();
1721 Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
1722 ArrayRef<NamedInstrProfRecord> Data;
1724 Error E = Index->getRecords(Data);
1725 if (E)
1726 return error(std::move(E));
1728 Record = Data[RecordIndex++];
1729 if (RecordIndex >= Data.size()) {
1730 Index->advanceToNextKey();
1731 RecordIndex = 0;
1733 return success();
1736 Error IndexedInstrProfReader::readBinaryIds(
1737 std::vector<llvm::object::BuildID> &BinaryIds) {
1738 return readBinaryIdsInternal(*DataBuffer, BinaryIdsBuffer, BinaryIds,
1739 llvm::endianness::little);
1742 Error IndexedInstrProfReader::printBinaryIds(raw_ostream &OS) {
1743 std::vector<llvm::object::BuildID> BinaryIds;
1744 if (Error E = readBinaryIds(BinaryIds))
1745 return E;
1746 printBinaryIdsInternal(OS, BinaryIds);
1747 return Error::success();
1750 void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) {
1751 uint64_t NumFuncs = 0;
1752 for (const auto &Func : *this) {
1753 if (isIRLevelProfile()) {
1754 bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
1755 if (FuncIsCS != IsCS)
1756 continue;
1758 Func.accumulateCounts(Sum);
1759 ++NumFuncs;
1761 Sum.NumEntries = NumFuncs;