LLVM 18.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"
30#include <algorithm>
31#include <cstddef>
32#include <cstdint>
33#include <limits>
34#include <memory>
35#include <system_error>
36#include <utility>
37#include <vector>
38
39using namespace llvm;
40
41// Extracts the variant information from the top 32 bits in the version and
42// returns an enum specifying the variants present.
44 InstrProfKind ProfileKind = InstrProfKind::Unknown;
45 if (Version & VARIANT_MASK_IR_PROF) {
46 ProfileKind |= InstrProfKind::IRInstrumentation;
47 }
48 if (Version & VARIANT_MASK_CSIR_PROF) {
49 ProfileKind |= InstrProfKind::ContextSensitive;
50 }
51 if (Version & VARIANT_MASK_INSTR_ENTRY) {
52 ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
53 }
54 if (Version & VARIANT_MASK_BYTE_COVERAGE) {
55 ProfileKind |= InstrProfKind::SingleByteCoverage;
56 }
57 if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
58 ProfileKind |= InstrProfKind::FunctionEntryOnly;
59 }
60 if (Version & VARIANT_MASK_MEMPROF) {
61 ProfileKind |= InstrProfKind::MemProf;
62 }
63 if (Version & VARIANT_MASK_TEMPORAL_PROF) {
64 ProfileKind |= InstrProfKind::TemporalProfile;
65 }
66 return ProfileKind;
67}
68
71 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
72 : FS.getBufferForFile(Filename);
73 if (std::error_code EC = BufferOrErr.getError())
74 return errorCodeToError(EC);
75 return std::move(BufferOrErr.get());
76}
77
79 return Reader.readHeader();
80}
81
82/// Read a list of binary ids from a profile that consist of
83/// a. uint64_t binary id length
84/// b. uint8_t binary id data
85/// c. uint8_t padding (if necessary)
86/// This function is shared between raw and indexed profiles.
87/// Raw profiles are in host-endian format, and indexed profiles are in
88/// little-endian format. So, this function takes an argument indicating the
89/// associated endian format to read the binary ids correctly.
90static Error
92 const uint64_t BinaryIdsSize,
93 const uint8_t *BinaryIdsStart,
94 std::vector<llvm::object::BuildID> &BinaryIds,
95 const llvm::endianness Endian) {
96 using namespace support;
97
98 if (BinaryIdsSize == 0)
99 return Error::success();
100
101 const uint8_t *BI = BinaryIdsStart;
102 const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
103 const uint8_t *End =
104 reinterpret_cast<const uint8_t *>(DataBuffer.getBufferEnd());
105
106 while (BI < BIEnd) {
107 size_t Remaining = BIEnd - BI;
108 // There should be enough left to read the binary id length.
109 if (Remaining < sizeof(uint64_t))
110 return make_error<InstrProfError>(
111 instrprof_error::malformed,
112 "not enough data to read binary id length");
113
114 uint64_t BILen = 0;
116 BILen =
117 endian::readNext<uint64_t, llvm::endianness::little, unaligned>(BI);
118 else
119 BILen = endian::readNext<uint64_t, llvm::endianness::big, unaligned>(BI);
120
121 if (BILen == 0)
122 return make_error<InstrProfError>(instrprof_error::malformed,
123 "binary id length is 0");
124
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");
130
131 // Add binary id to the binary ids list.
132 BinaryIds.push_back(object::BuildID(BI, BI + BILen));
133
134 // Increment by binary id data length, which aligned to the size of uint64.
135 BI += alignToPowerOf2(BILen, sizeof(uint64_t));
136 if (BI > End)
137 return make_error<InstrProfError>(
138 instrprof_error::malformed,
139 "binary id section is greater than buffer size");
140 }
141
142 return Error::success();
143}
144
145static void
147 std::vector<llvm::object::BuildID> &BinaryIds) {
148 OS << "Binary IDs: \n";
149 for (auto BI : BinaryIds) {
150 for (uint64_t I = 0; I < BI.size(); I++)
151 OS << format("%02x", BI[I]);
152 OS << "\n";
153 }
154}
155
158 const InstrProfCorrelator *Correlator,
159 std::function<void(Error)> Warn) {
160 // Set up the buffer to read.
161 auto BufferOrError = setupMemoryBuffer(Path, FS);
162 if (Error E = BufferOrError.takeError())
163 return std::move(E);
164 return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
165 Warn);
166}
167
169InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
170 const InstrProfCorrelator *Correlator,
171 std::function<void(Error)> Warn) {
172 if (Buffer->getBufferSize() == 0)
173 return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
174
175 std::unique_ptr<InstrProfReader> Result;
176 // Create the reader.
178 Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
179 else if (RawInstrProfReader64::hasFormat(*Buffer))
180 Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn));
181 else if (RawInstrProfReader32::hasFormat(*Buffer))
182 Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn));
183 else if (TextInstrProfReader::hasFormat(*Buffer))
184 Result.reset(new TextInstrProfReader(std::move(Buffer)));
185 else
186 return make_error<InstrProfError>(instrprof_error::unrecognized_format);
187
188 // Initialize the reader and return the result.
189 if (Error E = initializeReader(*Result))
190 return std::move(E);
191
192 return std::move(Result);
193}
194
197 const Twine &RemappingPath) {
198 // Set up the buffer to read.
199 auto BufferOrError = setupMemoryBuffer(Path, FS);
200 if (Error E = BufferOrError.takeError())
201 return std::move(E);
202
203 // Set up the remapping buffer if requested.
204 std::unique_ptr<MemoryBuffer> RemappingBuffer;
205 std::string RemappingPathStr = RemappingPath.str();
206 if (!RemappingPathStr.empty()) {
207 auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS);
208 if (Error E = RemappingBufferOrError.takeError())
209 return std::move(E);
210 RemappingBuffer = std::move(RemappingBufferOrError.get());
211 }
212
213 return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
214 std::move(RemappingBuffer));
215}
216
218IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
219 std::unique_ptr<MemoryBuffer> RemappingBuffer) {
220 // Create the reader.
222 return make_error<InstrProfError>(instrprof_error::bad_magic);
223 auto Result = std::make_unique<IndexedInstrProfReader>(
224 std::move(Buffer), std::move(RemappingBuffer));
225
226 // Initialize the reader and return the result.
227 if (Error E = initializeReader(*Result))
228 return std::move(E);
229
230 return std::move(Result);
231}
232
234 // Verify that this really looks like plain ASCII text by checking a
235 // 'reasonable' number of characters (up to profile magic size).
236 size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
237 StringRef buffer = Buffer.getBufferStart();
238 return count == 0 ||
239 std::all_of(buffer.begin(), buffer.begin() + count,
240 [](char c) { return isPrint(c) || isSpace(c); });
241}
242
243// Read the profile variant flag from the header: ":FE" means this is a FE
244// generated profile. ":IR" means this is an IR level profile. Other strings
245// with a leading ':' will be reported an error format.
247 Symtab.reset(new InstrProfSymtab());
248
249 while (Line->startswith(":")) {
250 StringRef Str = Line->substr(1);
251 if (Str.equals_insensitive("ir"))
253 else if (Str.equals_insensitive("fe"))
255 else if (Str.equals_insensitive("csir")) {
257 ProfileKind |= InstrProfKind::ContextSensitive;
258 } else if (Str.equals_insensitive("entry_first"))
260 else if (Str.equals_insensitive("not_entry_first"))
262 else if (Str.equals_insensitive("single_byte_coverage"))
264 else if (Str.equals_insensitive("temporal_prof_traces")) {
265 ProfileKind |= InstrProfKind::TemporalProfile;
266 if (auto Err = readTemporalProfTraceData())
267 return error(std::move(Err));
268 } else
270 ++Line;
271 }
272 return success();
273}
274
275/// Temporal profile trace data is stored in the header immediately after
276/// ":temporal_prof_traces". The first integer is the number of traces, the
277/// second integer is the stream size, then the following lines are the actual
278/// traces which consist of a weight and a comma separated list of function
279/// names.
280Error TextInstrProfReader::readTemporalProfTraceData() {
281 if ((++Line).is_at_end())
283
284 uint32_t NumTraces;
285 if (Line->getAsInteger(0, NumTraces))
287
288 if ((++Line).is_at_end())
290
293
294 for (uint32_t i = 0; i < NumTraces; i++) {
295 if ((++Line).is_at_end())
297
299 if (Line->getAsInteger(0, Trace.Weight))
301
302 if ((++Line).is_at_end())
304
305 SmallVector<StringRef> FuncNames;
306 Line->split(FuncNames, ",", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
307 for (auto &FuncName : FuncNames)
308 Trace.FunctionNameRefs.push_back(
309 IndexedInstrProf::ComputeHash(FuncName.trim()));
310 TemporalProfTraces.push_back(std::move(Trace));
311 }
312 return success();
313}
314
315Error
316TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
317
318#define CHECK_LINE_END(Line) \
319 if (Line.is_at_end()) \
320 return error(instrprof_error::truncated);
321#define READ_NUM(Str, Dst) \
322 if ((Str).getAsInteger(10, (Dst))) \
323 return error(instrprof_error::malformed);
324#define VP_READ_ADVANCE(Val) \
325 CHECK_LINE_END(Line); \
326 uint32_t Val; \
327 READ_NUM((*Line), (Val)); \
328 Line++;
329
330 if (Line.is_at_end())
331 return success();
332
333 uint32_t NumValueKinds;
334 if (Line->getAsInteger(10, NumValueKinds)) {
335 // No value profile data
336 return success();
337 }
338 if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
340 "number of value kinds is invalid");
341 Line++;
342
343 for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
344 VP_READ_ADVANCE(ValueKind);
345 if (ValueKind > IPVK_Last)
346 return error(instrprof_error::malformed, "value kind is invalid");
347 ;
348 VP_READ_ADVANCE(NumValueSites);
349 if (!NumValueSites)
350 continue;
351
352 Record.reserveSites(VK, NumValueSites);
353 for (uint32_t S = 0; S < NumValueSites; S++) {
354 VP_READ_ADVANCE(NumValueData);
355
356 std::vector<InstrProfValueData> CurrentValues;
357 for (uint32_t V = 0; V < NumValueData; V++) {
358 CHECK_LINE_END(Line);
359 std::pair<StringRef, StringRef> VD = Line->rsplit(':');
360 uint64_t TakenCount, Value;
361 if (ValueKind == IPVK_IndirectCallTarget) {
362 if (InstrProfSymtab::isExternalSymbol(VD.first)) {
363 Value = 0;
364 } else {
365 if (Error E = Symtab->addFuncName(VD.first))
366 return E;
368 }
369 } else {
370 READ_NUM(VD.first, Value);
371 }
372 READ_NUM(VD.second, TakenCount);
373 CurrentValues.push_back({Value, TakenCount});
374 Line++;
375 }
376 Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData,
377 nullptr);
378 }
379 }
380 return success();
381
382#undef CHECK_LINE_END
383#undef READ_NUM
384#undef VP_READ_ADVANCE
385}
386
388 // Skip empty lines and comments.
389 while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
390 ++Line;
391 // If we hit EOF while looking for a name, we're done.
392 if (Line.is_at_end()) {
394 }
395
396 // Read the function name.
397 Record.Name = *Line++;
398 if (Error E = Symtab->addFuncName(Record.Name))
399 return error(std::move(E));
400
401 // Read the function hash.
402 if (Line.is_at_end())
404 if ((Line++)->getAsInteger(0, Record.Hash))
406 "function hash is not a valid integer");
407
408 // Read the number of counters.
409 uint64_t NumCounters;
410 if (Line.is_at_end())
412 if ((Line++)->getAsInteger(10, NumCounters))
414 "number of counters is not a valid integer");
415 if (NumCounters == 0)
416 return error(instrprof_error::malformed, "number of counters is zero");
417
418 // Read each counter and fill our internal storage with the values.
419 Record.Clear();
420 Record.Counts.reserve(NumCounters);
421 for (uint64_t I = 0; I < NumCounters; ++I) {
422 if (Line.is_at_end())
424 uint64_t Count;
425 if ((Line++)->getAsInteger(10, Count))
426 return error(instrprof_error::malformed, "count is invalid");
427 Record.Counts.push_back(Count);
428 }
429
430 // Bitmap byte information is indicated with special character.
431 if (Line->startswith("$")) {
432 Record.BitmapBytes.clear();
433 // Read the number of bitmap bytes.
434 uint64_t NumBitmapBytes;
435 if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes))
437 "number of bitmap bytes is not a valid integer");
438 if (NumBitmapBytes != 0) {
439 // Read each bitmap and fill our internal storage with the values.
440 Record.BitmapBytes.reserve(NumBitmapBytes);
441 for (uint8_t I = 0; I < NumBitmapBytes; ++I) {
442 if (Line.is_at_end())
444 uint8_t BitmapByte;
445 if ((Line++)->getAsInteger(0, BitmapByte))
447 "bitmap byte is not a valid integer");
448 Record.BitmapBytes.push_back(BitmapByte);
449 }
450 }
451 }
452
453 // Check if value profile data exists and read it if so.
454 if (Error E = readValueProfileData(Record))
455 return error(std::move(E));
456
457 return success();
458}
459
460template <class IntPtrT>
462 return getProfileKindFromVersion(Version);
463}
464
465template <class IntPtrT>
468 std::optional<uint64_t> Weight) {
469 if (TemporalProfTimestamps.empty()) {
470 assert(TemporalProfTraces.empty());
471 return TemporalProfTraces;
472 }
473 // Sort functions by their timestamps to build the trace.
474 std::sort(TemporalProfTimestamps.begin(), TemporalProfTimestamps.end());
476 if (Weight)
477 Trace.Weight = *Weight;
478 for (auto &[TimestampValue, NameRef] : TemporalProfTimestamps)
479 Trace.FunctionNameRefs.push_back(NameRef);
480 TemporalProfTraces = {std::move(Trace)};
481 return TemporalProfTraces;
482}
483
484template <class IntPtrT>
486 if (DataBuffer.getBufferSize() < sizeof(uint64_t))
487 return false;
488 uint64_t Magic =
489 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
490 return RawInstrProf::getMagic<IntPtrT>() == Magic ||
491 llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic;
492}
493
494template <class IntPtrT>
496 if (!hasFormat(*DataBuffer))
498 if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
500 auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
501 DataBuffer->getBufferStart());
502 ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
503 return readHeader(*Header);
504}
505
506template <class IntPtrT>
508 const char *End = DataBuffer->getBufferEnd();
509 // Skip zero padding between profiles.
510 while (CurrentPos != End && *CurrentPos == 0)
511 ++CurrentPos;
512 // If there's nothing left, we're done.
513 if (CurrentPos == End)
514 return make_error<InstrProfError>(instrprof_error::eof);
515 // If there isn't enough space for another header, this is probably just
516 // garbage at the end of the file.
517 if (CurrentPos + sizeof(RawInstrProf::Header) > End)
518 return make_error<InstrProfError>(instrprof_error::malformed,
519 "not enough space for another header");
520 // The writer ensures each profile is padded to start at an aligned address.
521 if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
522 return make_error<InstrProfError>(instrprof_error::malformed,
523 "insufficient padding");
524 // The magic should have the same byte order as in the previous header.
525 uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
526 if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
527 return make_error<InstrProfError>(instrprof_error::bad_magic);
528
529 // There's another profile to read, so we need to process the header.
530 auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
531 return readHeader(*Header);
532}
533
534template <class IntPtrT>
536 if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart)))
537 return error(std::move(E));
538 for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
539 const IntPtrT FPtr = swap(I->FunctionPointer);
540 if (!FPtr)
541 continue;
542 Symtab.mapAddress(FPtr, I->NameRef);
543 }
544 return success();
545}
546
547template <class IntPtrT>
549 const RawInstrProf::Header &Header) {
550 Version = swap(Header.Version);
551 if (GET_VERSION(Version) != RawInstrProf::Version)
553 ("Profile uses raw profile format version = " +
554 Twine(GET_VERSION(Version)) +
555 "; expected version = " + Twine(RawInstrProf::Version) +
556 "\nPLEASE update this tool to version in the raw profile, or "
557 "regenerate raw profile with expected version.")
558 .str());
559 if (useCorrelate() && !Correlator)
561 if (!useCorrelate() && Correlator)
563
564 uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
565 // Binary id start just after the header if exists.
566 const uint8_t *BinaryIdStart =
567 reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
568 const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
569 const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
570 if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
572 if (BinaryIdSize != 0) {
573 if (Error Err =
574 readBinaryIdsInternal(*DataBuffer, BinaryIdSize, BinaryIdStart,
575 BinaryIds, getDataEndianness()))
576 return Err;
577 }
578
579 CountersDelta = swap(Header.CountersDelta);
580 BitmapDelta = swap(Header.BitmapDelta);
581 NamesDelta = swap(Header.NamesDelta);
582 auto NumData = swap(Header.NumData);
583 auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
584 auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize();
585 auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
586 auto NumBitmapBytes = swap(Header.NumBitmapBytes);
587 auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes);
588 auto NamesSize = swap(Header.NamesSize);
589 ValueKindLast = swap(Header.ValueKindLast);
590
591 auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
592 auto PaddingSize = getNumPaddingBytes(NamesSize);
593
594 // Profile data starts after profile header and binary ids if exist.
595 ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdSize;
596 ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
597 ptrdiff_t BitmapOffset =
598 CountersOffset + CountersSize + PaddingBytesAfterCounters;
599 ptrdiff_t NamesOffset =
600 BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes;
601 ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
602
603 auto *Start = reinterpret_cast<const char *>(&Header);
604 if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
606
607 if (Correlator) {
608 // These sizes in the raw file are zero because we constructed them in the
609 // Correlator.
610 assert(DataSize == 0 && NamesSize == 0);
611 assert(CountersDelta == 0 && NamesDelta == 0);
612 Data = Correlator->getDataPointer();
613 DataEnd = Data + Correlator->getDataSize();
614 NamesStart = Correlator->getNamesPointer();
615 NamesEnd = NamesStart + Correlator->getNamesSize();
616 } else {
617 Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
618 Start + DataOffset);
619 DataEnd = Data + NumData;
620 NamesStart = Start + NamesOffset;
621 NamesEnd = NamesStart + NamesSize;
622 }
623
624 CountersStart = Start + CountersOffset;
625 CountersEnd = CountersStart + CountersSize;
626 BitmapStart = Start + BitmapOffset;
627 BitmapEnd = BitmapStart + NumBitmapBytes;
628 ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
629
630 std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
631 if (Error E = createSymtab(*NewSymtab))
632 return E;
633
634 Symtab = std::move(NewSymtab);
635 return success();
636}
637
638template <class IntPtrT>
640 Record.Name = getName(Data->NameRef);
641 return success();
642}
643
644template <class IntPtrT>
646 Record.Hash = swap(Data->FuncHash);
647 return success();
648}
649
650template <class IntPtrT>
653 uint32_t NumCounters = swap(Data->NumCounters);
654 if (NumCounters == 0)
655 return error(instrprof_error::malformed, "number of counters is zero");
656
657 ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
658 if (CounterBaseOffset < 0)
659 return error(
661 ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
662
663 if (CounterBaseOffset >= CountersEnd - CountersStart)
665 ("counter offset " + Twine(CounterBaseOffset) +
666 " is greater than the maximum counter offset " +
667 Twine(CountersEnd - CountersStart - 1))
668 .str());
669
670 uint64_t MaxNumCounters =
671 (CountersEnd - (CountersStart + CounterBaseOffset)) /
672 getCounterTypeSize();
673 if (NumCounters > MaxNumCounters)
675 ("number of counters " + Twine(NumCounters) +
676 " is greater than the maximum number of counters " +
677 Twine(MaxNumCounters))
678 .str());
679
680 Record.Counts.clear();
681 Record.Counts.reserve(NumCounters);
682 for (uint32_t I = 0; I < NumCounters; I++) {
683 const char *Ptr =
684 CountersStart + CounterBaseOffset + I * getCounterTypeSize();
685 if (I == 0 && hasTemporalProfile()) {
686 uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
687 if (TimestampValue != 0 &&
688 TimestampValue != std::numeric_limits<uint64_t>::max()) {
689 TemporalProfTimestamps.emplace_back(TimestampValue,
690 swap(Data->NameRef));
691 TemporalProfTraceStreamSize = 1;
692 }
693 if (hasSingleByteCoverage()) {
694 // In coverage mode, getCounterTypeSize() returns 1 byte but our
695 // timestamp field has size uint64_t. Increment I so that the next
696 // iteration of this for loop points to the byte after the timestamp
697 // field, i.e., I += 8.
698 I += 7;
699 }
700 continue;
701 }
702 if (hasSingleByteCoverage()) {
703 // A value of zero signifies the block is covered.
704 Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
705 } else {
706 uint64_t CounterValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
707 if (CounterValue > MaxCounterValue && Warn)
708 Warn(make_error<InstrProfError>(
710
711 Record.Counts.push_back(CounterValue);
712 }
713 }
714
715 return success();
716}
717
718template <class IntPtrT>
720 uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
721
722 Record.BitmapBytes.clear();
723 Record.BitmapBytes.reserve(NumBitmapBytes);
724
725 // It's possible MCDC is either not enabled or only used for some functions
726 // and not others. So if we record 0 bytes, just move on.
727 if (NumBitmapBytes == 0)
728 return success();
729
730 // BitmapDelta decreases as we advance to the next data record.
731 ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
732 if (BitmapOffset < 0)
733 return error(
735 ("bitmap offset " + Twine(BitmapOffset) + " is negative").str());
736
737 if (BitmapOffset >= BitmapEnd - BitmapStart)
739 ("bitmap offset " + Twine(BitmapOffset) +
740 " is greater than the maximum bitmap offset " +
741 Twine(BitmapEnd - BitmapStart - 1))
742 .str());
743
744 uint64_t MaxNumBitmapBytes =
745 (BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t);
746 if (NumBitmapBytes > MaxNumBitmapBytes)
748 ("number of bitmap bytes " + Twine(NumBitmapBytes) +
749 " is greater than the maximum number of bitmap bytes " +
750 Twine(MaxNumBitmapBytes))
751 .str());
752
753 for (uint32_t I = 0; I < NumBitmapBytes; I++) {
754 const char *Ptr = BitmapStart + BitmapOffset + I;
755 Record.BitmapBytes.push_back(swap(*Ptr));
756 }
757
758 return success();
759}
760
761template <class IntPtrT>
764 Record.clearValueData();
765 CurValueDataSize = 0;
766 // Need to match the logic in value profile dumper code in compiler-rt:
767 uint32_t NumValueKinds = 0;
768 for (uint32_t I = 0; I < IPVK_Last + 1; I++)
769 NumValueKinds += (Data->NumValueSites[I] != 0);
770
771 if (!NumValueKinds)
772 return success();
773
775 ValueProfData::getValueProfData(
776 ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
777 getDataEndianness());
778
779 if (Error E = VDataPtrOrErr.takeError())
780 return E;
781
782 // Note that besides deserialization, this also performs the conversion for
783 // indirect call targets. The function pointers from the raw profile are
784 // remapped into function name hashes.
785 VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
786 CurValueDataSize = VDataPtrOrErr.get()->getSize();
787 return success();
788}
789
790template <class IntPtrT>
792 // Keep reading profiles that consist of only headers and no profile data and
793 // counters.
794 while (atEnd())
795 // At this point, ValueDataStart field points to the next header.
796 if (Error E = readNextHeader(getNextHeaderPos()))
797 return error(std::move(E));
798
799 // Read name and set it in Record.
800 if (Error E = readName(Record))
801 return error(std::move(E));
802
803 // Read FuncHash and set it in Record.
804 if (Error E = readFuncHash(Record))
805 return error(std::move(E));
806
807 // Read raw counts and set Record.
808 if (Error E = readRawCounts(Record))
809 return error(std::move(E));
810
811 // Read raw bitmap bytes and set Record.
812 if (Error E = readRawBitmapBytes(Record))
813 return error(std::move(E));
814
815 // Read value data and set Record.
816 if (Error E = readValueProfilingData(Record))
817 return error(std::move(E));
818
819 // Iterate.
820 advanceData();
821 return success();
822}
823
824template <class IntPtrT>
826 std::vector<llvm::object::BuildID> &BinaryIds) {
827 BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(),
828 this->BinaryIds.end());
829 return Error::success();
830}
831
832template <class IntPtrT>
834 if (!BinaryIds.empty())
835 printBinaryIdsInternal(OS, BinaryIds);
836 return Error::success();
837}
838
839namespace llvm {
840
841template class RawInstrProfReader<uint32_t>;
842template class RawInstrProfReader<uint64_t>;
843
844} // end namespace llvm
845
848 return IndexedInstrProf::ComputeHash(HashType, K);
849}
850
853
855 const unsigned char *&D, const unsigned char *const End) {
857 ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
858
859 if (VDataPtrOrErr.takeError())
860 return false;
861
862 VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
863 D += VDataPtrOrErr.get()->TotalSize;
864
865 return true;
866}
867
869 offset_type N) {
870 using namespace support;
871
872 // Check if the data is corrupt. If so, don't try to read it.
873 if (N % sizeof(uint64_t))
874 return data_type();
875
876 DataBuffer.clear();
877 std::vector<uint64_t> CounterBuffer;
878 std::vector<uint8_t> BitmapByteBuffer;
879
880 const unsigned char *End = D + N;
881 while (D < End) {
882 // Read hash.
883 if (D + sizeof(uint64_t) >= End)
884 return data_type();
885 uint64_t Hash =
886 endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
887
888 // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
889 uint64_t CountsSize = N / sizeof(uint64_t) - 1;
890 // If format version is different then read the number of counters.
891 if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
892 if (D + sizeof(uint64_t) > End)
893 return data_type();
894 CountsSize =
895 endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
896 }
897 // Read counter values.
898 if (D + CountsSize * sizeof(uint64_t) > End)
899 return data_type();
900
901 CounterBuffer.clear();
902 CounterBuffer.reserve(CountsSize);
903 for (uint64_t J = 0; J < CountsSize; ++J)
904 CounterBuffer.push_back(
905 endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D));
906
907 // Read bitmap bytes for GET_VERSION(FormatVersion) > 10.
908 if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) {
909 uint64_t BitmapBytes = 0;
910 if (D + sizeof(uint64_t) > End)
911 return data_type();
912 BitmapBytes =
913 endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
914 // Read bitmap byte values.
915 if (D + BitmapBytes * sizeof(uint8_t) > End)
916 return data_type();
917 BitmapByteBuffer.clear();
918 BitmapByteBuffer.reserve(BitmapBytes);
919 for (uint64_t J = 0; J < BitmapBytes; ++J)
920 BitmapByteBuffer.push_back(static_cast<uint8_t>(
921 endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
922 D)));
923 }
924
925 DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer),
926 std::move(BitmapByteBuffer));
927
928 // Read value profiling data.
929 if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
931 DataBuffer.clear();
932 return data_type();
933 }
934 }
935 return DataBuffer;
936}
937
938template <typename HashTableImpl>
941 auto Iter = HashTable->find(FuncName);
942 if (Iter == HashTable->end())
943 return make_error<InstrProfError>(instrprof_error::unknown_function);
944
945 Data = (*Iter);
946 if (Data.empty())
947 return make_error<InstrProfError>(instrprof_error::malformed,
948 "profile data is empty");
949
950 return Error::success();
951}
952
953template <typename HashTableImpl>
956 if (atEnd())
957 return make_error<InstrProfError>(instrprof_error::eof);
958
959 Data = *RecordIterator;
960
961 if (Data.empty())
962 return make_error<InstrProfError>(instrprof_error::malformed,
963 "profile data is empty");
964
965 return Error::success();
966}
967
968template <typename HashTableImpl>
970 const unsigned char *Buckets, const unsigned char *const Payload,
971 const unsigned char *const Base, IndexedInstrProf::HashT HashType,
972 uint64_t Version) {
973 FormatVersion = Version;
974 HashTable.reset(HashTableImpl::Create(
975 Buckets, Payload, Base,
976 typename HashTableImpl::InfoType(HashType, Version)));
977 RecordIterator = HashTable->data_begin();
978}
979
980template <typename HashTableImpl>
982 return getProfileKindFromVersion(FormatVersion);
983}
984
985namespace {
986/// A remapper that does not apply any remappings.
987class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
988 InstrProfReaderIndexBase &Underlying;
989
990public:
991 InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
992 : Underlying(Underlying) {}
993
994 Error getRecords(StringRef FuncName,
995 ArrayRef<NamedInstrProfRecord> &Data) override {
996 return Underlying.getRecords(FuncName, Data);
997 }
998};
999} // namespace
1000
1001/// A remapper that applies remappings based on a symbol remapping file.
1002template <typename HashTableImpl>
1004 : public InstrProfReaderRemapper {
1005public:
1007 std::unique_ptr<MemoryBuffer> RemapBuffer,
1009 : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
1010 }
1011
1012 /// Extract the original function name from a PGO function name.
1014 // We can have multiple :-separated pieces; there can be pieces both
1015 // before and after the mangled name. Find the first part that starts
1016 // with '_Z'; we'll assume that's the mangled name we want.
1017 std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
1018 while (true) {
1019 Parts = Parts.second.split(':');
1020 if (Parts.first.startswith("_Z"))
1021 return Parts.first;
1022 if (Parts.second.empty())
1023 return Name;
1024 }
1025 }
1026
1027 /// Given a mangled name extracted from a PGO function name, and a new
1028 /// form for that mangled name, reconstitute the name.
1029 static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
1030 StringRef Replacement,
1031 SmallVectorImpl<char> &Out) {
1032 Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
1033 Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
1034 Out.insert(Out.end(), Replacement.begin(), Replacement.end());
1035 Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
1036 }
1037
1039 if (Error E = Remappings.read(*RemapBuffer))
1040 return E;
1041 for (StringRef Name : Underlying.HashTable->keys()) {
1042 StringRef RealName = extractName(Name);
1043 if (auto Key = Remappings.insert(RealName)) {
1044 // FIXME: We could theoretically map the same equivalence class to
1045 // multiple names in the profile data. If that happens, we should
1046 // return NamedInstrProfRecords from all of them.
1047 MappedNames.insert({Key, RealName});
1048 }
1049 }
1050 return Error::success();
1051 }
1052
1055 StringRef RealName = extractName(FuncName);
1056 if (auto Key = Remappings.lookup(RealName)) {
1057 StringRef Remapped = MappedNames.lookup(Key);
1058 if (!Remapped.empty()) {
1059 if (RealName.begin() == FuncName.begin() &&
1060 RealName.end() == FuncName.end())
1061 FuncName = Remapped;
1062 else {
1063 // Try rebuilding the name from the given remapping.
1064 SmallString<256> Reconstituted;
1065 reconstituteName(FuncName, RealName, Remapped, Reconstituted);
1066 Error E = Underlying.getRecords(Reconstituted, Data);
1067 if (!E)
1068 return E;
1069
1070 // If we failed because the name doesn't exist, fall back to asking
1071 // about the original name.
1072 if (Error Unhandled = handleErrors(
1073 std::move(E), [](std::unique_ptr<InstrProfError> Err) {
1074 return Err->get() == instrprof_error::unknown_function
1075 ? Error::success()
1076 : Error(std::move(Err));
1077 }))
1078 return Unhandled;
1079 }
1080 }
1081 }
1082 return Underlying.getRecords(FuncName, Data);
1083 }
1084
1085private:
1086 /// The memory buffer containing the remapping configuration. Remappings
1087 /// holds pointers into this buffer.
1088 std::unique_ptr<MemoryBuffer> RemapBuffer;
1089
1090 /// The mangling remapper.
1091 SymbolRemappingReader Remappings;
1092
1093 /// Mapping from mangled name keys to the name used for the key in the
1094 /// profile data.
1095 /// FIXME: Can we store a location within the on-disk hash table instead of
1096 /// redoing lookup?
1098
1099 /// The real profile data reader.
1101};
1102
1104 using namespace support;
1105
1106 if (DataBuffer.getBufferSize() < 8)
1107 return false;
1108 uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(
1109 DataBuffer.getBufferStart());
1110 // Verify that it's magical.
1111 return Magic == IndexedInstrProf::Magic;
1112}
1113
1114const unsigned char *
1115IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
1116 const unsigned char *Cur, bool UseCS) {
1117 using namespace IndexedInstrProf;
1118 using namespace support;
1119
1120 if (Version >= IndexedInstrProf::Version4) {
1121 const IndexedInstrProf::Summary *SummaryInLE =
1122 reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
1123 uint64_t NFields = endian::byte_swap<uint64_t, llvm::endianness::little>(
1124 SummaryInLE->NumSummaryFields);
1125 uint64_t NEntries = endian::byte_swap<uint64_t, llvm::endianness::little>(
1126 SummaryInLE->NumCutoffEntries);
1127 uint32_t SummarySize =
1128 IndexedInstrProf::Summary::getSize(NFields, NEntries);
1129 std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
1130 IndexedInstrProf::allocSummary(SummarySize);
1131
1132 const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
1133 uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
1134 for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
1135 Dst[I] = endian::byte_swap<uint64_t, llvm::endianness::little>(Src[I]);
1136
1137 SummaryEntryVector DetailedSummary;
1138 for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
1139 const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
1140 DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
1141 Ent.NumBlocks);
1142 }
1143 std::unique_ptr<llvm::ProfileSummary> &Summary =
1144 UseCS ? this->CS_Summary : this->Summary;
1145
1146 // initialize InstrProfSummary using the SummaryData from disk.
1147 Summary = std::make_unique<ProfileSummary>(
1149 DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
1150 SummaryData->get(Summary::MaxBlockCount),
1151 SummaryData->get(Summary::MaxInternalBlockCount),
1152 SummaryData->get(Summary::MaxFunctionCount),
1153 SummaryData->get(Summary::TotalNumBlocks),
1154 SummaryData->get(Summary::TotalNumFunctions));
1155 return Cur + SummarySize;
1156 } else {
1157 // The older versions do not support a profile summary. This just computes
1158 // an empty summary, which will not result in accurate hot/cold detection.
1159 // We would need to call addRecord for all NamedInstrProfRecords to get the
1160 // correct summary. However, this version is old (prior to early 2016) and
1161 // has not been supporting an accurate summary for several years.
1163 Summary = Builder.getSummary();
1164 return Cur;
1165 }
1166}
1167
1169 using namespace support;
1170
1171 const unsigned char *Start =
1172 (const unsigned char *)DataBuffer->getBufferStart();
1173 const unsigned char *Cur = Start;
1174 if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
1176
1177 auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
1178 if (!HeaderOr)
1179 return HeaderOr.takeError();
1180
1181 const IndexedInstrProf::Header *Header = &HeaderOr.get();
1182 Cur += Header->size();
1183
1184 Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
1185 /* UseCS */ false);
1186 if (Header->formatVersion() & VARIANT_MASK_CSIR_PROF)
1187 Cur =
1188 readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
1189 /* UseCS */ true);
1190 // Read the hash type and start offset.
1191 IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
1192 endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashType));
1193 if (HashType > IndexedInstrProf::HashT::Last)
1195
1196 uint64_t HashOffset =
1197 endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashOffset);
1198
1199 // The hash table with profile counts comes next.
1200 auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
1201 Start + HashOffset, Cur, Start, HashType, Header->formatVersion());
1202
1203 // The MemProfOffset field in the header is only valid when the format
1204 // version is higher than 8 (when it was introduced).
1205 if (GET_VERSION(Header->formatVersion()) >= 8 &&
1206 Header->formatVersion() & VARIANT_MASK_MEMPROF) {
1207 uint64_t MemProfOffset =
1208 endian::byte_swap<uint64_t, llvm::endianness::little>(
1209 Header->MemProfOffset);
1210
1211 const unsigned char *Ptr = Start + MemProfOffset;
1212 // The value returned from RecordTableGenerator.Emit.
1213 const uint64_t RecordTableOffset =
1215 unaligned>(Ptr);
1216 // The offset in the stream right before invoking
1217 // FrameTableGenerator.Emit.
1218 const uint64_t FramePayloadOffset =
1220 unaligned>(Ptr);
1221 // The value returned from FrameTableGenerator.Emit.
1222 const uint64_t FrameTableOffset =
1224 unaligned>(Ptr);
1225
1226 // Read the schema.
1227 auto SchemaOr = memprof::readMemProfSchema(Ptr);
1228 if (!SchemaOr)
1229 return SchemaOr.takeError();
1230 Schema = SchemaOr.get();
1231
1232 // Now initialize the table reader with a pointer into data buffer.
1233 MemProfRecordTable.reset(MemProfRecordHashTable::Create(
1234 /*Buckets=*/Start + RecordTableOffset,
1235 /*Payload=*/Ptr,
1236 /*Base=*/Start, memprof::RecordLookupTrait(Schema)));
1237
1238 // Initialize the frame table reader with the payload and bucket offsets.
1239 MemProfFrameTable.reset(MemProfFrameHashTable::Create(
1240 /*Buckets=*/Start + FrameTableOffset,
1241 /*Payload=*/Start + FramePayloadOffset,
1242 /*Base=*/Start, memprof::FrameLookupTrait()));
1243 }
1244
1245 // BinaryIdOffset field in the header is only valid when the format version
1246 // is higher than 9 (when it was introduced).
1247 if (GET_VERSION(Header->formatVersion()) >= 9) {
1248 uint64_t BinaryIdOffset =
1249 endian::byte_swap<uint64_t, llvm::endianness::little>(
1250 Header->BinaryIdOffset);
1251 const unsigned char *Ptr = Start + BinaryIdOffset;
1252 // Read binary ids size.
1253 BinaryIdsSize =
1255 unaligned>(Ptr);
1256 if (BinaryIdsSize % sizeof(uint64_t))
1258 // Set the binary ids start.
1259 BinaryIdsStart = Ptr;
1260 if (BinaryIdsStart > (const unsigned char *)DataBuffer->getBufferEnd())
1261 return make_error<InstrProfError>(instrprof_error::malformed,
1262 "corrupted binary ids");
1263 }
1264
1265 if (GET_VERSION(Header->formatVersion()) >= 10 &&
1266 Header->formatVersion() & VARIANT_MASK_TEMPORAL_PROF) {
1267 uint64_t TemporalProfTracesOffset =
1268 endian::byte_swap<uint64_t, llvm::endianness::little>(
1269 Header->TemporalProfTracesOffset);
1270 const unsigned char *Ptr = Start + TemporalProfTracesOffset;
1271 const auto *PtrEnd = (const unsigned char *)DataBuffer->getBufferEnd();
1272 // Expect at least two 64 bit fields: NumTraces, and TraceStreamSize
1273 if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1275 const uint64_t NumTraces =
1277 unaligned>(Ptr);
1280 unaligned>(Ptr);
1281 for (unsigned i = 0; i < NumTraces; i++) {
1282 // Expect at least two 64 bit fields: Weight and NumFunctions
1283 if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1286 Trace.Weight =
1288 unaligned>(Ptr);
1289 const uint64_t NumFunctions =
1291 unaligned>(Ptr);
1292 // Expect at least NumFunctions 64 bit fields
1293 if (Ptr + NumFunctions * sizeof(uint64_t) > PtrEnd)
1295 for (unsigned j = 0; j < NumFunctions; j++) {
1296 const uint64_t NameRef =
1298 unaligned>(Ptr);
1299 Trace.FunctionNameRefs.push_back(NameRef);
1300 }
1301 TemporalProfTraces.push_back(std::move(Trace));
1302 }
1303 }
1304
1305 // Load the remapping table now if requested.
1306 if (RemappingBuffer) {
1307 Remapper =
1308 std::make_unique<InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
1309 std::move(RemappingBuffer), *IndexPtr);
1310 if (Error E = Remapper->populateRemappings())
1311 return E;
1312 } else {
1313 Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
1314 }
1315 Index = std::move(IndexPtr);
1316
1317 return success();
1318}
1319
1321 if (Symtab)
1322 return *Symtab;
1323
1324 std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
1325 if (Error E = Index->populateSymtab(*NewSymtab)) {
1326 auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1327 consumeError(error(ErrCode, Msg));
1328 }
1329
1330 Symtab = std::move(NewSymtab);
1331 return *Symtab;
1332}
1333
1335 StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName,
1336 uint64_t *MismatchedFuncSum) {
1338 uint64_t FuncSum = 0;
1339 auto Err = Remapper->getRecords(FuncName, Data);
1340 if (Err) {
1341 // If we don't find FuncName, try DeprecatedFuncName to handle profiles
1342 // built by older compilers.
1343 auto Err2 =
1344 handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
1345 if (IE.get() != instrprof_error::unknown_function)
1346 return make_error<InstrProfError>(IE);
1347 if (auto Err = Remapper->getRecords(DeprecatedFuncName, Data))
1348 return Err;
1349 return Error::success();
1350 });
1351 if (Err2)
1352 return std::move(Err2);
1353 }
1354 // Found it. Look for counters with the right hash.
1355
1356 // A flag to indicate if the records are from the same type
1357 // of profile (i.e cs vs nocs).
1358 bool CSBitMatch = false;
1359 auto getFuncSum = [](const std::vector<uint64_t> &Counts) {
1360 uint64_t ValueSum = 0;
1361 for (uint64_t CountValue : Counts) {
1362 if (CountValue == (uint64_t)-1)
1363 continue;
1364 // Handle overflow -- if that happens, return max.
1365 if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1366 return std::numeric_limits<uint64_t>::max();
1367 ValueSum += CountValue;
1368 }
1369 return ValueSum;
1370 };
1371
1372 for (const NamedInstrProfRecord &I : Data) {
1373 // Check for a match and fill the vector if there is one.
1374 if (I.Hash == FuncHash)
1375 return std::move(I);
1378 CSBitMatch = true;
1379 if (MismatchedFuncSum == nullptr)
1380 continue;
1381 FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
1382 }
1383 }
1384 if (CSBitMatch) {
1385 if (MismatchedFuncSum != nullptr)
1386 *MismatchedFuncSum = FuncSum;
1388 }
1390}
1391
1394 // TODO: Add memprof specific errors.
1395 if (MemProfRecordTable == nullptr)
1396 return make_error<InstrProfError>(instrprof_error::invalid_prof,
1397 "no memprof data available in profile");
1398 auto Iter = MemProfRecordTable->find(FuncNameHash);
1399 if (Iter == MemProfRecordTable->end())
1400 return make_error<InstrProfError>(
1402 "memprof record not found for function hash " + Twine(FuncNameHash));
1403
1404 // Setup a callback to convert from frame ids to frame using the on-disk
1405 // FrameData hash table.
1406 memprof::FrameId LastUnmappedFrameId = 0;
1407 bool HasFrameMappingError = false;
1408 auto IdToFrameCallback = [&](const memprof::FrameId Id) {
1409 auto FrIter = MemProfFrameTable->find(Id);
1410 if (FrIter == MemProfFrameTable->end()) {
1411 LastUnmappedFrameId = Id;
1412 HasFrameMappingError = true;
1413 return memprof::Frame(0, 0, 0, false);
1414 }
1415 return *FrIter;
1416 };
1417
1418 memprof::MemProfRecord Record(*Iter, IdToFrameCallback);
1419
1420 // Check that all frame ids were successfully converted to frames.
1421 if (HasFrameMappingError) {
1422 return make_error<InstrProfError>(instrprof_error::hash_mismatch,
1423 "memprof frame not found for frame id " +
1424 Twine(LastUnmappedFrameId));
1425 }
1426 return Record;
1427}
1428
1430 uint64_t FuncHash,
1431 std::vector<uint64_t> &Counts) {
1433 if (Error E = Record.takeError())
1434 return error(std::move(E));
1435
1436 Counts = Record.get().Counts;
1437 return success();
1438}
1439
1441 StringRef FuncName, uint64_t FuncHash, std::vector<uint8_t> &BitmapBytes) {
1443 if (Error E = Record.takeError())
1444 return error(std::move(E));
1445
1446 BitmapBytes = Record.get().BitmapBytes;
1447 return success();
1448}
1449
1452
1453 Error E = Index->getRecords(Data);
1454 if (E)
1455 return error(std::move(E));
1456
1457 Record = Data[RecordIndex++];
1458 if (RecordIndex >= Data.size()) {
1459 Index->advanceToNextKey();
1460 RecordIndex = 0;
1461 }
1462 return success();
1463}
1464
1466 std::vector<llvm::object::BuildID> &BinaryIds) {
1467 return readBinaryIdsInternal(*DataBuffer, BinaryIdsSize, BinaryIdsStart,
1468 BinaryIds, llvm::endianness::little);
1469}
1470
1472 std::vector<llvm::object::BuildID> BinaryIds;
1473 if (Error E = readBinaryIds(BinaryIds))
1474 return E;
1475 printBinaryIdsInternal(OS, BinaryIds);
1476 return Error::success();
1477}
1478
1480 uint64_t NumFuncs = 0;
1481 for (const auto &Func : *this) {
1482 if (isIRLevelProfile()) {
1483 bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
1484 if (FuncIsCS != IsCS)
1485 continue;
1486 }
1487 Func.accumulateCounts(Sum);
1488 ++NumFuncs;
1489 }
1490 Sum.NumEntries = NumFuncs;
1491}
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the DenseMap class.
std::string Name
bool End
Definition: ELF_riscv.cpp:478
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
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.
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 getFunctionBitmapBytes(StringRef FuncName, uint64_t FuncHash, std::vector< uint8_t > &BitmapBytes)
Fill Bitmap Bytes 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:390
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 PGO name look-up with keys (such as pointers, md5hash values) to the...
Definition: InstrProf.h:425
static bool isExternalSymbol(const StringRef &Symbol)
True if Symbol is the value used to represent external symbols.
Definition: InstrProf.h:525
void mapAddress(uint64_t Addr, uint64_t MD5Val)
Map a function address to its name's MD5 hash.
Definition: InstrProf.h:503
Error create(object::SectionRef &Section)
Create InstrProfSymtab from an object file section which contains function PGO names.
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:577
void reserve(size_type N)
Definition: SmallVector.h:667
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:809
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
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:704
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:474
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:575
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
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
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:737
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:1141
uint64_t ComputeHash(StringRef K)
Definition: InstrProf.h:1031
const uint64_t Version
Definition: InstrProf.h:1027
const uint64_t Magic
Definition: InstrProf.h:990
const uint64_t Version
Definition: InstrProf.h:1163
Expected< MemProfSchema > readMemProfSchema(const unsigned char *&Buffer)
Definition: MemProf.cpp:94
value_type readNext(const CharT *&memory, endianness endian)
Read a value of a particular endianness from a buffer, and increment the buffer past that value.
Definition: Endian.h:76
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
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:1918
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:1853
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:297
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:1495
uint64_t Cutoff
The required percentile of total execution count.
Definition: InstrProf.h:1065
uint64_t NumBlocks
Number of blocks >= the minumum execution count.
Definition: InstrProf.h:1068
uint64_t MinBlockCount
The minimum execution count for this percentile.
Definition: InstrProf.h:1067
static uint32_t getSize(uint32_t NumSumFields, uint32_t NumCutoffEntries)
Definition: InstrProf.h:1101
Profiling information for a single function.
Definition: InstrProf.h:689
static bool hasCSFlagInHash(uint64_t FuncHash)
Definition: InstrProf.h:892
An ordered list of functions identified by their NameRef found in INSTR_PROF_DATA.
Definition: InstrProf.h:351