1 //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===//
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
7 //===----------------------------------------------------------------------===//
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"
36 #include <system_error>
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
;
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.
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
;
110 reinterpret_cast<const uint8_t *>(DataBuffer
.getBufferEnd());
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
);
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));
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
) {
150 OS
<< format("%02x", I
);
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())
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
,
185 else if (RawInstrProfReader32::hasFormat(*Buffer
))
186 Result
.reset(new RawInstrProfReader32(std::move(Buffer
), Correlator
,
187 BIDFetcher
, BIDFetcherCorrelatorKind
,
189 else if (TextInstrProfReader::hasFormat(*Buffer
))
190 Result
.reset(new TextInstrProfReader(std::move(Buffer
)));
192 return make_error
<InstrProfError
>(instrprof_error::unrecognized_format
);
194 // Initialize the reader and return the result.
195 if (Error E
= initializeReader(*Result
))
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())
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())
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
))
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();
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
));
277 return error(instrprof_error::bad_header
);
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
288 Error
TextInstrProfReader::readTemporalProfTraceData() {
289 if ((++Line
).is_at_end())
290 return error(instrprof_error::eof
);
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
));
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); \
335 READ_NUM((*Line), (Val)); \
338 if (Line
.is_at_end())
341 uint32_t NumValueKinds
;
342 if (Line
->getAsInteger(10, NumValueKinds
)) {
343 // No value profile data
346 if (NumValueKinds
== 0 || NumValueKinds
> IPVK_Last
+ 1)
347 return error(instrprof_error::malformed
,
348 "number of value kinds is invalid");
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
);
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
)) {
373 if (Error E
= Symtab
->addFuncName(VD
.first
))
375 Value
= IndexedInstrProf::ComputeHash(VD
.first
);
377 } else if (ValueKind
== IPVK_VTableTarget
) {
378 if (InstrProfSymtab::isExternalSymbol(VD
.first
))
381 if (Error E
= Symtab
->addVTableName(VD
.first
))
383 Value
= IndexedInstrProf::ComputeHash(VD
.first
);
386 READ_NUM(VD
.first
, Value
);
388 READ_NUM(VD
.second
, TakenCount
);
389 CurrentValues
.push_back({Value
, TakenCount
});
392 assert(CurrentValues
.size() == NumValueData
);
393 Record
.addValueData(ValueKind
, S
, CurrentValues
, nullptr);
398 #undef CHECK_LINE_END
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("#")))
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.
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
);
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
);
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
));
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
;
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))
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)
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
);
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
);
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
));
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.")
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()))
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
);
648 std::vector
<object::BuildID
> BinaryIDs
;
649 if (Error E
= readBinaryIds(BinaryIDs
))
651 if (auto E
= InstrProfCorrelator::get("", BIDFetcherCorrelatorKind
,
652 BIDFetcher
, BinaryIDs
)
653 .moveInto(BIDFetcherCorrelator
)) {
656 if (auto Err
= BIDFetcherCorrelator
->correlateProfileData(0))
661 // These sizes in the raw file are zero because we constructed them in the
663 if (!(DataSize
== 0 && NamesSize
== 0 && CountersDelta
== 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();
679 Data
= reinterpret_cast<const RawInstrProf::ProfileData
<IntPtrT
> *>(
681 DataEnd
= Data
+ NumData
;
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
))
702 Symtab
= std::move(NewSymtab
);
706 template <class IntPtrT
>
707 Error RawInstrProfReader
<IntPtrT
>::readName(NamedInstrProfRecord
&Record
) {
708 Record
.Name
= getName(Data
->NameRef
);
712 template <class IntPtrT
>
713 Error RawInstrProfReader
<IntPtrT
>::readFuncHash(NamedInstrProfRecord
&Record
) {
714 Record
.Hash
= swap(Data
->FuncHash
);
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)
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))
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
))
748 Record
.Counts
.clear();
749 Record
.Counts
.reserve(NumCounters
);
750 for (uint32_t I
= 0; I
< NumCounters
; I
++) {
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.
770 if (hasSingleByteCoverage()) {
771 // A value of zero signifies the block is covered.
772 Record
.Counts
.push_back(*Ptr
== 0 ? 1 : 0);
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
);
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)
798 // BitmapDelta decreases as we advance to the next data record.
799 ptrdiff_t BitmapOffset
= swap(Data
->BitmapPtr
) - BitmapDelta
;
800 if (BitmapOffset
< 0)
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))
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
))
821 for (uint32_t I
= 0; I
< NumBitmapBytes
; I
++) {
822 const char *Ptr
= BitmapStart
+ BitmapOffset
+ I
;
823 Record
.BitmapBytes
.push_back(swap(*Ptr
));
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);
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())
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();
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
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
));
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();
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())
930 VDataPtrOrErr
.get()->deserializeTo(DataBuffer
.back(), nullptr);
931 D
+= VDataPtrOrErr
.get()->TotalSize
;
936 data_type
InstrProfLookupTrait::ReadData(StringRef K
, const unsigned char *D
,
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))
945 std::vector
<uint64_t> CounterBuffer
;
946 std::vector
<uint8_t> BitmapByteBuffer
;
948 const unsigned char *End
= D
+ N
;
951 if (D
+ sizeof(uint64_t) >= End
)
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
)
961 CountsSize
= endian::readNext
<uint64_t, llvm::endianness::little
>(D
);
963 // Read counter values.
964 if (D
+ CountsSize
* sizeof(uint64_t) > End
)
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
)
978 BitmapBytes
= endian::readNext
<uint64_t, llvm::endianness::little
>(D
);
979 // Read bitmap byte values.
980 if (D
+ BitmapBytes
* sizeof(uint8_t) > End
)
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
)) {
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
);
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
) {
1021 return make_error
<InstrProfError
>(instrprof_error::eof
);
1023 Data
= *RecordIterator
;
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
,
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
);
1050 /// A remapper that does not apply any remappings.
1051 class InstrProfReaderNullRemapper
: public InstrProfReaderRemapper
{
1052 InstrProfReaderIndexBase
&Underlying
;
1055 InstrProfReaderNullRemapper(InstrProfReaderIndexBase
&Underlying
)
1056 : Underlying(Underlying
) {}
1058 Error
getRecords(StringRef FuncName
,
1059 ArrayRef
<NamedInstrProfRecord
> &Data
) override
{
1060 return Underlying
.getRecords(FuncName
, Data
);
1065 /// A remapper that applies remappings based on a symbol remapping file.
1066 template <typename HashTableImpl
>
1067 class llvm::InstrProfReaderItaniumRemapper
1068 : public InstrProfReaderRemapper
{
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
};
1084 Parts
= Parts
.second
.split(GlobalIdentifierDelimiter
);
1085 if (Parts
.first
.starts_with("_Z"))
1087 if (Parts
.second
.empty())
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
))
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
;
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
);
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
1141 : Error(std::move(Err
));
1147 return Underlying
.getRecords(FuncName
, Data
);
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
1160 /// FIXME: Can we store a location within the on-disk hash table instead of
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)
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
,
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
;
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();
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
);
1259 auto SchemaOr
= memprof::readMemProfSchema(Ptr
);
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
,
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
,
1276 if (Version
>= memprof::Version2
)
1277 MemProfCallStackTable
.reset(MemProfCallStackHashTable::Create(
1278 /*Buckets=*/Start
+ CallStackTableOffset
,
1279 /*Payload=*/Start
+ CallStackPayloadOffset
,
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
);
1299 auto SchemaOr
= memprof::readMemProfSchema(Ptr
);
1301 return SchemaOr
.takeError();
1302 Schema
= SchemaOr
.get();
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
);
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
));
1343 case memprof::Version2
:
1344 if (Error E
= deserializeV2(Start
, Ptr
))
1347 case memprof::Version3
:
1348 if (Error E
= deserializeV3(Start
, Ptr
))
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
);
1367 return HeaderOr
.takeError();
1369 const IndexedInstrProf::Header
*Header
= &HeaderOr
.get();
1370 Cur
+= Header
->size();
1372 Cur
= readSummary((IndexedInstrProf::ProfVersion
)Header
->Version
, Cur
,
1374 if (Header
->Version
& VARIANT_MASK_CSIR_PROF
)
1375 Cur
= readSummary((IndexedInstrProf::ProfVersion
)Header
->Version
, Cur
,
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
))
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
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
;
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
) {
1461 std::make_unique
<InstrProfReaderItaniumRemapper
<OnDiskHashTableImplV3
>>(
1462 std::move(RemappingBuffer
), *IndexPtr
);
1463 if (Error E
= Remapper
->populateRemappings())
1466 Remapper
= std::make_unique
<InstrProfReaderNullRemapper
>(*IndexPtr
);
1468 Index
= std::move(IndexPtr
);
1473 InstrProfSymtab
&IndexedInstrProfReader::getSymtab() {
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
);
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
);
1501 // If we don't find FuncName, try DeprecatedFuncName to handle profiles
1502 // built by older compilers.
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
))
1509 return Error::success();
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)
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
;
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
)) {
1539 if (MismatchedFuncSum
== nullptr)
1541 FuncSum
= std::max(FuncSum
, getFuncSum(I
.Counts
));
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(
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
));
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
);
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
;
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
,
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
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())
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());
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())
1675 memprof::GUIDMemProfRecordPair Pair
;
1677 Pair
.Record
= std::move(*Record
);
1678 AllMemProfData
.HeapProfileRecords
.push_back(std::move(Pair
));
1680 return AllMemProfData
;
1683 Error
IndexedInstrProfReader::getFunctionCounts(StringRef FuncName
,
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
;
1694 Error
IndexedInstrProfReader::getFunctionBitmap(StringRef FuncName
,
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
);
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
);
1712 return support::endian::read
<XTy
, llvm::endianness::little
,
1713 support::aligned
>(W
);
1721 Error
IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord
&Record
) {
1722 ArrayRef
<NamedInstrProfRecord
> Data
;
1724 Error E
= Index
->getRecords(Data
);
1726 return error(std::move(E
));
1728 Record
= Data
[RecordIndex
++];
1729 if (RecordIndex
>= Data
.size()) {
1730 Index
->advanceToNextKey();
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
))
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
)
1758 Func
.accumulateCounts(Sum
);
1761 Sum
.NumEntries
= NumFuncs
;