LLVM 19.0.0git
InstrProfReader.cpp
Go to the documentation of this file.
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.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/ArrayRef.h"
16#include "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/StringRef.h"
24#include "llvm/Support/Endian.h"
25#include "llvm/Support/Error.h"
31#include <algorithm>
32#include <cstddef>
33#include <cstdint>
34#include <limits>
35#include <memory>
36#include <optional>
37#include <system_error>
38#include <utility>
39#include <vector>
40
41using namespace llvm;
42
43// Extracts the variant information from the top 32 bits in the version and
44// returns an enum specifying the variants present.
46 InstrProfKind ProfileKind = InstrProfKind::Unknown;
47 if (Version & VARIANT_MASK_IR_PROF) {
48 ProfileKind |= InstrProfKind::IRInstrumentation;
49 }
50 if (Version & VARIANT_MASK_CSIR_PROF) {
51 ProfileKind |= InstrProfKind::ContextSensitive;
52 }
53 if (Version & VARIANT_MASK_INSTR_ENTRY) {
54 ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
55 }
56 if (Version & VARIANT_MASK_BYTE_COVERAGE) {
57 ProfileKind |= InstrProfKind::SingleByteCoverage;
58 }
59 if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
60 ProfileKind |= InstrProfKind::FunctionEntryOnly;
61 }
62 if (Version & VARIANT_MASK_MEMPROF) {
63 ProfileKind |= InstrProfKind::MemProf;
64 }
65 if (Version & VARIANT_MASK_TEMPORAL_PROF) {
66 ProfileKind |= InstrProfKind::TemporalProfile;
67 }
68 return ProfileKind;
69}
70
73 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
74 : FS.getBufferForFile(Filename);
75 if (std::error_code EC = BufferOrErr.getError())
76 return errorCodeToError(EC);
77 return std::move(BufferOrErr.get());
78}
79
81 return Reader.readHeader();
82}
83
84/// Read a list of binary ids from a profile that consist of
85/// a. uint64_t binary id length
86/// b. uint8_t binary id data
87/// c. uint8_t padding (if necessary)
88/// This function is shared between raw and indexed profiles.
89/// Raw profiles are in host-endian format, and indexed profiles are in
90/// little-endian format. So, this function takes an argument indicating the
91/// associated endian format to read the binary ids correctly.
92static Error
94 const uint64_t BinaryIdsSize,
95 const uint8_t *BinaryIdsStart,
96 std::vector<llvm::object::BuildID> &BinaryIds,
97 const llvm::endianness Endian) {
98 using namespace support;
99
100 if (BinaryIdsSize == 0)
101 return Error::success();
102
103 const uint8_t *BI = BinaryIdsStart;
104 const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
105 const uint8_t *End =
106 reinterpret_cast<const uint8_t *>(DataBuffer.getBufferEnd());
107
108 while (BI < BIEnd) {
109 size_t Remaining = BIEnd - BI;
110 // There should be enough left to read the binary id length.
111 if (Remaining < sizeof(uint64_t))
112 return make_error<InstrProfError>(
113 instrprof_error::malformed,
114 "not enough data to read binary id length");
115
116 uint64_t BILen = 0;
118 BILen = endian::readNext<uint64_t, llvm::endianness::little>(BI);
119 else
120 BILen = endian::readNext<uint64_t, llvm::endianness::big>(BI);
121
122 if (BILen == 0)
123 return make_error<InstrProfError>(instrprof_error::malformed,
124 "binary id length is 0");
125
126 Remaining = BIEnd - BI;
127 // There should be enough left to read the binary id data.
128 if (Remaining < alignToPowerOf2(BILen, sizeof(uint64_t)))
129 return make_error<InstrProfError>(
130 instrprof_error::malformed, "not enough data to read binary id data");
131
132 // Add binary id to the binary ids list.
133 BinaryIds.push_back(object::BuildID(BI, BI + BILen));
134
135 // Increment by binary id data length, which aligned to the size of uint64.
136 BI += alignToPowerOf2(BILen, sizeof(uint64_t));
137 if (BI > End)
138 return make_error<InstrProfError>(
139 instrprof_error::malformed,
140 "binary id section is greater than buffer size");
141 }
142
143 return Error::success();
144}
145
146static void
148 std::vector<llvm::object::BuildID> &BinaryIds) {
149 OS << "Binary IDs: \n";
150 for (auto BI : BinaryIds) {
151 for (uint64_t I = 0; I < BI.size(); I++)
152 OS << format("%02x", BI[I]);
153 OS << "\n";
154 }
155}
156
159 const InstrProfCorrelator *Correlator,
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 Warn);
167}
168
170InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
171 const InstrProfCorrelator *Correlator,
172 std::function<void(Error)> Warn) {
173 if (Buffer->getBufferSize() == 0)
174 return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
175
176 std::unique_ptr<InstrProfReader> Result;
177 // Create the reader.
179 Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
180 else if (RawInstrProfReader64::hasFormat(*Buffer))
181 Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn));
182 else if (RawInstrProfReader32::hasFormat(*Buffer))
183 Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn));
184 else if (TextInstrProfReader::hasFormat(*Buffer))
185 Result.reset(new TextInstrProfReader(std::move(Buffer)));
186 else
187 return make_error<InstrProfError>(instrprof_error::unrecognized_format);
188
189 // Initialize the reader and return the result.
190 if (Error E = initializeReader(*Result))
191 return std::move(E);
192
193 return std::move(Result);
194}
195
198 const Twine &RemappingPath) {
199 // Set up the buffer to read.
200 auto BufferOrError = setupMemoryBuffer(Path, FS);
201 if (Error E = BufferOrError.takeError())
202 return std::move(E);
203
204 // Set up the remapping buffer if requested.
205 std::unique_ptr<MemoryBuffer> RemappingBuffer;
206 std::string RemappingPathStr = RemappingPath.str();
207 if (!RemappingPathStr.empty()) {
208 auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS);
209 if (Error E = RemappingBufferOrError.takeError())
210 return std::move(E);
211 RemappingBuffer = std::move(RemappingBufferOrError.get());
212 }
213
214 return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
215 std::move(RemappingBuffer));
216}
217
219IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
220 std::unique_ptr<MemoryBuffer> RemappingBuffer) {
221 // Create the reader.
223 return make_error<InstrProfError>(instrprof_error::bad_magic);
224 auto Result = std::make_unique<IndexedInstrProfReader>(
225 std::move(Buffer), std::move(RemappingBuffer));
226
227 // Initialize the reader and return the result.
228 if (Error E = initializeReader(*Result))
229 return std::move(E);
230
231 return std::move(Result);
232}
233
235 // Verify that this really looks like plain ASCII text by checking a
236 // 'reasonable' number of characters (up to profile magic size).
237 size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
238 StringRef buffer = Buffer.getBufferStart();
239 return count == 0 ||
240 std::all_of(buffer.begin(), buffer.begin() + count,
241 [](char c) { return isPrint(c) || isSpace(c); });
242}
243
244// Read the profile variant flag from the header: ":FE" means this is a FE
245// generated profile. ":IR" means this is an IR level profile. Other strings
246// with a leading ':' will be reported an error format.
248 Symtab.reset(new InstrProfSymtab());
249
250 while (Line->starts_with(":")) {
251 StringRef Str = Line->substr(1);
252 if (Str.equals_insensitive("ir"))
254 else if (Str.equals_insensitive("fe"))
256 else if (Str.equals_insensitive("csir")) {
258 ProfileKind |= InstrProfKind::ContextSensitive;
259 } else if (Str.equals_insensitive("entry_first"))
261 else if (Str.equals_insensitive("not_entry_first"))
263 else if (Str.equals_insensitive("single_byte_coverage"))
265 else if (Str.equals_insensitive("temporal_prof_traces")) {
266 ProfileKind |= InstrProfKind::TemporalProfile;
267 if (auto Err = readTemporalProfTraceData())
268 return error(std::move(Err));
269 } else
271 ++Line;
272 }
273 return success();
274}
275
276/// Temporal profile trace data is stored in the header immediately after
277/// ":temporal_prof_traces". The first integer is the number of traces, the
278/// second integer is the stream size, then the following lines are the actual
279/// traces which consist of a weight and a comma separated list of function
280/// names.
281Error TextInstrProfReader::readTemporalProfTraceData() {
282 if ((++Line).is_at_end())
284
285 uint32_t NumTraces;
286 if (Line->getAsInteger(0, NumTraces))
288
289 if ((++Line).is_at_end())
291
294
295 for (uint32_t i = 0; i < NumTraces; i++) {
296 if ((++Line).is_at_end())
298
300 if (Line->getAsInteger(0, Trace.Weight))
302
303 if ((++Line).is_at_end())
305
306 SmallVector<StringRef> FuncNames;
307 Line->split(FuncNames, ",", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
308 for (auto &FuncName : FuncNames)
309 Trace.FunctionNameRefs.push_back(
310 IndexedInstrProf::ComputeHash(FuncName.trim()));
311 TemporalProfTraces.push_back(std::move(Trace));
312 }
313 return success();
314}
315
316Error
317TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
318
319#define CHECK_LINE_END(Line) \
320 if (Line.is_at_end()) \
321 return error(instrprof_error::truncated);
322#define READ_NUM(Str, Dst) \
323 if ((Str).getAsInteger(10, (Dst))) \
324 return error(instrprof_error::malformed);
325#define VP_READ_ADVANCE(Val) \
326 CHECK_LINE_END(Line); \
327 uint32_t Val; \
328 READ_NUM((*Line), (Val)); \
329 Line++;
330
331 if (Line.is_at_end())
332 return success();
333
334 uint32_t NumValueKinds;
335 if (Line->getAsInteger(10, NumValueKinds)) {
336 // No value profile data
337 return success();
338 }
339 if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
341 "number of value kinds is invalid");
342 Line++;
343
344 for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
345 VP_READ_ADVANCE(ValueKind);
346 if (ValueKind > IPVK_Last)
347 return error(instrprof_error::malformed, "value kind is invalid");
348 ;
349 VP_READ_ADVANCE(NumValueSites);
350 if (!NumValueSites)
351 continue;
352
353 Record.reserveSites(VK, NumValueSites);
354 for (uint32_t S = 0; S < NumValueSites; S++) {
355 VP_READ_ADVANCE(NumValueData);
356
357 std::vector<InstrProfValueData> CurrentValues;
358 for (uint32_t V = 0; V < NumValueData; V++) {
359 CHECK_LINE_END(Line);
360 std::pair<StringRef, StringRef> VD = Line->rsplit(':');
361 uint64_t TakenCount, Value;
362 if (ValueKind == IPVK_IndirectCallTarget) {
363 if (InstrProfSymtab::isExternalSymbol(VD.first)) {
364 Value = 0;
365 } else {
366 if (Error E = Symtab->addFuncName(VD.first))
367 return E;
369 }
370 } else if (ValueKind == IPVK_VTableTarget) {
372 Value = 0;
373 else {
374 if (Error E = Symtab->addVTableName(VD.first))
375 return E;
377 }
378 } else {
379 READ_NUM(VD.first, Value);
380 }
381 READ_NUM(VD.second, TakenCount);
382 CurrentValues.push_back({Value, TakenCount});
383 Line++;
384 }
385 Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData,
386 nullptr);
387 }
388 }
389 return success();
390
391#undef CHECK_LINE_END
392#undef READ_NUM
393#undef VP_READ_ADVANCE
394}
395
397 // Skip empty lines and comments.
398 while (!Line.is_at_end() && (Line->empty() || Line->starts_with("#")))
399 ++Line;
400 // If we hit EOF while looking for a name, we're done.
401 if (Line.is_at_end()) {
403 }
404
405 // Read the function name.
406 Record.Name = *Line++;
407 if (Error E = Symtab->addFuncName(Record.Name))
408 return error(std::move(E));
409
410 // Read the function hash.
411 if (Line.is_at_end())
413 if ((Line++)->getAsInteger(0, Record.Hash))
415 "function hash is not a valid integer");
416
417 // Read the number of counters.
418 uint64_t NumCounters;
419 if (Line.is_at_end())
421 if ((Line++)->getAsInteger(10, NumCounters))
423 "number of counters is not a valid integer");
424 if (NumCounters == 0)
425 return error(instrprof_error::malformed, "number of counters is zero");
426
427 // Read each counter and fill our internal storage with the values.
428 Record.Clear();
429 Record.Counts.reserve(NumCounters);
430 for (uint64_t I = 0; I < NumCounters; ++I) {
431 if (Line.is_at_end())
433 uint64_t Count;
434 if ((Line++)->getAsInteger(10, Count))
435 return error(instrprof_error::malformed, "count is invalid");
436 Record.Counts.push_back(Count);
437 }
438
439 // Bitmap byte information is indicated with special character.
440 if (Line->starts_with("$")) {
441 Record.BitmapBytes.clear();
442 // Read the number of bitmap bytes.
443 uint64_t NumBitmapBytes;
444 if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes))
446 "number of bitmap bytes is not a valid integer");
447 if (NumBitmapBytes != 0) {
448 // Read each bitmap and fill our internal storage with the values.
449 Record.BitmapBytes.reserve(NumBitmapBytes);
450 for (uint8_t I = 0; I < NumBitmapBytes; ++I) {
451 if (Line.is_at_end())
453 uint8_t BitmapByte;
454 if ((Line++)->getAsInteger(0, BitmapByte))
456 "bitmap byte is not a valid integer");
457 Record.BitmapBytes.push_back(BitmapByte);
458 }
459 }
460 }
461
462 // Check if value profile data exists and read it if so.
463 if (Error E = readValueProfileData(Record))
464 return error(std::move(E));
465
466 return success();
467}
468
469template <class IntPtrT>
471 return getProfileKindFromVersion(Version);
472}
473
474template <class IntPtrT>
477 std::optional<uint64_t> Weight) {
478 if (TemporalProfTimestamps.empty()) {
479 assert(TemporalProfTraces.empty());
480 return TemporalProfTraces;
481 }
482 // Sort functions by their timestamps to build the trace.
483 std::sort(TemporalProfTimestamps.begin(), TemporalProfTimestamps.end());
485 if (Weight)
486 Trace.Weight = *Weight;
487 for (auto &[TimestampValue, NameRef] : TemporalProfTimestamps)
488 Trace.FunctionNameRefs.push_back(NameRef);
489 TemporalProfTraces = {std::move(Trace)};
490 return TemporalProfTraces;
491}
492
493template <class IntPtrT>
495 if (DataBuffer.getBufferSize() < sizeof(uint64_t))
496 return false;
497 uint64_t Magic =
498 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
499 return RawInstrProf::getMagic<IntPtrT>() == Magic ||
500 llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic;
501}
502
503template <class IntPtrT>
505 if (!hasFormat(*DataBuffer))
507 if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
509 auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
510 DataBuffer->getBufferStart());
511 ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
512 return readHeader(*Header);
513}
514
515template <class IntPtrT>
517 const char *End = DataBuffer->getBufferEnd();
518 // Skip zero padding between profiles.
519 while (CurrentPos != End && *CurrentPos == 0)
520 ++CurrentPos;
521 // If there's nothing left, we're done.
522 if (CurrentPos == End)
523 return make_error<InstrProfError>(instrprof_error::eof);
524 // If there isn't enough space for another header, this is probably just
525 // garbage at the end of the file.
526 if (CurrentPos + sizeof(RawInstrProf::Header) > End)
527 return make_error<InstrProfError>(instrprof_error::malformed,
528 "not enough space for another header");
529 // The writer ensures each profile is padded to start at an aligned address.
530 if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
531 return make_error<InstrProfError>(instrprof_error::malformed,
532 "insufficient padding");
533 // The magic should have the same byte order as in the previous header.
534 uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
535 if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
536 return make_error<InstrProfError>(instrprof_error::bad_magic);
537
538 // There's another profile to read, so we need to process the header.
539 auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
540 return readHeader(*Header);
541}
542
543template <class IntPtrT>
545 if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart),
546 StringRef(VNamesStart, VNamesEnd - VNamesStart)))
547 return error(std::move(E));
548 for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
549 const IntPtrT FPtr = swap(I->FunctionPointer);
550 if (!FPtr)
551 continue;
552 Symtab.mapAddress(FPtr, swap(I->NameRef));
553 }
554
555 if (VTableBegin != nullptr && VTableEnd != nullptr) {
556 for (const RawInstrProf::VTableProfileData<IntPtrT> *I = VTableBegin;
557 I != VTableEnd; ++I) {
558 const IntPtrT VPtr = swap(I->VTablePointer);
559 if (!VPtr)
560 continue;
561 // Map both begin and end address to the name hash, since the instrumented
562 // address could be somewhere in the middle.
563 // VPtr is of type uint32_t or uint64_t so 'VPtr + I->VTableSize' marks
564 // the end of vtable address.
565 Symtab.mapVTableAddress(VPtr, VPtr + swap(I->VTableSize),
566 swap(I->VTableNameHash));
567 }
568 }
569 return success();
570}
571
572template <class IntPtrT>
574 const RawInstrProf::Header &Header) {
575 Version = swap(Header.Version);
576 if (GET_VERSION(Version) != RawInstrProf::Version)
578 ("Profile uses raw profile format version = " +
579 Twine(GET_VERSION(Version)) +
580 "; expected version = " + Twine(RawInstrProf::Version) +
581 "\nPLEASE update this tool to version in the raw profile, or "
582 "regenerate raw profile with expected version.")
583 .str());
584
585 uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
586 // Binary id start just after the header if exists.
587 const uint8_t *BinaryIdStart =
588 reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
589 const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
590 const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
591 if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
593 if (BinaryIdSize != 0) {
594 if (Error Err =
595 readBinaryIdsInternal(*DataBuffer, BinaryIdSize, BinaryIdStart,
596 BinaryIds, getDataEndianness()))
597 return Err;
598 }
599
600 CountersDelta = swap(Header.CountersDelta);
601 BitmapDelta = swap(Header.BitmapDelta);
602 NamesDelta = swap(Header.NamesDelta);
603 auto NumData = swap(Header.NumData);
604 auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
605 auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize();
606 auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
607 auto NumBitmapBytes = swap(Header.NumBitmapBytes);
608 auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes);
609 auto NamesSize = swap(Header.NamesSize);
610 auto VTableNameSize = swap(Header.VNamesSize);
611 auto NumVTables = swap(Header.NumVTables);
612 ValueKindLast = swap(Header.ValueKindLast);
613
614 auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
615 auto PaddingBytesAfterNames = getNumPaddingBytes(NamesSize);
616 auto PaddingBytesAfterVTableNames = getNumPaddingBytes(VTableNameSize);
617
618 auto VTableSectionSize =
619 NumVTables * sizeof(RawInstrProf::VTableProfileData<IntPtrT>);
620 auto PaddingBytesAfterVTableProfData = getNumPaddingBytes(VTableSectionSize);
621
622 // Profile data starts after profile header and binary ids if exist.
623 ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdSize;
624 ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
625 ptrdiff_t BitmapOffset =
626 CountersOffset + CountersSize + PaddingBytesAfterCounters;
627 ptrdiff_t NamesOffset =
628 BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes;
629 ptrdiff_t VTableProfDataOffset =
630 NamesOffset + NamesSize + PaddingBytesAfterNames;
631 ptrdiff_t VTableNameOffset = VTableProfDataOffset + VTableSectionSize +
632 PaddingBytesAfterVTableProfData;
633 ptrdiff_t ValueDataOffset =
634 VTableNameOffset + VTableNameSize + PaddingBytesAfterVTableNames;
635
636 auto *Start = reinterpret_cast<const char *>(&Header);
637 if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
639
640 if (Correlator) {
641 // These sizes in the raw file are zero because we constructed them in the
642 // Correlator.
643 if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 &&
644 NamesDelta == 0))
646 Data = Correlator->getDataPointer();
647 DataEnd = Data + Correlator->getDataSize();
648 NamesStart = Correlator->getNamesPointer();
649 NamesEnd = NamesStart + Correlator->getNamesSize();
650 } else {
651 Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
652 Start + DataOffset);
653 DataEnd = Data + NumData;
654 VTableBegin =
655 reinterpret_cast<const RawInstrProf::VTableProfileData<IntPtrT> *>(
656 Start + VTableProfDataOffset);
657 VTableEnd = VTableBegin + NumVTables;
658 NamesStart = Start + NamesOffset;
659 NamesEnd = NamesStart + NamesSize;
660 VNamesStart = Start + VTableNameOffset;
661 VNamesEnd = VNamesStart + VTableNameSize;
662 }
663
664 CountersStart = Start + CountersOffset;
665 CountersEnd = CountersStart + CountersSize;
666 BitmapStart = Start + BitmapOffset;
667 BitmapEnd = BitmapStart + NumBitmapBytes;
668 ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
669
670 std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
671 if (Error E = createSymtab(*NewSymtab))
672 return E;
673
674 Symtab = std::move(NewSymtab);
675 return success();
676}
677
678template <class IntPtrT>
680 Record.Name = getName(Data->NameRef);
681 return success();
682}
683
684template <class IntPtrT>
686 Record.Hash = swap(Data->FuncHash);
687 return success();
688}
689
690template <class IntPtrT>
693 uint32_t NumCounters = swap(Data->NumCounters);
694 if (NumCounters == 0)
695 return error(instrprof_error::malformed, "number of counters is zero");
696
697 ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
698 if (CounterBaseOffset < 0)
699 return error(
701 ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
702
703 if (CounterBaseOffset >= CountersEnd - CountersStart)
705 ("counter offset " + Twine(CounterBaseOffset) +
706 " is greater than the maximum counter offset " +
707 Twine(CountersEnd - CountersStart - 1))
708 .str());
709
710 uint64_t MaxNumCounters =
711 (CountersEnd - (CountersStart + CounterBaseOffset)) /
712 getCounterTypeSize();
713 if (NumCounters > MaxNumCounters)
715 ("number of counters " + Twine(NumCounters) +
716 " is greater than the maximum number of counters " +
717 Twine(MaxNumCounters))
718 .str());
719
720 Record.Counts.clear();
721 Record.Counts.reserve(NumCounters);
722 for (uint32_t I = 0; I < NumCounters; I++) {
723 const char *Ptr =
724 CountersStart + CounterBaseOffset + I * getCounterTypeSize();
725 if (I == 0 && hasTemporalProfile()) {
726 uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
727 if (TimestampValue != 0 &&
728 TimestampValue != std::numeric_limits<uint64_t>::max()) {
729 TemporalProfTimestamps.emplace_back(TimestampValue,
730 swap(Data->NameRef));
731 TemporalProfTraceStreamSize = 1;
732 }
733 if (hasSingleByteCoverage()) {
734 // In coverage mode, getCounterTypeSize() returns 1 byte but our
735 // timestamp field has size uint64_t. Increment I so that the next
736 // iteration of this for loop points to the byte after the timestamp
737 // field, i.e., I += 8.
738 I += 7;
739 }
740 continue;
741 }
742 if (hasSingleByteCoverage()) {
743 // A value of zero signifies the block is covered.
744 Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
745 } else {
746 uint64_t CounterValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
747 if (CounterValue > MaxCounterValue && Warn)
748 Warn(make_error<InstrProfError>(
750
751 Record.Counts.push_back(CounterValue);
752 }
753 }
754
755 return success();
756}
757
758template <class IntPtrT>
760 uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
761
762 Record.BitmapBytes.clear();
763 Record.BitmapBytes.reserve(NumBitmapBytes);
764
765 // It's possible MCDC is either not enabled or only used for some functions
766 // and not others. So if we record 0 bytes, just move on.
767 if (NumBitmapBytes == 0)
768 return success();
769
770 // BitmapDelta decreases as we advance to the next data record.
771 ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
772 if (BitmapOffset < 0)
773 return error(
775 ("bitmap offset " + Twine(BitmapOffset) + " is negative").str());
776
777 if (BitmapOffset >= BitmapEnd - BitmapStart)
779 ("bitmap offset " + Twine(BitmapOffset) +
780 " is greater than the maximum bitmap offset " +
781 Twine(BitmapEnd - BitmapStart - 1))
782 .str());
783
784 uint64_t MaxNumBitmapBytes =
785 (BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t);
786 if (NumBitmapBytes > MaxNumBitmapBytes)
788 ("number of bitmap bytes " + Twine(NumBitmapBytes) +
789 " is greater than the maximum number of bitmap bytes " +
790 Twine(MaxNumBitmapBytes))
791 .str());
792
793 for (uint32_t I = 0; I < NumBitmapBytes; I++) {
794 const char *Ptr = BitmapStart + BitmapOffset + I;
795 Record.BitmapBytes.push_back(swap(*Ptr));
796 }
797
798 return success();
799}
800
801template <class IntPtrT>
804 Record.clearValueData();
805 CurValueDataSize = 0;
806 // Need to match the logic in value profile dumper code in compiler-rt:
807 uint32_t NumValueKinds = 0;
808 for (uint32_t I = 0; I < IPVK_Last + 1; I++)
809 NumValueKinds += (Data->NumValueSites[I] != 0);
810
811 if (!NumValueKinds)
812 return success();
813
815 ValueProfData::getValueProfData(
816 ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
817 getDataEndianness());
818
819 if (Error E = VDataPtrOrErr.takeError())
820 return E;
821
822 // Note that besides deserialization, this also performs the conversion for
823 // indirect call targets. The function pointers from the raw profile are
824 // remapped into function name hashes.
825 VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
826 CurValueDataSize = VDataPtrOrErr.get()->getSize();
827 return success();
828}
829
830template <class IntPtrT>
832 // Keep reading profiles that consist of only headers and no profile data and
833 // counters.
834 while (atEnd())
835 // At this point, ValueDataStart field points to the next header.
836 if (Error E = readNextHeader(getNextHeaderPos()))
837 return error(std::move(E));
838
839 // Read name and set it in Record.
840 if (Error E = readName(Record))
841 return error(std::move(E));
842
843 // Read FuncHash and set it in Record.
844 if (Error E = readFuncHash(Record))
845 return error(std::move(E));
846
847 // Read raw counts and set Record.
848 if (Error E = readRawCounts(Record))
849 return error(std::move(E));
850
851 // Read raw bitmap bytes and set Record.
852 if (Error E = readRawBitmapBytes(Record))
853 return error(std::move(E));
854
855 // Read value data and set Record.
856 if (Error E = readValueProfilingData(Record))
857 return error(std::move(E));
858
859 // Iterate.
860 advanceData();
861 return success();
862}
863
864template <class IntPtrT>
866 std::vector<llvm::object::BuildID> &BinaryIds) {
867 BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(),
868 this->BinaryIds.end());
869 return Error::success();
870}
871
872template <class IntPtrT>
874 if (!BinaryIds.empty())
875 printBinaryIdsInternal(OS, BinaryIds);
876 return Error::success();
877}
878
879namespace llvm {
880
881template class RawInstrProfReader<uint32_t>;
882template class RawInstrProfReader<uint64_t>;
883
884} // end namespace llvm
885
888 return IndexedInstrProf::ComputeHash(HashType, K);
889}
890
893
895 const unsigned char *&D, const unsigned char *const End) {
897 ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
898
899 if (VDataPtrOrErr.takeError())
900 return false;
901
902 VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
903 D += VDataPtrOrErr.get()->TotalSize;
904
905 return true;
906}
907
909 offset_type N) {
910 using namespace support;
911
912 // Check if the data is corrupt. If so, don't try to read it.
913 if (N % sizeof(uint64_t))
914 return data_type();
915
916 DataBuffer.clear();
917 std::vector<uint64_t> CounterBuffer;
918 std::vector<uint8_t> BitmapByteBuffer;
919
920 const unsigned char *End = D + N;
921 while (D < End) {
922 // Read hash.
923 if (D + sizeof(uint64_t) >= End)
924 return data_type();
925 uint64_t Hash = endian::readNext<uint64_t, llvm::endianness::little>(D);
926
927 // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
928 uint64_t CountsSize = N / sizeof(uint64_t) - 1;
929 // If format version is different then read the number of counters.
930 if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
931 if (D + sizeof(uint64_t) > End)
932 return data_type();
933 CountsSize = endian::readNext<uint64_t, llvm::endianness::little>(D);
934 }
935 // Read counter values.
936 if (D + CountsSize * sizeof(uint64_t) > End)
937 return data_type();
938
939 CounterBuffer.clear();
940 CounterBuffer.reserve(CountsSize);
941 for (uint64_t J = 0; J < CountsSize; ++J)
942 CounterBuffer.push_back(
943 endian::readNext<uint64_t, llvm::endianness::little>(D));
944
945 // Read bitmap bytes for GET_VERSION(FormatVersion) > 10.
946 if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) {
947 uint64_t BitmapBytes = 0;
948 if (D + sizeof(uint64_t) > End)
949 return data_type();
950 BitmapBytes = endian::readNext<uint64_t, llvm::endianness::little>(D);
951 // Read bitmap byte values.
952 if (D + BitmapBytes * sizeof(uint8_t) > End)
953 return data_type();
954 BitmapByteBuffer.clear();
955 BitmapByteBuffer.reserve(BitmapBytes);
956 for (uint64_t J = 0; J < BitmapBytes; ++J)
957 BitmapByteBuffer.push_back(static_cast<uint8_t>(
958 endian::readNext<uint64_t, llvm::endianness::little>(D)));
959 }
960
961 DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer),
962 std::move(BitmapByteBuffer));
963
964 // Read value profiling data.
965 if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
967 DataBuffer.clear();
968 return data_type();
969 }
970 }
971 return DataBuffer;
972}
973
974template <typename HashTableImpl>
977 auto Iter = HashTable->find(FuncName);
978 if (Iter == HashTable->end())
979 return make_error<InstrProfError>(instrprof_error::unknown_function);
980
981 Data = (*Iter);
982 if (Data.empty())
983 return make_error<InstrProfError>(instrprof_error::malformed,
984 "profile data is empty");
985
986 return Error::success();
987}
988
989template <typename HashTableImpl>
992 if (atEnd())
993 return make_error<InstrProfError>(instrprof_error::eof);
994
995 Data = *RecordIterator;
996
997 if (Data.empty())
998 return make_error<InstrProfError>(instrprof_error::malformed,
999 "profile data is empty");
1000
1001 return Error::success();
1002}
1003
1004template <typename HashTableImpl>
1006 const unsigned char *Buckets, const unsigned char *const Payload,
1007 const unsigned char *const Base, IndexedInstrProf::HashT HashType,
1008 uint64_t Version) {
1009 FormatVersion = Version;
1010 HashTable.reset(HashTableImpl::Create(
1011 Buckets, Payload, Base,
1012 typename HashTableImpl::InfoType(HashType, Version)));
1013 RecordIterator = HashTable->data_begin();
1014}
1015
1016template <typename HashTableImpl>
1018 return getProfileKindFromVersion(FormatVersion);
1019}
1020
1021namespace {
1022/// A remapper that does not apply any remappings.
1023class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
1024 InstrProfReaderIndexBase &Underlying;
1025
1026public:
1027 InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
1028 : Underlying(Underlying) {}
1029
1030 Error getRecords(StringRef FuncName,
1031 ArrayRef<NamedInstrProfRecord> &Data) override {
1032 return Underlying.getRecords(FuncName, Data);
1033 }
1034};
1035} // namespace
1036
1037/// A remapper that applies remappings based on a symbol remapping file.
1038template <typename HashTableImpl>
1040 : public InstrProfReaderRemapper {
1041public:
1043 std::unique_ptr<MemoryBuffer> RemapBuffer,
1045 : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
1046 }
1047
1048 /// Extract the original function name from a PGO function name.
1050 // We can have multiple pieces separated by kGlobalIdentifierDelimiter (
1051 // semicolon now and colon in older profiles); there can be pieces both
1052 // before and after the mangled name. Find the first part that starts with
1053 // '_Z'; we'll assume that's the mangled name we want.
1054 std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
1055 while (true) {
1056 Parts = Parts.second.split(kGlobalIdentifierDelimiter);
1057 if (Parts.first.starts_with("_Z"))
1058 return Parts.first;
1059 if (Parts.second.empty())
1060 return Name;
1061 }
1062 }
1063
1064 /// Given a mangled name extracted from a PGO function name, and a new
1065 /// form for that mangled name, reconstitute the name.
1066 static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
1067 StringRef Replacement,
1068 SmallVectorImpl<char> &Out) {
1069 Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
1070 Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
1071 Out.insert(Out.end(), Replacement.begin(), Replacement.end());
1072 Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
1073 }
1074
1076 if (Error E = Remappings.read(*RemapBuffer))
1077 return E;
1078 for (StringRef Name : Underlying.HashTable->keys()) {
1079 StringRef RealName = extractName(Name);
1080 if (auto Key = Remappings.insert(RealName)) {
1081 // FIXME: We could theoretically map the same equivalence class to
1082 // multiple names in the profile data. If that happens, we should
1083 // return NamedInstrProfRecords from all of them.
1084 MappedNames.insert({Key, RealName});
1085 }
1086 }
1087 return Error::success();
1088 }
1089
1092 StringRef RealName = extractName(FuncName);
1093 if (auto Key = Remappings.lookup(RealName)) {
1094 StringRef Remapped = MappedNames.lookup(Key);
1095 if (!Remapped.empty()) {
1096 if (RealName.begin() == FuncName.begin() &&
1097 RealName.end() == FuncName.end())
1098 FuncName = Remapped;
1099 else {
1100 // Try rebuilding the name from the given remapping.
1101 SmallString<256> Reconstituted;
1102 reconstituteName(FuncName, RealName, Remapped, Reconstituted);
1103 Error E = Underlying.getRecords(Reconstituted, Data);
1104 if (!E)
1105 return E;
1106
1107 // If we failed because the name doesn't exist, fall back to asking
1108 // about the original name.
1109 if (Error Unhandled = handleErrors(
1110 std::move(E), [](std::unique_ptr<InstrProfError> Err) {
1111 return Err->get() == instrprof_error::unknown_function
1112 ? Error::success()
1113 : Error(std::move(Err));
1114 }))
1115 return Unhandled;
1116 }
1117 }
1118 }
1119 return Underlying.getRecords(FuncName, Data);
1120 }
1121
1122private:
1123 /// The memory buffer containing the remapping configuration. Remappings
1124 /// holds pointers into this buffer.
1125 std::unique_ptr<MemoryBuffer> RemapBuffer;
1126
1127 /// The mangling remapper.
1128 SymbolRemappingReader Remappings;
1129
1130 /// Mapping from mangled name keys to the name used for the key in the
1131 /// profile data.
1132 /// FIXME: Can we store a location within the on-disk hash table instead of
1133 /// redoing lookup?
1135
1136 /// The real profile data reader.
1138};
1139
1141 using namespace support;
1142
1143 if (DataBuffer.getBufferSize() < 8)
1144 return false;
1145 uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(
1146 DataBuffer.getBufferStart());
1147 // Verify that it's magical.
1148 return Magic == IndexedInstrProf::Magic;
1149}
1150
1151const unsigned char *
1152IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
1153 const unsigned char *Cur, bool UseCS) {
1154 using namespace IndexedInstrProf;
1155 using namespace support;
1156
1157 if (Version >= IndexedInstrProf::Version4) {
1158 const IndexedInstrProf::Summary *SummaryInLE =
1159 reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
1160 uint64_t NFields = endian::byte_swap<uint64_t, llvm::endianness::little>(
1161 SummaryInLE->NumSummaryFields);
1162 uint64_t NEntries = endian::byte_swap<uint64_t, llvm::endianness::little>(
1163 SummaryInLE->NumCutoffEntries);
1164 uint32_t SummarySize =
1165 IndexedInstrProf::Summary::getSize(NFields, NEntries);
1166 std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
1167 IndexedInstrProf::allocSummary(SummarySize);
1168
1169 const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
1170 uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
1171 for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
1172 Dst[I] = endian::byte_swap<uint64_t, llvm::endianness::little>(Src[I]);
1173
1174 SummaryEntryVector DetailedSummary;
1175 for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
1176 const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
1177 DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
1178 Ent.NumBlocks);
1179 }
1180 std::unique_ptr<llvm::ProfileSummary> &Summary =
1181 UseCS ? this->CS_Summary : this->Summary;
1182
1183 // initialize InstrProfSummary using the SummaryData from disk.
1184 Summary = std::make_unique<ProfileSummary>(
1186 DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
1187 SummaryData->get(Summary::MaxBlockCount),
1188 SummaryData->get(Summary::MaxInternalBlockCount),
1189 SummaryData->get(Summary::MaxFunctionCount),
1190 SummaryData->get(Summary::TotalNumBlocks),
1191 SummaryData->get(Summary::TotalNumFunctions));
1192 return Cur + SummarySize;
1193 } else {
1194 // The older versions do not support a profile summary. This just computes
1195 // an empty summary, which will not result in accurate hot/cold detection.
1196 // We would need to call addRecord for all NamedInstrProfRecords to get the
1197 // correct summary. However, this version is old (prior to early 2016) and
1198 // has not been supporting an accurate summary for several years.
1200 Summary = Builder.getSummary();
1201 return Cur;
1202 }
1203}
1204
1206 using namespace support;
1207
1208 const unsigned char *Start =
1209 (const unsigned char *)DataBuffer->getBufferStart();
1210 const unsigned char *Cur = Start;
1211 if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
1213
1214 auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
1215 if (!HeaderOr)
1216 return HeaderOr.takeError();
1217
1218 const IndexedInstrProf::Header *Header = &HeaderOr.get();
1219 Cur += Header->size();
1220
1221 Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
1222 /* UseCS */ false);
1223 if (Header->formatVersion() & VARIANT_MASK_CSIR_PROF)
1224 Cur =
1225 readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
1226 /* UseCS */ true);
1227 // Read the hash type and start offset.
1228 IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
1229 endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashType));
1230 if (HashType > IndexedInstrProf::HashT::Last)
1232
1233 uint64_t HashOffset =
1234 endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashOffset);
1235
1236 // The hash table with profile counts comes next.
1237 auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
1238 Start + HashOffset, Cur, Start, HashType, Header->formatVersion());
1239
1240 // The MemProfOffset field in the header is only valid when the format
1241 // version is higher than 8 (when it was introduced).
1242 if (GET_VERSION(Header->formatVersion()) >= 8 &&
1243 Header->formatVersion() & VARIANT_MASK_MEMPROF) {
1244 uint64_t MemProfOffset =
1245 endian::byte_swap<uint64_t, llvm::endianness::little>(
1246 Header->MemProfOffset);
1247
1248 const unsigned char *Ptr = Start + MemProfOffset;
1249
1250 // Read the first 64-bit word, which may be RecordTableOffset in
1251 // memprof::MemProfVersion0 or the MemProf version number in
1252 // memprof::MemProfVersion1.
1253 const uint64_t FirstWord =
1254 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1255
1257 if (FirstWord == memprof::Version1) {
1258 // Everything is good. We can proceed to deserialize the rest.
1259 Version = memprof::Version1;
1260 } else if (FirstWord >= 24) {
1261 // This is a heuristic/hack to detect memprof::MemProfVersion0,
1262 // which does not have a version field in the header.
1263 // In memprof::MemProfVersion0, FirstWord will be RecordTableOffset,
1264 // which should be at least 24 because of the MemProf header size.
1265 Version = memprof::Version0;
1266 } else {
1267 return make_error<InstrProfError>(
1269 formatv("MemProf version {} not supported; "
1270 "requires version between {} and {}, inclusive",
1273 }
1274
1275 // The value returned from RecordTableGenerator.Emit.
1276 const uint64_t RecordTableOffset =
1277 Version == memprof::Version0
1278 ? FirstWord
1279 : support::endian::readNext<uint64_t, llvm::endianness::little>(
1280 Ptr);
1281 // The offset in the stream right before invoking
1282 // FrameTableGenerator.Emit.
1283 const uint64_t FramePayloadOffset =
1284 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1285 // The value returned from FrameTableGenerator.Emit.
1286 const uint64_t FrameTableOffset =
1287 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1288
1289 // Read the schema.
1290 auto SchemaOr = memprof::readMemProfSchema(Ptr);
1291 if (!SchemaOr)
1292 return SchemaOr.takeError();
1293 Schema = SchemaOr.get();
1294
1295 // Now initialize the table reader with a pointer into data buffer.
1296 MemProfRecordTable.reset(MemProfRecordHashTable::Create(
1297 /*Buckets=*/Start + RecordTableOffset,
1298 /*Payload=*/Ptr,
1299 /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version1, Schema)));
1300
1301 // Initialize the frame table reader with the payload and bucket offsets.
1302 MemProfFrameTable.reset(MemProfFrameHashTable::Create(
1303 /*Buckets=*/Start + FrameTableOffset,
1304 /*Payload=*/Start + FramePayloadOffset,
1305 /*Base=*/Start, memprof::FrameLookupTrait()));
1306
1307#ifdef EXPENSIVE_CHECKS
1308 // Go through all the records and verify that CSId has been correctly
1309 // populated. Do this only under EXPENSIVE_CHECKS. Otherwise, we
1310 // would defeat the purpose of OnDiskIterableChainedHashTable.
1311 for (const auto &Record : MemProfRecordTable->data())
1312 verifyIndexedMemProfRecord(Record);
1313#endif
1314 }
1315
1316 // BinaryIdOffset field in the header is only valid when the format version
1317 // is higher than 9 (when it was introduced).
1318 if (GET_VERSION(Header->formatVersion()) >= 9) {
1319 uint64_t BinaryIdOffset =
1320 endian::byte_swap<uint64_t, llvm::endianness::little>(
1321 Header->BinaryIdOffset);
1322 const unsigned char *Ptr = Start + BinaryIdOffset;
1323 // Read binary ids size.
1324 BinaryIdsSize =
1325 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1326 if (BinaryIdsSize % sizeof(uint64_t))
1328 // Set the binary ids start.
1329 BinaryIdsStart = Ptr;
1330 if (BinaryIdsStart > (const unsigned char *)DataBuffer->getBufferEnd())
1331 return make_error<InstrProfError>(instrprof_error::malformed,
1332 "corrupted binary ids");
1333 }
1334
1335 if (GET_VERSION(Header->formatVersion()) >= 12) {
1336 uint64_t VTableNamesOffset =
1337 endian::byte_swap<uint64_t, llvm::endianness::little>(
1338 Header->VTableNamesOffset);
1339 const unsigned char *Ptr = Start + VTableNamesOffset;
1340
1341 CompressedVTableNamesLen =
1342 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1343
1344 // Writer first writes the length of compressed string, and then the actual
1345 // content.
1346 VTableNamePtr = (const char *)Ptr;
1347 if (VTableNamePtr > (const char *)DataBuffer->getBufferEnd())
1348 return make_error<InstrProfError>(instrprof_error::truncated);
1349 }
1350
1351 if (GET_VERSION(Header->formatVersion()) >= 10 &&
1352 Header->formatVersion() & VARIANT_MASK_TEMPORAL_PROF) {
1353 uint64_t TemporalProfTracesOffset =
1354 endian::byte_swap<uint64_t, llvm::endianness::little>(
1355 Header->TemporalProfTracesOffset);
1356 const unsigned char *Ptr = Start + TemporalProfTracesOffset;
1357 const auto *PtrEnd = (const unsigned char *)DataBuffer->getBufferEnd();
1358 // Expect at least two 64 bit fields: NumTraces, and TraceStreamSize
1359 if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1361 const uint64_t NumTraces =
1362 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1364 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1365 for (unsigned i = 0; i < NumTraces; i++) {
1366 // Expect at least two 64 bit fields: Weight and NumFunctions
1367 if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1370 Trace.Weight =
1371 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1372 const uint64_t NumFunctions =
1373 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1374 // Expect at least NumFunctions 64 bit fields
1375 if (Ptr + NumFunctions * sizeof(uint64_t) > PtrEnd)
1377 for (unsigned j = 0; j < NumFunctions; j++) {
1378 const uint64_t NameRef =
1379 support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1380 Trace.FunctionNameRefs.push_back(NameRef);
1381 }
1382 TemporalProfTraces.push_back(std::move(Trace));
1383 }
1384 }
1385
1386 // Load the remapping table now if requested.
1387 if (RemappingBuffer) {
1388 Remapper =
1389 std::make_unique<InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
1390 std::move(RemappingBuffer), *IndexPtr);
1391 if (Error E = Remapper->populateRemappings())
1392 return E;
1393 } else {
1394 Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
1395 }
1396 Index = std::move(IndexPtr);
1397
1398 return success();
1399}
1400
1402 if (Symtab)
1403 return *Symtab;
1404
1405 auto NewSymtab = std::make_unique<InstrProfSymtab>();
1406
1407 if (Error E = NewSymtab->initVTableNamesFromCompressedStrings(
1408 StringRef(VTableNamePtr, CompressedVTableNamesLen))) {
1409 auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1410 consumeError(error(ErrCode, Msg));
1411 }
1412
1413 // finalizeSymtab is called inside populateSymtab.
1414 if (Error E = Index->populateSymtab(*NewSymtab)) {
1415 auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1416 consumeError(error(ErrCode, Msg));
1417 }
1418
1419 Symtab = std::move(NewSymtab);
1420 return *Symtab;
1421}
1422
1424 StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName,
1425 uint64_t *MismatchedFuncSum) {
1427 uint64_t FuncSum = 0;
1428 auto Err = Remapper->getRecords(FuncName, Data);
1429 if (Err) {
1430 // If we don't find FuncName, try DeprecatedFuncName to handle profiles
1431 // built by older compilers.
1432 auto Err2 =
1433 handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
1434 if (IE.get() != instrprof_error::unknown_function)
1435 return make_error<InstrProfError>(IE);
1436 if (auto Err = Remapper->getRecords(DeprecatedFuncName, Data))
1437 return Err;
1438 return Error::success();
1439 });
1440 if (Err2)
1441 return std::move(Err2);
1442 }
1443 // Found it. Look for counters with the right hash.
1444
1445 // A flag to indicate if the records are from the same type
1446 // of profile (i.e cs vs nocs).
1447 bool CSBitMatch = false;
1448 auto getFuncSum = [](const std::vector<uint64_t> &Counts) {
1449 uint64_t ValueSum = 0;
1450 for (uint64_t CountValue : Counts) {
1451 if (CountValue == (uint64_t)-1)
1452 continue;
1453 // Handle overflow -- if that happens, return max.
1454 if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1455 return std::numeric_limits<uint64_t>::max();
1456 ValueSum += CountValue;
1457 }
1458 return ValueSum;
1459 };
1460
1461 for (const NamedInstrProfRecord &I : Data) {
1462 // Check for a match and fill the vector if there is one.
1463 if (I.Hash == FuncHash)
1464 return std::move(I);
1467 CSBitMatch = true;
1468 if (MismatchedFuncSum == nullptr)
1469 continue;
1470 FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
1471 }
1472 }
1473 if (CSBitMatch) {
1474 if (MismatchedFuncSum != nullptr)
1475 *MismatchedFuncSum = FuncSum;
1477 }
1479}
1480
1483 // TODO: Add memprof specific errors.
1484 if (MemProfRecordTable == nullptr)
1485 return make_error<InstrProfError>(instrprof_error::invalid_prof,
1486 "no memprof data available in profile");
1487 auto Iter = MemProfRecordTable->find(FuncNameHash);
1488 if (Iter == MemProfRecordTable->end())
1489 return make_error<InstrProfError>(
1491 "memprof record not found for function hash " + Twine(FuncNameHash));
1492
1493 // Setup a callback to convert from frame ids to frame using the on-disk
1494 // FrameData hash table.
1495 std::optional<memprof::FrameId> LastUnmappedFrameId;
1496 auto IdToFrameCallback = [&](const memprof::FrameId Id) {
1497 auto FrIter = MemProfFrameTable->find(Id);
1498 if (FrIter == MemProfFrameTable->end()) {
1499 LastUnmappedFrameId = Id;
1500 return memprof::Frame(0, 0, 0, false);
1501 }
1502 return *FrIter;
1503 };
1504
1505 memprof::MemProfRecord Record(*Iter, IdToFrameCallback);
1506
1507 // Check that all frame ids were successfully converted to frames.
1508 if (LastUnmappedFrameId) {
1509 return make_error<InstrProfError>(instrprof_error::hash_mismatch,
1510 "memprof frame not found for frame id " +
1511 Twine(*LastUnmappedFrameId));
1512 }
1513 return Record;
1514}
1515
1517 uint64_t FuncHash,
1518 std::vector<uint64_t> &Counts) {
1520 if (Error E = Record.takeError())
1521 return error(std::move(E));
1522
1523 Counts = Record.get().Counts;
1524 return success();
1525}
1526
1528 uint64_t FuncHash,
1529 BitVector &Bitmap) {
1531 if (Error E = Record.takeError())
1532 return error(std::move(E));
1533
1534 const auto &BitmapBytes = Record.get().BitmapBytes;
1535 size_t I = 0, E = BitmapBytes.size();
1536 Bitmap.resize(E * CHAR_BIT);
1538 [&](auto X) {
1539 using XTy = decltype(X);
1540 alignas(XTy) uint8_t W[sizeof(X)];
1541 size_t N = std::min(E - I, sizeof(W));
1542 std::memset(W, 0, sizeof(W));
1543 std::memcpy(W, &BitmapBytes[I], N);
1544 I += N;
1546 support::aligned>(W);
1547 },
1548 Bitmap, Bitmap);
1549 assert(I == E);
1550
1551 return success();
1552}
1553
1556
1557 Error E = Index->getRecords(Data);
1558 if (E)
1559 return error(std::move(E));
1560
1561 Record = Data[RecordIndex++];
1562 if (RecordIndex >= Data.size()) {
1563 Index->advanceToNextKey();
1564 RecordIndex = 0;
1565 }
1566 return success();
1567}
1568
1570 std::vector<llvm::object::BuildID> &BinaryIds) {
1571 return readBinaryIdsInternal(*DataBuffer, BinaryIdsSize, BinaryIdsStart,
1572 BinaryIds, llvm::endianness::little);
1573}
1574
1576 std::vector<llvm::object::BuildID> BinaryIds;
1577 if (Error E = readBinaryIds(BinaryIds))
1578 return E;
1579 printBinaryIdsInternal(OS, BinaryIds);
1580 return Error::success();
1581}
1582
1584 uint64_t NumFuncs = 0;
1585 for (const auto &Func : *this) {
1586 if (isIRLevelProfile()) {
1587 bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
1588 if (FuncIsCS != IsCS)
1589 continue;
1590 }
1591 Func.accumulateCounts(Sum);
1592 ++NumFuncs;
1593 }
1594 Sum.NumEntries = NumFuncs;
1595}
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
This file defines the DenseMap class.
std::string Name
bool End
Definition: ELF_riscv.cpp:480
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Provides ErrorOr<T> smart pointer.
static Expected< std::unique_ptr< MemoryBuffer > > setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS)
static Error initializeReader(InstrProfReader &Reader)
static void printBinaryIdsInternal(raw_ostream &OS, std::vector< llvm::object::BuildID > &BinaryIds)
static Error readBinaryIdsInternal(const MemoryBuffer &DataBuffer, const uint64_t BinaryIdsSize, const uint8_t *BinaryIdsStart, std::vector< llvm::object::BuildID > &BinaryIds, const llvm::endianness Endian)
Read a list of binary ids from a profile that consist of a.
#define READ_NUM(Str, Dst)
#define CHECK_LINE_END(Line)
#define VP_READ_ADVANCE(Val)
static InstrProfKind getProfileKindFromVersion(uint64_t Version)
#define I(x, y, z)
Definition: MD5.cpp:58
if(VerifyEach)
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
endianness Endian
raw_pwrite_stream & OS
This file contains some functions that are useful when dealing with strings.
#define error(X)
Defines the virtual file system interface vfs::FileSystem.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Definition: BitVector.h:341
static BitVector & apply(F &&f, BitVector &Out, BitVector const &Arg, ArgTys const &...Args)
Definition: BitVector.h:552
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
Error takeError()
Take ownership of the stored error.
Definition: Error.h:601
reference get()
Returns a reference to the stored T value.
Definition: Error.h:571
Reader for the indexed binary instrprof format.
Error readNextRecord(NamedInstrProfRecord &Record) override
Read a single record.
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const Twine &RemappingPath="")
Factory method to create an indexed reader.
Expected< memprof::MemProfRecord > getMemProfRecord(uint64_t FuncNameHash)
Return the memprof record for the function identified by llvm::md5(Name).
Error readHeader() override
Read the file header.
Error printBinaryIds(raw_ostream &OS) override
Print binary ids.
Error getFunctionBitmap(StringRef FuncName, uint64_t FuncHash, BitVector &Bitmap)
Fill Bitmap with the profile data for the given function name.
InstrProfSymtab & getSymtab() override
Return the PGO symtab.
static bool hasFormat(const MemoryBuffer &DataBuffer)
Return true if the given buffer is in an indexed instrprof format.
Expected< InstrProfRecord > getInstrProfRecord(StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName="", uint64_t *MismatchedFuncSum=nullptr)
Return the NamedInstrProfRecord associated with FuncName and FuncHash.
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector< uint64_t > &Counts)
Fill Counts with the profile data for the given function name.
Error readBinaryIds(std::vector< llvm::object::BuildID > &BinaryIds) override
Read a list of binary ids.
InstrProfCorrelator - A base class used to create raw instrumentation data to their functions.
const char * getNamesPointer() const
Return a pointer to the names string that this class constructs.
std::optional< size_t > getDataSize() const
Return the number of ProfileData elements.
size_t getNamesSize() const
Return the number of bytes in the names string.
static std::pair< instrprof_error, std::string > take(Error E)
Consume an Error and return the raw enum value contained within it, and the optional error message.
Definition: InstrProf.h:416
data_type ReadData(StringRef K, const unsigned char *D, offset_type N)
bool readValueProfilingData(const unsigned char *&D, const unsigned char *const End)
hash_value_type ComputeHash(StringRef K)
ArrayRef< NamedInstrProfRecord > data_type
InstrProfKind getProfileKind() const override
Error getRecords(ArrayRef< NamedInstrProfRecord > &Data) override
InstrProfReaderIndex(const unsigned char *Buckets, const unsigned char *const Payload, const unsigned char *const Base, IndexedInstrProf::HashT HashType, uint64_t Version)
A remapper that applies remappings based on a symbol remapping file.
static StringRef extractName(StringRef Name)
Extract the original function name from a PGO function name.
InstrProfReaderItaniumRemapper(std::unique_ptr< MemoryBuffer > RemapBuffer, InstrProfReaderIndex< HashTableImpl > &Underlying)
static void reconstituteName(StringRef OrigName, StringRef ExtractedName, StringRef Replacement, SmallVectorImpl< char > &Out)
Given a mangled name extracted from a PGO function name, and a new form for that mangled name,...
Error getRecords(StringRef FuncName, ArrayRef< NamedInstrProfRecord > &Data) override
Name matcher supporting fuzzy matching of symbol names to names in profiles.
Base class and interface for reading profiling data of any known instrprof format.
std::unique_ptr< InstrProfSymtab > Symtab
Error success()
Clear the current error and return a successful one.
SmallVector< TemporalProfTraceTy > TemporalProfTraces
A list of temporal profile traces.
uint64_t TemporalProfTraceStreamSize
The total number of temporal profile traces seen.
static Expected< std::unique_ptr< InstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const InstrProfCorrelator *Correlator=nullptr, std::function< void(Error)> Warn=nullptr)
Factory method to create an appropriately typed reader for the given instrprof file.
virtual bool isIRLevelProfile() const =0
virtual Error readHeader()=0
Read the header. Required before reading first record.
void accumulateCounts(CountSumOrPercent &Sum, bool IsCS)
Compute the sum of counts and return in Sum.
A symbol table used for function [IR]PGO name look-up with keys (such as pointers,...
Definition: InstrProf.h:451
static bool isExternalSymbol(const StringRef &Symbol)
True if Symbol is the value used to represent external symbols.
Definition: InstrProf.h:626
void mapAddress(uint64_t Addr, uint64_t MD5Val)
Map a function address to its name's MD5 hash.
Definition: InstrProf.h:594
Error create(object::SectionRef &Section)
Create InstrProfSymtab from an object file section which contains function PGO names.
void mapVTableAddress(uint64_t StartAddr, uint64_t EndAddr, uint64_t MD5Val)
Map the address range (i.e., [start_address, end_address)) of a variable to its names' MD5 hash.
Definition: InstrProf.h:601
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:51
size_t getBufferSize() const
Definition: MemoryBuffer.h:68
const char * getBufferEnd() const
Definition: MemoryBuffer.h:67
static ErrorOr< std::unique_ptr< MemoryBuffer > > getSTDIN()
Read all of stdin into a file buffer, and return it.
const char * getBufferStart() const
Definition: MemoryBuffer.h:66
static OnDiskIterableChainedHashTable * Create(const unsigned char *Buckets, const unsigned char *const Payload, const unsigned char *const Base, const Info &InfoObj=Info())
Create the hash table.
static const ArrayRef< uint32_t > DefaultCutoffs
A vector of useful cutoff values for detailed summary.
Definition: ProfileCommon.h:70
Reader for the raw instrprof binary format from runtime.
Error readHeader() override
Read the header. Required before reading first record.
Error readNextRecord(NamedInstrProfRecord &Record) override
Read a single record.
Error printBinaryIds(raw_ostream &OS) override
Print binary ids.
static bool hasFormat(const MemoryBuffer &DataBuffer)
InstrProfKind getProfileKind() const override
Returns a BitsetEnum describing the attributes of the raw instr profile.
Error readBinaryIds(std::vector< llvm::object::BuildID > &BinaryIds) override
Read a list of binary ids.
SmallVector< TemporalProfTraceTy > & getTemporalProfTraces(std::optional< uint64_t > Weight={}) override
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
void reserve(size_type N)
Definition: SmallVector.h:676
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:818
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:696
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:466
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:567
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:257
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
iterator begin() const
Definition: StringRef.h:111
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
iterator end() const
Definition: StringRef.h:113
std::pair< StringRef, StringRef > rsplit(StringRef Separator) const
Split into two substrings around the last occurrence of a separator string.
Definition: StringRef.h:729
Reader for symbol remapping files.
Key insert(StringRef FunctionName)
Construct a key for the given symbol, or return an existing one if an equivalent name has already bee...
Key lookup(StringRef FunctionName)
Map the given symbol name into the key for the corresponding equivalence class.
Error read(MemoryBuffer &B)
Read remappings from the given buffer, which must live as long as the remapper.
Reader for the simple text based instrprof format.
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if the given buffer is in text instrprof format.
Error readNextRecord(NamedInstrProfRecord &Record) override
Read a single record.
Error readHeader() override
Read the header.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
LLVM Value Representation.
Definition: Value.h:74
bool is_at_end() const
Return true if we're an "end" iterator or have reached EOF.
Definition: LineIterator.h:63
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
The virtual file system interface.
std::unique_ptr< Summary > allocSummary(uint32_t TotalSize)
Definition: InstrProf.h:1275
uint64_t ComputeHash(StringRef K)
Definition: InstrProf.h:1157
const uint64_t Version
Definition: InstrProf.h:1153
const uint64_t Magic
Definition: InstrProf.h:1114
const uint64_t Version
Definition: InstrProf.h:1298
constexpr uint64_t MaximumSupportedVersion
Definition: MemProf.h:32
constexpr uint64_t MinimumSupportedVersion
Definition: MemProf.h:31
Expected< MemProfSchema > readMemProfSchema(const unsigned char *&Buffer)
Definition: MemProf.cpp:260
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition: Endian.h:58
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
RawInstrProfReader< uint32_t > RawInstrProfReader32
uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align)
Definition: MathExtras.h:382
constexpr T byteswap(T V) noexcept
Reverses the bytes in the given integer value V.
Definition: bit.h:101
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Definition: Error.h:947
auto formatv(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< Ts >(Vals))...))>
constexpr char kGlobalIdentifierDelimiter
Definition: GlobalValue.h:46
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
std::vector< ProfileSummaryEntry > SummaryEntryVector
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition: STLExtras.h:1914
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1849
RawInstrProfReader< uint64_t > RawInstrProfReader64
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:103
endianness
Definition: bit.h:70
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1041
InstrProfKind
An enum describing the attributes of an instrumented profile.
Definition: InstrProf.h:323
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
#define N
static Expected< Header > readFromBuffer(const unsigned char *Buffer)
Definition: InstrProf.cpp:1600
uint64_t Cutoff
The required percentile of total execution count.
Definition: InstrProf.h:1199
uint64_t NumBlocks
Number of blocks >= the minumum execution count.
Definition: InstrProf.h:1202
uint64_t MinBlockCount
The minimum execution count for this percentile.
Definition: InstrProf.h:1201
static uint32_t getSize(uint32_t NumSumFields, uint32_t NumCutoffEntries)
Definition: InstrProf.h:1235
Profiling information for a single function.
Definition: InstrProf.h:808
static bool hasCSFlagInHash(uint64_t FuncHash)
Definition: InstrProf.h:1016
An ordered list of functions identified by their NameRef found in INSTR_PROF_DATA.
Definition: InstrProf.h:377