1 //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains support for reading profiling data for clang's
11 // instrumentation based PGO and coverage.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/ProfileData/InstrProfReader.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/IR/ProfileSummary.h"
20 #include "llvm/ProfileData/InstrProf.h"
21 #include "llvm/ProfileData/ProfileCommon.h"
22 #include "llvm/Support/Endian.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/ErrorOr.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/SwapByteOrder.h"
33 #include <system_error>
39 static Expected
<std::unique_ptr
<MemoryBuffer
>>
40 setupMemoryBuffer(const Twine
&Path
) {
41 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufferOrErr
=
42 MemoryBuffer::getFileOrSTDIN(Path
);
43 if (std::error_code EC
= BufferOrErr
.getError())
44 return errorCodeToError(EC
);
45 return std::move(BufferOrErr
.get());
48 static Error
initializeReader(InstrProfReader
&Reader
) {
49 return Reader
.readHeader();
52 Expected
<std::unique_ptr
<InstrProfReader
>>
53 InstrProfReader::create(const Twine
&Path
) {
54 // Set up the buffer to read.
55 auto BufferOrError
= setupMemoryBuffer(Path
);
56 if (Error E
= BufferOrError
.takeError())
58 return InstrProfReader::create(std::move(BufferOrError
.get()));
61 Expected
<std::unique_ptr
<InstrProfReader
>>
62 InstrProfReader::create(std::unique_ptr
<MemoryBuffer
> Buffer
) {
63 // Sanity check the buffer.
64 if (uint64_t(Buffer
->getBufferSize()) > std::numeric_limits
<unsigned>::max())
65 return make_error
<InstrProfError
>(instrprof_error::too_large
);
67 if (Buffer
->getBufferSize() == 0)
68 return make_error
<InstrProfError
>(instrprof_error::empty_raw_profile
);
70 std::unique_ptr
<InstrProfReader
> Result
;
72 if (IndexedInstrProfReader::hasFormat(*Buffer
))
73 Result
.reset(new IndexedInstrProfReader(std::move(Buffer
)));
74 else if (RawInstrProfReader64::hasFormat(*Buffer
))
75 Result
.reset(new RawInstrProfReader64(std::move(Buffer
)));
76 else if (RawInstrProfReader32::hasFormat(*Buffer
))
77 Result
.reset(new RawInstrProfReader32(std::move(Buffer
)));
78 else if (TextInstrProfReader::hasFormat(*Buffer
))
79 Result
.reset(new TextInstrProfReader(std::move(Buffer
)));
81 return make_error
<InstrProfError
>(instrprof_error::unrecognized_format
);
83 // Initialize the reader and return the result.
84 if (Error E
= initializeReader(*Result
))
87 return std::move(Result
);
90 Expected
<std::unique_ptr
<IndexedInstrProfReader
>>
91 IndexedInstrProfReader::create(const Twine
&Path
) {
92 // Set up the buffer to read.
93 auto BufferOrError
= setupMemoryBuffer(Path
);
94 if (Error E
= BufferOrError
.takeError())
96 return IndexedInstrProfReader::create(std::move(BufferOrError
.get()));
99 Expected
<std::unique_ptr
<IndexedInstrProfReader
>>
100 IndexedInstrProfReader::create(std::unique_ptr
<MemoryBuffer
> Buffer
) {
101 // Sanity check the buffer.
102 if (uint64_t(Buffer
->getBufferSize()) > std::numeric_limits
<unsigned>::max())
103 return make_error
<InstrProfError
>(instrprof_error::too_large
);
105 // Create the reader.
106 if (!IndexedInstrProfReader::hasFormat(*Buffer
))
107 return make_error
<InstrProfError
>(instrprof_error::bad_magic
);
108 auto Result
= llvm::make_unique
<IndexedInstrProfReader
>(std::move(Buffer
));
110 // Initialize the reader and return the result.
111 if (Error E
= initializeReader(*Result
))
114 return std::move(Result
);
117 void InstrProfIterator::Increment() {
118 if (auto E
= Reader
->readNextRecord(Record
)) {
119 // Handle errors in the reader.
120 InstrProfError::take(std::move(E
));
121 *this = InstrProfIterator();
125 bool TextInstrProfReader::hasFormat(const MemoryBuffer
&Buffer
) {
126 // Verify that this really looks like plain ASCII text by checking a
127 // 'reasonable' number of characters (up to profile magic size).
128 size_t count
= std::min(Buffer
.getBufferSize(), sizeof(uint64_t));
129 StringRef buffer
= Buffer
.getBufferStart();
131 std::all_of(buffer
.begin(), buffer
.begin() + count
,
132 [](char c
) { return isPrint(c
) || ::isspace(c
); });
135 // Read the profile variant flag from the header: ":FE" means this is a FE
136 // generated profile. ":IR" means this is an IR level profile. Other strings
137 // with a leading ':' will be reported an error format.
138 Error
TextInstrProfReader::readHeader() {
139 Symtab
.reset(new InstrProfSymtab());
140 bool IsIRInstr
= false;
141 if (!Line
->startswith(":")) {
142 IsIRLevelProfile
= false;
145 StringRef Str
= (Line
)->substr(1);
146 if (Str
.equals_lower("ir"))
148 else if (Str
.equals_lower("fe"))
151 return error(instrprof_error::bad_header
);
154 IsIRLevelProfile
= IsIRInstr
;
159 TextInstrProfReader::readValueProfileData(InstrProfRecord
&Record
) {
161 #define CHECK_LINE_END(Line) \
162 if (Line.is_at_end()) \
163 return error(instrprof_error::truncated);
164 #define READ_NUM(Str, Dst) \
165 if ((Str).getAsInteger(10, (Dst))) \
166 return error(instrprof_error::malformed);
167 #define VP_READ_ADVANCE(Val) \
168 CHECK_LINE_END(Line); \
170 READ_NUM((*Line), (Val)); \
173 if (Line
.is_at_end())
176 uint32_t NumValueKinds
;
177 if (Line
->getAsInteger(10, NumValueKinds
)) {
178 // No value profile data
181 if (NumValueKinds
== 0 || NumValueKinds
> IPVK_Last
+ 1)
182 return error(instrprof_error::malformed
);
185 for (uint32_t VK
= 0; VK
< NumValueKinds
; VK
++) {
186 VP_READ_ADVANCE(ValueKind
);
187 if (ValueKind
> IPVK_Last
)
188 return error(instrprof_error::malformed
);
189 VP_READ_ADVANCE(NumValueSites
);
193 Record
.reserveSites(VK
, NumValueSites
);
194 for (uint32_t S
= 0; S
< NumValueSites
; S
++) {
195 VP_READ_ADVANCE(NumValueData
);
197 std::vector
<InstrProfValueData
> CurrentValues
;
198 for (uint32_t V
= 0; V
< NumValueData
; V
++) {
199 CHECK_LINE_END(Line
);
200 std::pair
<StringRef
, StringRef
> VD
= Line
->rsplit(':');
201 uint64_t TakenCount
, Value
;
202 if (ValueKind
== IPVK_IndirectCallTarget
) {
203 if (InstrProfSymtab::isExternalSymbol(VD
.first
)) {
206 if (Error E
= Symtab
->addFuncName(VD
.first
))
208 Value
= IndexedInstrProf::ComputeHash(VD
.first
);
211 READ_NUM(VD
.first
, Value
);
213 READ_NUM(VD
.second
, TakenCount
);
214 CurrentValues
.push_back({Value
, TakenCount
});
217 Record
.addValueData(ValueKind
, S
, CurrentValues
.data(), NumValueData
,
223 #undef CHECK_LINE_END
225 #undef VP_READ_ADVANCE
228 Error
TextInstrProfReader::readNextRecord(NamedInstrProfRecord
&Record
) {
229 // Skip empty lines and comments.
230 while (!Line
.is_at_end() && (Line
->empty() || Line
->startswith("#")))
232 // If we hit EOF while looking for a name, we're done.
233 if (Line
.is_at_end()) {
234 return error(instrprof_error::eof
);
237 // Read the function name.
238 Record
.Name
= *Line
++;
239 if (Error E
= Symtab
->addFuncName(Record
.Name
))
240 return error(std::move(E
));
242 // Read the function hash.
243 if (Line
.is_at_end())
244 return error(instrprof_error::truncated
);
245 if ((Line
++)->getAsInteger(0, Record
.Hash
))
246 return error(instrprof_error::malformed
);
248 // Read the number of counters.
249 uint64_t NumCounters
;
250 if (Line
.is_at_end())
251 return error(instrprof_error::truncated
);
252 if ((Line
++)->getAsInteger(10, NumCounters
))
253 return error(instrprof_error::malformed
);
254 if (NumCounters
== 0)
255 return error(instrprof_error::malformed
);
257 // Read each counter and fill our internal storage with the values.
259 Record
.Counts
.reserve(NumCounters
);
260 for (uint64_t I
= 0; I
< NumCounters
; ++I
) {
261 if (Line
.is_at_end())
262 return error(instrprof_error::truncated
);
264 if ((Line
++)->getAsInteger(10, Count
))
265 return error(instrprof_error::malformed
);
266 Record
.Counts
.push_back(Count
);
269 // Check if value profile data exists and read it if so.
270 if (Error E
= readValueProfileData(Record
))
271 return error(std::move(E
));
276 template <class IntPtrT
>
277 bool RawInstrProfReader
<IntPtrT
>::hasFormat(const MemoryBuffer
&DataBuffer
) {
278 if (DataBuffer
.getBufferSize() < sizeof(uint64_t))
281 *reinterpret_cast<const uint64_t *>(DataBuffer
.getBufferStart());
282 return RawInstrProf::getMagic
<IntPtrT
>() == Magic
||
283 sys::getSwappedBytes(RawInstrProf::getMagic
<IntPtrT
>()) == Magic
;
286 template <class IntPtrT
>
287 Error RawInstrProfReader
<IntPtrT
>::readHeader() {
288 if (!hasFormat(*DataBuffer
))
289 return error(instrprof_error::bad_magic
);
290 if (DataBuffer
->getBufferSize() < sizeof(RawInstrProf::Header
))
291 return error(instrprof_error::bad_header
);
292 auto *Header
= reinterpret_cast<const RawInstrProf::Header
*>(
293 DataBuffer
->getBufferStart());
294 ShouldSwapBytes
= Header
->Magic
!= RawInstrProf::getMagic
<IntPtrT
>();
295 return readHeader(*Header
);
298 template <class IntPtrT
>
299 Error RawInstrProfReader
<IntPtrT
>::readNextHeader(const char *CurrentPos
) {
300 const char *End
= DataBuffer
->getBufferEnd();
301 // Skip zero padding between profiles.
302 while (CurrentPos
!= End
&& *CurrentPos
== 0)
304 // If there's nothing left, we're done.
305 if (CurrentPos
== End
)
306 return make_error
<InstrProfError
>(instrprof_error::eof
);
307 // If there isn't enough space for another header, this is probably just
308 // garbage at the end of the file.
309 if (CurrentPos
+ sizeof(RawInstrProf::Header
) > End
)
310 return make_error
<InstrProfError
>(instrprof_error::malformed
);
311 // The writer ensures each profile is padded to start at an aligned address.
312 if (reinterpret_cast<size_t>(CurrentPos
) % alignof(uint64_t))
313 return make_error
<InstrProfError
>(instrprof_error::malformed
);
314 // The magic should have the same byte order as in the previous header.
315 uint64_t Magic
= *reinterpret_cast<const uint64_t *>(CurrentPos
);
316 if (Magic
!= swap(RawInstrProf::getMagic
<IntPtrT
>()))
317 return make_error
<InstrProfError
>(instrprof_error::bad_magic
);
319 // There's another profile to read, so we need to process the header.
320 auto *Header
= reinterpret_cast<const RawInstrProf::Header
*>(CurrentPos
);
321 return readHeader(*Header
);
324 template <class IntPtrT
>
325 Error RawInstrProfReader
<IntPtrT
>::createSymtab(InstrProfSymtab
&Symtab
) {
326 if (Error E
= Symtab
.create(StringRef(NamesStart
, NamesSize
)))
327 return error(std::move(E
));
328 for (const RawInstrProf::ProfileData
<IntPtrT
> *I
= Data
; I
!= DataEnd
; ++I
) {
329 const IntPtrT FPtr
= swap(I
->FunctionPointer
);
332 Symtab
.mapAddress(FPtr
, I
->NameRef
);
337 template <class IntPtrT
>
338 Error RawInstrProfReader
<IntPtrT
>::readHeader(
339 const RawInstrProf::Header
&Header
) {
340 Version
= swap(Header
.Version
);
341 if (GET_VERSION(Version
) != RawInstrProf::Version
)
342 return error(instrprof_error::unsupported_version
);
344 CountersDelta
= swap(Header
.CountersDelta
);
345 NamesDelta
= swap(Header
.NamesDelta
);
346 auto DataSize
= swap(Header
.DataSize
);
347 auto CountersSize
= swap(Header
.CountersSize
);
348 NamesSize
= swap(Header
.NamesSize
);
349 ValueKindLast
= swap(Header
.ValueKindLast
);
351 auto DataSizeInBytes
= DataSize
* sizeof(RawInstrProf::ProfileData
<IntPtrT
>);
352 auto PaddingSize
= getNumPaddingBytes(NamesSize
);
354 ptrdiff_t DataOffset
= sizeof(RawInstrProf::Header
);
355 ptrdiff_t CountersOffset
= DataOffset
+ DataSizeInBytes
;
356 ptrdiff_t NamesOffset
= CountersOffset
+ sizeof(uint64_t) * CountersSize
;
357 ptrdiff_t ValueDataOffset
= NamesOffset
+ NamesSize
+ PaddingSize
;
359 auto *Start
= reinterpret_cast<const char *>(&Header
);
360 if (Start
+ ValueDataOffset
> DataBuffer
->getBufferEnd())
361 return error(instrprof_error::bad_header
);
363 Data
= reinterpret_cast<const RawInstrProf::ProfileData
<IntPtrT
> *>(
365 DataEnd
= Data
+ DataSize
;
366 CountersStart
= reinterpret_cast<const uint64_t *>(Start
+ CountersOffset
);
367 NamesStart
= Start
+ NamesOffset
;
368 ValueDataStart
= reinterpret_cast<const uint8_t *>(Start
+ ValueDataOffset
);
370 std::unique_ptr
<InstrProfSymtab
> NewSymtab
= make_unique
<InstrProfSymtab
>();
371 if (Error E
= createSymtab(*NewSymtab
.get()))
374 Symtab
= std::move(NewSymtab
);
378 template <class IntPtrT
>
379 Error RawInstrProfReader
<IntPtrT
>::readName(NamedInstrProfRecord
&Record
) {
380 Record
.Name
= getName(Data
->NameRef
);
384 template <class IntPtrT
>
385 Error RawInstrProfReader
<IntPtrT
>::readFuncHash(NamedInstrProfRecord
&Record
) {
386 Record
.Hash
= swap(Data
->FuncHash
);
390 template <class IntPtrT
>
391 Error RawInstrProfReader
<IntPtrT
>::readRawCounts(
392 InstrProfRecord
&Record
) {
393 uint32_t NumCounters
= swap(Data
->NumCounters
);
394 IntPtrT CounterPtr
= Data
->CounterPtr
;
395 if (NumCounters
== 0)
396 return error(instrprof_error::malformed
);
398 auto RawCounts
= makeArrayRef(getCounter(CounterPtr
), NumCounters
);
399 auto *NamesStartAsCounter
= reinterpret_cast<const uint64_t *>(NamesStart
);
402 if (RawCounts
.data() < CountersStart
||
403 RawCounts
.data() + RawCounts
.size() > NamesStartAsCounter
)
404 return error(instrprof_error::malformed
);
406 if (ShouldSwapBytes
) {
407 Record
.Counts
.clear();
408 Record
.Counts
.reserve(RawCounts
.size());
409 for (uint64_t Count
: RawCounts
)
410 Record
.Counts
.push_back(swap(Count
));
412 Record
.Counts
= RawCounts
;
417 template <class IntPtrT
>
418 Error RawInstrProfReader
<IntPtrT
>::readValueProfilingData(
419 InstrProfRecord
&Record
) {
420 Record
.clearValueData();
421 CurValueDataSize
= 0;
422 // Need to match the logic in value profile dumper code in compiler-rt:
423 uint32_t NumValueKinds
= 0;
424 for (uint32_t I
= 0; I
< IPVK_Last
+ 1; I
++)
425 NumValueKinds
+= (Data
->NumValueSites
[I
] != 0);
430 Expected
<std::unique_ptr
<ValueProfData
>> VDataPtrOrErr
=
431 ValueProfData::getValueProfData(
432 ValueDataStart
, (const unsigned char *)DataBuffer
->getBufferEnd(),
433 getDataEndianness());
435 if (Error E
= VDataPtrOrErr
.takeError())
438 // Note that besides deserialization, this also performs the conversion for
439 // indirect call targets. The function pointers from the raw profile are
440 // remapped into function name hashes.
441 VDataPtrOrErr
.get()->deserializeTo(Record
, Symtab
.get());
442 CurValueDataSize
= VDataPtrOrErr
.get()->getSize();
446 template <class IntPtrT
>
447 Error RawInstrProfReader
<IntPtrT
>::readNextRecord(NamedInstrProfRecord
&Record
) {
449 // At this point, ValueDataStart field points to the next header.
450 if (Error E
= readNextHeader(getNextHeaderPos()))
451 return error(std::move(E
));
453 // Read name ad set it in Record.
454 if (Error E
= readName(Record
))
455 return error(std::move(E
));
457 // Read FuncHash and set it in Record.
458 if (Error E
= readFuncHash(Record
))
459 return error(std::move(E
));
461 // Read raw counts and set Record.
462 if (Error E
= readRawCounts(Record
))
463 return error(std::move(E
));
465 // Read value data and set Record.
466 if (Error E
= readValueProfilingData(Record
))
467 return error(std::move(E
));
476 template class RawInstrProfReader
<uint32_t>;
477 template class RawInstrProfReader
<uint64_t>;
479 } // end namespace llvm
481 InstrProfLookupTrait::hash_value_type
482 InstrProfLookupTrait::ComputeHash(StringRef K
) {
483 return IndexedInstrProf::ComputeHash(HashType
, K
);
486 using data_type
= InstrProfLookupTrait::data_type
;
487 using offset_type
= InstrProfLookupTrait::offset_type
;
489 bool InstrProfLookupTrait::readValueProfilingData(
490 const unsigned char *&D
, const unsigned char *const End
) {
491 Expected
<std::unique_ptr
<ValueProfData
>> VDataPtrOrErr
=
492 ValueProfData::getValueProfData(D
, End
, ValueProfDataEndianness
);
494 if (VDataPtrOrErr
.takeError())
497 VDataPtrOrErr
.get()->deserializeTo(DataBuffer
.back(), nullptr);
498 D
+= VDataPtrOrErr
.get()->TotalSize
;
503 data_type
InstrProfLookupTrait::ReadData(StringRef K
, const unsigned char *D
,
505 using namespace support
;
507 // Check if the data is corrupt. If so, don't try to read it.
508 if (N
% sizeof(uint64_t))
512 std::vector
<uint64_t> CounterBuffer
;
514 const unsigned char *End
= D
+ N
;
517 if (D
+ sizeof(uint64_t) >= End
)
519 uint64_t Hash
= endian::readNext
<uint64_t, little
, unaligned
>(D
);
521 // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
522 uint64_t CountsSize
= N
/ sizeof(uint64_t) - 1;
523 // If format version is different then read the number of counters.
524 if (GET_VERSION(FormatVersion
) != IndexedInstrProf::ProfVersion::Version1
) {
525 if (D
+ sizeof(uint64_t) > End
)
527 CountsSize
= endian::readNext
<uint64_t, little
, unaligned
>(D
);
529 // Read counter values.
530 if (D
+ CountsSize
* sizeof(uint64_t) > End
)
533 CounterBuffer
.clear();
534 CounterBuffer
.reserve(CountsSize
);
535 for (uint64_t J
= 0; J
< CountsSize
; ++J
)
536 CounterBuffer
.push_back(endian::readNext
<uint64_t, little
, unaligned
>(D
));
538 DataBuffer
.emplace_back(K
, Hash
, std::move(CounterBuffer
));
540 // Read value profiling data.
541 if (GET_VERSION(FormatVersion
) > IndexedInstrProf::ProfVersion::Version2
&&
542 !readValueProfilingData(D
, End
)) {
550 template <typename HashTableImpl
>
551 Error InstrProfReaderIndex
<HashTableImpl
>::getRecords(
552 StringRef FuncName
, ArrayRef
<NamedInstrProfRecord
> &Data
) {
553 auto Iter
= HashTable
->find(FuncName
);
554 if (Iter
== HashTable
->end())
555 return make_error
<InstrProfError
>(instrprof_error::unknown_function
);
559 return make_error
<InstrProfError
>(instrprof_error::malformed
);
561 return Error::success();
564 template <typename HashTableImpl
>
565 Error InstrProfReaderIndex
<HashTableImpl
>::getRecords(
566 ArrayRef
<NamedInstrProfRecord
> &Data
) {
568 return make_error
<InstrProfError
>(instrprof_error::eof
);
570 Data
= *RecordIterator
;
573 return make_error
<InstrProfError
>(instrprof_error::malformed
);
575 return Error::success();
578 template <typename HashTableImpl
>
579 InstrProfReaderIndex
<HashTableImpl
>::InstrProfReaderIndex(
580 const unsigned char *Buckets
, const unsigned char *const Payload
,
581 const unsigned char *const Base
, IndexedInstrProf::HashT HashType
,
583 FormatVersion
= Version
;
584 HashTable
.reset(HashTableImpl::Create(
585 Buckets
, Payload
, Base
,
586 typename
HashTableImpl::InfoType(HashType
, Version
)));
587 RecordIterator
= HashTable
->data_begin();
590 bool IndexedInstrProfReader::hasFormat(const MemoryBuffer
&DataBuffer
) {
591 using namespace support
;
593 if (DataBuffer
.getBufferSize() < 8)
596 endian::read
<uint64_t, little
, aligned
>(DataBuffer
.getBufferStart());
597 // Verify that it's magical.
598 return Magic
== IndexedInstrProf::Magic
;
601 const unsigned char *
602 IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version
,
603 const unsigned char *Cur
) {
604 using namespace IndexedInstrProf
;
605 using namespace support
;
607 if (Version
>= IndexedInstrProf::Version4
) {
608 const IndexedInstrProf::Summary
*SummaryInLE
=
609 reinterpret_cast<const IndexedInstrProf::Summary
*>(Cur
);
611 endian::byte_swap
<uint64_t, little
>(SummaryInLE
->NumSummaryFields
);
613 endian::byte_swap
<uint64_t, little
>(SummaryInLE
->NumCutoffEntries
);
614 uint32_t SummarySize
=
615 IndexedInstrProf::Summary::getSize(NFields
, NEntries
);
616 std::unique_ptr
<IndexedInstrProf::Summary
> SummaryData
=
617 IndexedInstrProf::allocSummary(SummarySize
);
619 const uint64_t *Src
= reinterpret_cast<const uint64_t *>(SummaryInLE
);
620 uint64_t *Dst
= reinterpret_cast<uint64_t *>(SummaryData
.get());
621 for (unsigned I
= 0; I
< SummarySize
/ sizeof(uint64_t); I
++)
622 Dst
[I
] = endian::byte_swap
<uint64_t, little
>(Src
[I
]);
624 SummaryEntryVector DetailedSummary
;
625 for (unsigned I
= 0; I
< SummaryData
->NumCutoffEntries
; I
++) {
626 const IndexedInstrProf::Summary::Entry
&Ent
= SummaryData
->getEntry(I
);
627 DetailedSummary
.emplace_back((uint32_t)Ent
.Cutoff
, Ent
.MinBlockCount
,
630 // initialize InstrProfSummary using the SummaryData from disk.
631 this->Summary
= llvm::make_unique
<ProfileSummary
>(
632 ProfileSummary::PSK_Instr
, DetailedSummary
,
633 SummaryData
->get(Summary::TotalBlockCount
),
634 SummaryData
->get(Summary::MaxBlockCount
),
635 SummaryData
->get(Summary::MaxInternalBlockCount
),
636 SummaryData
->get(Summary::MaxFunctionCount
),
637 SummaryData
->get(Summary::TotalNumBlocks
),
638 SummaryData
->get(Summary::TotalNumFunctions
));
639 return Cur
+ SummarySize
;
641 // For older version of profile data, we need to compute on the fly:
642 using namespace IndexedInstrProf
;
644 InstrProfSummaryBuilder
Builder(ProfileSummaryBuilder::DefaultCutoffs
);
645 // FIXME: This only computes an empty summary. Need to call addRecord for
646 // all NamedInstrProfRecords to get the correct summary.
647 this->Summary
= Builder
.getSummary();
652 Error
IndexedInstrProfReader::readHeader() {
653 using namespace support
;
655 const unsigned char *Start
=
656 (const unsigned char *)DataBuffer
->getBufferStart();
657 const unsigned char *Cur
= Start
;
658 if ((const unsigned char *)DataBuffer
->getBufferEnd() - Cur
< 24)
659 return error(instrprof_error::truncated
);
661 auto *Header
= reinterpret_cast<const IndexedInstrProf::Header
*>(Cur
);
662 Cur
+= sizeof(IndexedInstrProf::Header
);
664 // Check the magic number.
665 uint64_t Magic
= endian::byte_swap
<uint64_t, little
>(Header
->Magic
);
666 if (Magic
!= IndexedInstrProf::Magic
)
667 return error(instrprof_error::bad_magic
);
670 uint64_t FormatVersion
= endian::byte_swap
<uint64_t, little
>(Header
->Version
);
671 if (GET_VERSION(FormatVersion
) >
672 IndexedInstrProf::ProfVersion::CurrentVersion
)
673 return error(instrprof_error::unsupported_version
);
675 Cur
= readSummary((IndexedInstrProf::ProfVersion
)FormatVersion
, Cur
);
677 // Read the hash type and start offset.
678 IndexedInstrProf::HashT HashType
= static_cast<IndexedInstrProf::HashT
>(
679 endian::byte_swap
<uint64_t, little
>(Header
->HashType
));
680 if (HashType
> IndexedInstrProf::HashT::Last
)
681 return error(instrprof_error::unsupported_hash_type
);
683 uint64_t HashOffset
= endian::byte_swap
<uint64_t, little
>(Header
->HashOffset
);
685 // The rest of the file is an on disk hash table.
686 InstrProfReaderIndexBase
*IndexPtr
= nullptr;
687 IndexPtr
= new InstrProfReaderIndex
<OnDiskHashTableImplV3
>(
688 Start
+ HashOffset
, Cur
, Start
, HashType
, FormatVersion
);
689 Index
.reset(IndexPtr
);
693 InstrProfSymtab
&IndexedInstrProfReader::getSymtab() {
695 return *Symtab
.get();
697 std::unique_ptr
<InstrProfSymtab
> NewSymtab
= make_unique
<InstrProfSymtab
>();
698 if (Error E
= Index
->populateSymtab(*NewSymtab
.get())) {
699 consumeError(error(InstrProfError::take(std::move(E
))));
702 Symtab
= std::move(NewSymtab
);
703 return *Symtab
.get();
706 Expected
<InstrProfRecord
>
707 IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName
,
709 ArrayRef
<NamedInstrProfRecord
> Data
;
710 Error Err
= Index
->getRecords(FuncName
, Data
);
712 return std::move(Err
);
713 // Found it. Look for counters with the right hash.
714 for (unsigned I
= 0, E
= Data
.size(); I
< E
; ++I
) {
715 // Check for a match and fill the vector if there is one.
716 if (Data
[I
].Hash
== FuncHash
) {
717 return std::move(Data
[I
]);
720 return error(instrprof_error::hash_mismatch
);
723 Error
IndexedInstrProfReader::getFunctionCounts(StringRef FuncName
,
725 std::vector
<uint64_t> &Counts
) {
726 Expected
<InstrProfRecord
> Record
= getInstrProfRecord(FuncName
, FuncHash
);
727 if (Error E
= Record
.takeError())
728 return error(std::move(E
));
730 Counts
= Record
.get().Counts
;
734 Error
IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord
&Record
) {
735 ArrayRef
<NamedInstrProfRecord
> Data
;
737 Error E
= Index
->getRecords(Data
);
739 return error(std::move(E
));
741 Record
= Data
[RecordIndex
++];
742 if (RecordIndex
>= Data
.size()) {
743 Index
->advanceToNextKey();