LLVM 17.0.0git
SampleProfReader.cpp
Go to the documentation of this file.
1//===- SampleProfReader.cpp - Read LLVM sample profile data ---------------===//
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 implements the class that reads LLVM sample profiles. It
10// supports three file formats: text, binary and gcov.
11//
12// The textual representation is useful for debugging and testing purposes. The
13// binary representation is more compact, resulting in smaller file sizes.
14//
15// The gcov encoding is the one generated by GCC's AutoFDO profile creation
16// tool (https://github.com/google/autofdo)
17//
18// All three encodings can be used interchangeably as an input sample profile.
19//
20//===----------------------------------------------------------------------===//
21
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/IR/Module.h"
33#include "llvm/Support/JSON.h"
34#include "llvm/Support/LEB128.h"
36#include "llvm/Support/MD5.h"
40#include <algorithm>
41#include <cstddef>
42#include <cstdint>
43#include <limits>
44#include <memory>
45#include <system_error>
46#include <vector>
47
48using namespace llvm;
49using namespace sampleprof;
50
51#define DEBUG_TYPE "samplepgo-reader"
52
53// This internal option specifies if the profile uses FS discriminators.
54// It only applies to text, binary and compact binary format profiles.
55// For ext-binary format profiles, the flag is set in the summary.
57 "profile-isfs", cl::Hidden, cl::init(false),
58 cl::desc("Profile uses flow sensitive discriminators"));
59
60/// Dump the function profile for \p FName.
61///
62/// \param FContext Name + context of the function to print.
63/// \param OS Stream to emit the output to.
65 raw_ostream &OS) {
66 OS << "Function: " << FContext.toString() << ": " << Profiles[FContext];
67}
68
69/// Dump all the function profiles found on stream \p OS.
71 std::vector<NameFunctionSamples> V;
73 for (const auto &I : V)
74 dumpFunctionProfile(I.first, OS);
75}
76
78 json::OStream &JOS, bool TopLevel = false) {
79 auto DumpBody = [&](const BodySampleMap &BodySamples) {
80 for (const auto &I : BodySamples) {
81 const LineLocation &Loc = I.first;
82 const SampleRecord &Sample = I.second;
83 JOS.object([&] {
84 JOS.attribute("line", Loc.LineOffset);
85 if (Loc.Discriminator)
86 JOS.attribute("discriminator", Loc.Discriminator);
87 JOS.attribute("samples", Sample.getSamples());
88
89 auto CallTargets = Sample.getSortedCallTargets();
90 if (!CallTargets.empty()) {
91 JOS.attributeArray("calls", [&] {
92 for (const auto &J : CallTargets) {
93 JOS.object([&] {
94 JOS.attribute("function", J.first);
95 JOS.attribute("samples", J.second);
96 });
97 }
98 });
99 }
100 });
101 }
102 };
103
104 auto DumpCallsiteSamples = [&](const CallsiteSampleMap &CallsiteSamples) {
105 for (const auto &I : CallsiteSamples)
106 for (const auto &FS : I.second) {
107 const LineLocation &Loc = I.first;
108 const FunctionSamples &CalleeSamples = FS.second;
109 JOS.object([&] {
110 JOS.attribute("line", Loc.LineOffset);
111 if (Loc.Discriminator)
112 JOS.attribute("discriminator", Loc.Discriminator);
113 JOS.attributeArray(
114 "samples", [&] { dumpFunctionProfileJson(CalleeSamples, JOS); });
115 });
116 }
117 };
118
119 JOS.object([&] {
120 JOS.attribute("name", S.getName());
121 JOS.attribute("total", S.getTotalSamples());
122 if (TopLevel)
123 JOS.attribute("head", S.getHeadSamples());
124
125 const auto &BodySamples = S.getBodySamples();
126 if (!BodySamples.empty())
127 JOS.attributeArray("body", [&] { DumpBody(BodySamples); });
128
129 const auto &CallsiteSamples = S.getCallsiteSamples();
130 if (!CallsiteSamples.empty())
131 JOS.attributeArray("callsites",
132 [&] { DumpCallsiteSamples(CallsiteSamples); });
133 });
134}
135
136/// Dump all the function profiles found on stream \p OS in the JSON format.
138 std::vector<NameFunctionSamples> V;
140 json::OStream JOS(OS, 2);
141 JOS.arrayBegin();
142 for (const auto &F : V)
143 dumpFunctionProfileJson(*F.second, JOS, true);
144 JOS.arrayEnd();
145
146 // Emit a newline character at the end as json::OStream doesn't emit one.
147 OS << "\n";
148}
149
150/// Parse \p Input as function head.
151///
152/// Parse one line of \p Input, and update function name in \p FName,
153/// function's total sample count in \p NumSamples, function's entry
154/// count in \p NumHeadSamples.
155///
156/// \returns true if parsing is successful.
157static bool ParseHead(const StringRef &Input, StringRef &FName,
158 uint64_t &NumSamples, uint64_t &NumHeadSamples) {
159 if (Input[0] == ' ')
160 return false;
161 size_t n2 = Input.rfind(':');
162 size_t n1 = Input.rfind(':', n2 - 1);
163 FName = Input.substr(0, n1);
164 if (Input.substr(n1 + 1, n2 - n1 - 1).getAsInteger(10, NumSamples))
165 return false;
166 if (Input.substr(n2 + 1).getAsInteger(10, NumHeadSamples))
167 return false;
168 return true;
169}
170
171/// Returns true if line offset \p L is legal (only has 16 bits).
172static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; }
173
174/// Parse \p Input that contains metadata.
175/// Possible metadata:
176/// - CFG Checksum information:
177/// !CFGChecksum: 12345
178/// - CFG Checksum information:
179/// !Attributes: 1
180/// Stores the FunctionHash (a.k.a. CFG Checksum) into \p FunctionHash.
181static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash,
182 uint32_t &Attributes) {
183 if (Input.startswith("!CFGChecksum:")) {
184 StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim();
185 return !CFGInfo.getAsInteger(10, FunctionHash);
186 }
187
188 if (Input.startswith("!Attributes:")) {
189 StringRef Attrib = Input.substr(strlen("!Attributes:")).trim();
190 return !Attrib.getAsInteger(10, Attributes);
191 }
192
193 return false;
194}
195
196enum class LineType {
199 Metadata,
200};
201
202/// Parse \p Input as line sample.
203///
204/// \param Input input line.
205/// \param LineTy Type of this line.
206/// \param Depth the depth of the inline stack.
207/// \param NumSamples total samples of the line/inlined callsite.
208/// \param LineOffset line offset to the start of the function.
209/// \param Discriminator discriminator of the line.
210/// \param TargetCountMap map from indirect call target to count.
211/// \param FunctionHash the function's CFG hash, used by pseudo probe.
212///
213/// returns true if parsing is successful.
214static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth,
215 uint64_t &NumSamples, uint32_t &LineOffset,
216 uint32_t &Discriminator, StringRef &CalleeName,
217 DenseMap<StringRef, uint64_t> &TargetCountMap,
218 uint64_t &FunctionHash, uint32_t &Attributes) {
219 for (Depth = 0; Input[Depth] == ' '; Depth++)
220 ;
221 if (Depth == 0)
222 return false;
223
224 if (Input[Depth] == '!') {
225 LineTy = LineType::Metadata;
226 return parseMetadata(Input.substr(Depth), FunctionHash, Attributes);
227 }
228
229 size_t n1 = Input.find(':');
230 StringRef Loc = Input.substr(Depth, n1 - Depth);
231 size_t n2 = Loc.find('.');
232 if (n2 == StringRef::npos) {
233 if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset))
234 return false;
235 Discriminator = 0;
236 } else {
237 if (Loc.substr(0, n2).getAsInteger(10, LineOffset))
238 return false;
239 if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator))
240 return false;
241 }
242
243 StringRef Rest = Input.substr(n1 + 2);
244 if (isDigit(Rest[0])) {
245 LineTy = LineType::BodyProfile;
246 size_t n3 = Rest.find(' ');
247 if (n3 == StringRef::npos) {
248 if (Rest.getAsInteger(10, NumSamples))
249 return false;
250 } else {
251 if (Rest.substr(0, n3).getAsInteger(10, NumSamples))
252 return false;
253 }
254 // Find call targets and their sample counts.
255 // Note: In some cases, there are symbols in the profile which are not
256 // mangled. To accommodate such cases, use colon + integer pairs as the
257 // anchor points.
258 // An example:
259 // _M_construct<char *>:1000 string_view<std::allocator<char> >:437
260 // ":1000" and ":437" are used as anchor points so the string above will
261 // be interpreted as
262 // target: _M_construct<char *>
263 // count: 1000
264 // target: string_view<std::allocator<char> >
265 // count: 437
266 while (n3 != StringRef::npos) {
267 n3 += Rest.substr(n3).find_first_not_of(' ');
268 Rest = Rest.substr(n3);
269 n3 = Rest.find_first_of(':');
270 if (n3 == StringRef::npos || n3 == 0)
271 return false;
272
274 uint64_t count, n4;
275 while (true) {
276 // Get the segment after the current colon.
277 StringRef AfterColon = Rest.substr(n3 + 1);
278 // Get the target symbol before the current colon.
279 Target = Rest.substr(0, n3);
280 // Check if the word after the current colon is an integer.
281 n4 = AfterColon.find_first_of(' ');
282 n4 = (n4 != StringRef::npos) ? n3 + n4 + 1 : Rest.size();
283 StringRef WordAfterColon = Rest.substr(n3 + 1, n4 - n3 - 1);
284 if (!WordAfterColon.getAsInteger(10, count))
285 break;
286
287 // Try to find the next colon.
288 uint64_t n5 = AfterColon.find_first_of(':');
289 if (n5 == StringRef::npos)
290 return false;
291 n3 += n5 + 1;
292 }
293
294 // An anchor point is found. Save the {target, count} pair
295 TargetCountMap[Target] = count;
296 if (n4 == Rest.size())
297 break;
298 // Change n3 to the next blank space after colon + integer pair.
299 n3 = n4;
300 }
301 } else {
302 LineTy = LineType::CallSiteProfile;
303 size_t n3 = Rest.find_last_of(':');
304 CalleeName = Rest.substr(0, n3);
305 if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
306 return false;
307 }
308 return true;
309}
310
311/// Load samples from a text file.
312///
313/// See the documentation at the top of the file for an explanation of
314/// the expected format.
315///
316/// \returns true if the file was loaded successfully, false otherwise.
318 line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
320
321 InlineCallStack InlineStack;
322 uint32_t TopLevelProbeProfileCount = 0;
323
324 // DepthMetadata tracks whether we have processed metadata for the current
325 // top-level or nested function profile.
326 uint32_t DepthMetadata = 0;
327
330 for (; !LineIt.is_at_eof(); ++LineIt) {
331 size_t pos = LineIt->find_first_not_of(' ');
332 if (pos == LineIt->npos || (*LineIt)[pos] == '#')
333 continue;
334 // Read the header of each function.
335 //
336 // Note that for function identifiers we are actually expecting
337 // mangled names, but we may not always get them. This happens when
338 // the compiler decides not to emit the function (e.g., it was inlined
339 // and removed). In this case, the binary will not have the linkage
340 // name for the function, so the profiler will emit the function's
341 // unmangled name, which may contain characters like ':' and '>' in its
342 // name (member functions, templates, etc).
343 //
344 // The only requirement we place on the identifier, then, is that it
345 // should not begin with a number.
346 if ((*LineIt)[0] != ' ') {
347 uint64_t NumSamples, NumHeadSamples;
348 StringRef FName;
349 if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) {
350 reportError(LineIt.line_number(),
351 "Expected 'mangled_name:NUM:NUM', found " + *LineIt);
353 }
354 DepthMetadata = 0;
355 SampleContext FContext(FName, CSNameTable);
356 if (FContext.hasContext())
358 Profiles[FContext] = FunctionSamples();
359 FunctionSamples &FProfile = Profiles[FContext];
360 FProfile.setContext(FContext);
361 MergeResult(Result, FProfile.addTotalSamples(NumSamples));
362 MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
363 InlineStack.clear();
364 InlineStack.push_back(&FProfile);
365 } else {
366 uint64_t NumSamples;
367 StringRef FName;
368 DenseMap<StringRef, uint64_t> TargetCountMap;
369 uint32_t Depth, LineOffset, Discriminator;
370 LineType LineTy;
371 uint64_t FunctionHash = 0;
373 if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
374 Discriminator, FName, TargetCountMap, FunctionHash,
375 Attributes)) {
376 reportError(LineIt.line_number(),
377 "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
378 *LineIt);
380 }
381 if (LineTy != LineType::Metadata && Depth == DepthMetadata) {
382 // Metadata must be put at the end of a function profile.
383 reportError(LineIt.line_number(),
384 "Found non-metadata after metadata: " + *LineIt);
386 }
387
388 // Here we handle FS discriminators.
389 Discriminator &= getDiscriminatorMask();
390
391 while (InlineStack.size() > Depth) {
392 InlineStack.pop_back();
393 }
394 switch (LineTy) {
395 case LineType::CallSiteProfile: {
396 FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
397 LineLocation(LineOffset, Discriminator))[std::string(FName)];
398 FSamples.setName(FName);
399 MergeResult(Result, FSamples.addTotalSamples(NumSamples));
400 InlineStack.push_back(&FSamples);
401 DepthMetadata = 0;
402 break;
403 }
404 case LineType::BodyProfile: {
405 while (InlineStack.size() > Depth) {
406 InlineStack.pop_back();
407 }
408 FunctionSamples &FProfile = *InlineStack.back();
409 for (const auto &name_count : TargetCountMap) {
410 MergeResult(Result, FProfile.addCalledTargetSamples(
411 LineOffset, Discriminator, name_count.first,
412 name_count.second));
413 }
414 MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
415 NumSamples));
416 break;
417 }
418 case LineType::Metadata: {
419 FunctionSamples &FProfile = *InlineStack.back();
420 if (FunctionHash) {
421 FProfile.setFunctionHash(FunctionHash);
422 if (Depth == 1)
423 ++TopLevelProbeProfileCount;
424 }
427 ProfileIsPreInlined = true;
428 DepthMetadata = Depth;
429 break;
430 }
431 }
432 }
433 }
434
435 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
436 "Cannot have both context-sensitive and regular profile");
438 assert((TopLevelProbeProfileCount == 0 ||
439 TopLevelProbeProfileCount == Profiles.size()) &&
440 "Cannot have both probe-based profiles and regular profiles");
441 ProfileIsProbeBased = (TopLevelProbeProfileCount > 0);
445
446 if (Result == sampleprof_error::success)
448
449 return Result;
450}
451
453 bool result = false;
454
455 // Check that the first non-comment line is a valid function header.
456 line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
457 if (!LineIt.is_at_eof()) {
458 if ((*LineIt)[0] != ' ') {
459 uint64_t NumSamples, NumHeadSamples;
460 StringRef FName;
461 result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
462 }
463 }
464
465 return result;
466}
467
469 unsigned NumBytesRead = 0;
470 std::error_code EC;
471 uint64_t Val = decodeULEB128(Data, &NumBytesRead);
472
473 if (Val > std::numeric_limits<T>::max())
475 else if (Data + NumBytesRead > End)
477 else
479
480 if (EC) {
481 reportError(0, EC.message());
482 return EC;
483 }
484
485 Data += NumBytesRead;
486 return static_cast<T>(Val);
487}
488
490 std::error_code EC;
491 StringRef Str(reinterpret_cast<const char *>(Data));
492 if (Data + Str.size() + 1 > End) {
494 reportError(0, EC.message());
495 return EC;
496 }
497
498 Data += Str.size() + 1;
499 return Str;
500}
501
502template <typename T>
504 std::error_code EC;
505
506 if (Data + sizeof(T) > End) {
508 reportError(0, EC.message());
509 return EC;
510 }
511
512 using namespace support;
513 T Val = endian::readNext<T, little, unaligned>(Data);
514 return Val;
515}
516
517template <typename T>
519 std::error_code EC;
520 auto Idx = readNumber<uint32_t>();
521 if (std::error_code EC = Idx.getError())
522 return EC;
523 if (*Idx >= Table.size())
525 return *Idx;
526}
527
530 if (std::error_code EC = Idx.getError())
531 return EC;
532
533 return NameTable[*Idx];
534}
535
537 auto FName(readStringFromTable());
538 if (std::error_code EC = FName.getError())
539 return EC;
540 return SampleContext(*FName);
541}
542
544 if (!FixedLengthMD5)
546
547 // read NameTable index.
549 if (std::error_code EC = Idx.getError())
550 return EC;
551
552 // Check whether the name to be accessed has been accessed before,
553 // if not, read it from memory directly.
554 StringRef &SR = NameTable[*Idx];
555 if (SR.empty()) {
556 const uint8_t *SavedData = Data;
557 Data = MD5NameMemStart + ((*Idx) * sizeof(uint64_t));
558 auto FID = readUnencodedNumber<uint64_t>();
559 if (std::error_code EC = FID.getError())
560 return EC;
561 // Save the string converted from uint64_t in MD5StringBuf. All the
562 // references to the name are all StringRefs refering to the string
563 // in MD5StringBuf.
564 MD5StringBuf->push_back(std::to_string(*FID));
565 SR = MD5StringBuf->back();
566 Data = SavedData;
567 }
568 return SR;
569}
570
571ErrorOr<StringRef> SampleProfileReaderCompactBinary::readStringFromTable() {
572 auto Idx = readStringIndex(NameTable);
573 if (std::error_code EC = Idx.getError())
574 return EC;
575
576 return StringRef(NameTable[*Idx]);
577}
578
579std::error_code
581 auto NumSamples = readNumber<uint64_t>();
582 if (std::error_code EC = NumSamples.getError())
583 return EC;
584 FProfile.addTotalSamples(*NumSamples);
585
586 // Read the samples in the body.
587 auto NumRecords = readNumber<uint32_t>();
588 if (std::error_code EC = NumRecords.getError())
589 return EC;
590
591 for (uint32_t I = 0; I < *NumRecords; ++I) {
592 auto LineOffset = readNumber<uint64_t>();
593 if (std::error_code EC = LineOffset.getError())
594 return EC;
595
596 if (!isOffsetLegal(*LineOffset)) {
597 return std::error_code();
598 }
599
600 auto Discriminator = readNumber<uint64_t>();
601 if (std::error_code EC = Discriminator.getError())
602 return EC;
603
604 auto NumSamples = readNumber<uint64_t>();
605 if (std::error_code EC = NumSamples.getError())
606 return EC;
607
608 auto NumCalls = readNumber<uint32_t>();
609 if (std::error_code EC = NumCalls.getError())
610 return EC;
611
612 // Here we handle FS discriminators:
613 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
614
615 for (uint32_t J = 0; J < *NumCalls; ++J) {
616 auto CalledFunction(readStringFromTable());
617 if (std::error_code EC = CalledFunction.getError())
618 return EC;
619
620 auto CalledFunctionSamples = readNumber<uint64_t>();
621 if (std::error_code EC = CalledFunctionSamples.getError())
622 return EC;
623
624 FProfile.addCalledTargetSamples(*LineOffset, DiscriminatorVal,
625 *CalledFunction, *CalledFunctionSamples);
626 }
627
628 FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples);
629 }
630
631 // Read all the samples for inlined function calls.
632 auto NumCallsites = readNumber<uint32_t>();
633 if (std::error_code EC = NumCallsites.getError())
634 return EC;
635
636 for (uint32_t J = 0; J < *NumCallsites; ++J) {
637 auto LineOffset = readNumber<uint64_t>();
638 if (std::error_code EC = LineOffset.getError())
639 return EC;
640
641 auto Discriminator = readNumber<uint64_t>();
642 if (std::error_code EC = Discriminator.getError())
643 return EC;
644
645 auto FName(readStringFromTable());
646 if (std::error_code EC = FName.getError())
647 return EC;
648
649 // Here we handle FS discriminators:
650 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
651
652 FunctionSamples &CalleeProfile = FProfile.functionSamplesAt(
653 LineLocation(*LineOffset, DiscriminatorVal))[std::string(*FName)];
654 CalleeProfile.setName(*FName);
655 if (std::error_code EC = readProfile(CalleeProfile))
656 return EC;
657 }
658
660}
661
662std::error_code
664 Data = Start;
665 auto NumHeadSamples = readNumber<uint64_t>();
666 if (std::error_code EC = NumHeadSamples.getError())
667 return EC;
668
670 if (std::error_code EC = FContext.getError())
671 return EC;
672
673 Profiles[*FContext] = FunctionSamples();
674 FunctionSamples &FProfile = Profiles[*FContext];
675 FProfile.setContext(*FContext);
676 FProfile.addHeadSamples(*NumHeadSamples);
677
678 if (FContext->hasContext())
680
681 if (std::error_code EC = readProfile(FProfile))
682 return EC;
684}
685
689 while (!at_eof()) {
690 if (std::error_code EC = readFuncProfile(Data))
691 return EC;
692 }
693
695}
696
699 auto ContextIdx = readNumber<uint32_t>();
700 if (std::error_code EC = ContextIdx.getError())
701 return EC;
702 if (*ContextIdx >= CSNameTable->size())
704 return (*CSNameTable)[*ContextIdx];
705}
706
709 if (ProfileIsCS) {
710 auto FContext(readContextFromTable());
711 if (std::error_code EC = FContext.getError())
712 return EC;
713 return SampleContext(*FContext);
714 } else {
715 auto FName(readStringFromTable());
716 if (std::error_code EC = FName.getError())
717 return EC;
718 return SampleContext(*FName);
719 }
720}
721
723 const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
724 Data = Start;
725 End = Start + Size;
726 switch (Entry.Type) {
727 case SecProfSummary:
728 if (std::error_code EC = readSummary())
729 return EC;
731 Summary->setPartialProfile(true);
738 break;
739 case SecNameTable: {
742 bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
743 assert((!FixedLengthMD5 || UseMD5) &&
744 "If FixedLengthMD5 is true, UseMD5 has to be true");
747 if (std::error_code EC = readNameTableSec(UseMD5))
748 return EC;
749 break;
750 }
751 case SecCSNameTable: {
752 if (std::error_code EC = readCSNameTableSec())
753 return EC;
754 break;
755 }
756 case SecLBRProfile:
757 if (std::error_code EC = readFuncProfiles())
758 return EC;
759 break;
762 if (std::error_code EC = readFuncOffsetTable())
763 return EC;
764 break;
765 case SecFuncMetadata: {
769 bool HasAttribute =
771 if (std::error_code EC = readFuncMetadata(HasAttribute))
772 return EC;
773 break;
774 }
776 if (std::error_code EC = readProfileSymbolList())
777 return EC;
778 break;
779 default:
780 if (std::error_code EC = readCustomSection(Entry))
781 return EC;
782 break;
783 }
785}
786
788 if (!M)
789 return false;
790 FuncsToUse.clear();
791 for (auto &F : *M)
793 return true;
794}
795
797 // If there are more than one FuncOffsetTable, the profile read associated
798 // with previous FuncOffsetTable has to be done before next FuncOffsetTable
799 // is read.
800 FuncOffsetTable.clear();
801
802 auto Size = readNumber<uint64_t>();
803 if (std::error_code EC = Size.getError())
804 return EC;
805
806 FuncOffsetTable.reserve(*Size);
807
808 if (FuncOffsetsOrdered) {
810 std::make_unique<std::vector<std::pair<SampleContext, uint64_t>>>();
811 OrderedFuncOffsets->reserve(*Size);
812 }
813
814 for (uint64_t I = 0; I < *Size; ++I) {
815 auto FContext(readSampleContextFromTable());
816 if (std::error_code EC = FContext.getError())
817 return EC;
818
819 auto Offset = readNumber<uint64_t>();
820 if (std::error_code EC = Offset.getError())
821 return EC;
822
823 FuncOffsetTable[*FContext] = *Offset;
825 OrderedFuncOffsets->emplace_back(*FContext, *Offset);
826 }
827
829}
830
832 // Collect functions used by current module if the Reader has been
833 // given a module.
834 // collectFuncsFromModule uses FunctionSamples::getCanonicalFnName
835 // which will query FunctionSamples::HasUniqSuffix, so it has to be
836 // called after FunctionSamples::HasUniqSuffix is set, i.e. after
837 // NameTable section is read.
838 bool LoadFuncsToBeUsed = collectFuncsFromModule();
839
840 // When LoadFuncsToBeUsed is false, load all the function profiles.
841 const uint8_t *Start = Data;
842 if (!LoadFuncsToBeUsed) {
843 while (Data < End) {
844 if (std::error_code EC = readFuncProfile(Data))
845 return EC;
846 }
847 assert(Data == End && "More data is read than expected");
848 } else {
849 // Load function profiles on demand.
850 if (Remapper) {
851 for (auto Name : FuncsToUse) {
852 Remapper->insert(Name);
853 }
854 }
855
856 if (ProfileIsCS) {
857 DenseSet<uint64_t> FuncGuidsToUse;
858 if (useMD5()) {
859 for (auto Name : FuncsToUse)
860 FuncGuidsToUse.insert(Function::getGUID(Name));
861 }
862
863 // For each function in current module, load all context profiles for
864 // the function as well as their callee contexts which can help profile
865 // guided importing for ThinLTO. This can be achieved by walking
866 // through an ordered context container, where contexts are laid out
867 // as if they were walked in preorder of a context trie. While
868 // traversing the trie, a link to the highest common ancestor node is
869 // kept so that all of its decendants will be loaded.
871 "func offset table should always be sorted in CS profile");
872 const SampleContext *CommonContext = nullptr;
873 for (const auto &NameOffset : *OrderedFuncOffsets) {
874 const auto &FContext = NameOffset.first;
875 auto FName = FContext.getName();
876 // For function in the current module, keep its farthest ancestor
877 // context. This can be used to load itself and its child and
878 // sibling contexts.
879 if ((useMD5() && FuncGuidsToUse.count(std::stoull(FName.data()))) ||
880 (!useMD5() && (FuncsToUse.count(FName) ||
881 (Remapper && Remapper->exist(FName))))) {
882 if (!CommonContext || !CommonContext->IsPrefixOf(FContext))
883 CommonContext = &FContext;
884 }
885
886 if (CommonContext == &FContext ||
887 (CommonContext && CommonContext->IsPrefixOf(FContext))) {
888 // Load profile for the current context which originated from
889 // the common ancestor.
890 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
891 assert(FuncProfileAddr < End && "out of LBRProfile section");
892 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
893 return EC;
894 }
895 }
896 } else {
897 if (useMD5()) {
898 for (auto Name : FuncsToUse) {
899 auto GUID = std::to_string(MD5Hash(Name));
900 auto iter = FuncOffsetTable.find(StringRef(GUID));
901 if (iter == FuncOffsetTable.end())
902 continue;
903 const uint8_t *FuncProfileAddr = Start + iter->second;
904 assert(FuncProfileAddr < End && "out of LBRProfile section");
905 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
906 return EC;
907 }
908 } else {
909 for (auto NameOffset : FuncOffsetTable) {
910 SampleContext FContext(NameOffset.first);
911 auto FuncName = FContext.getName();
912 if (!FuncsToUse.count(FuncName) &&
913 (!Remapper || !Remapper->exist(FuncName)))
914 continue;
915 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
916 assert(FuncProfileAddr < End && "out of LBRProfile section");
917 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
918 return EC;
919 }
920 }
921 }
922 Data = End;
923 }
924 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
925 "Cannot have both context-sensitive and regular profile");
927 "Section flag should be consistent with actual profile");
929}
930
932 if (!ProfSymList)
933 ProfSymList = std::make_unique<ProfileSymbolList>();
934
935 if (std::error_code EC = ProfSymList->read(Data, End - Data))
936 return EC;
937
938 Data = End;
940}
941
942std::error_code SampleProfileReaderExtBinaryBase::decompressSection(
943 const uint8_t *SecStart, const uint64_t SecSize,
944 const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) {
945 Data = SecStart;
946 End = SecStart + SecSize;
947 auto DecompressSize = readNumber<uint64_t>();
948 if (std::error_code EC = DecompressSize.getError())
949 return EC;
950 DecompressBufSize = *DecompressSize;
951
952 auto CompressSize = readNumber<uint64_t>();
953 if (std::error_code EC = CompressSize.getError())
954 return EC;
955
958
959 uint8_t *Buffer = Allocator.Allocate<uint8_t>(DecompressBufSize);
960 size_t UCSize = DecompressBufSize;
962 Buffer, UCSize);
963 if (E)
965 DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer);
967}
968
970 const uint8_t *BufStart =
971 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
972
973 for (auto &Entry : SecHdrTable) {
974 // Skip empty section.
975 if (!Entry.Size)
976 continue;
977
978 // Skip sections without context when SkipFlatProf is true.
980 continue;
981
982 const uint8_t *SecStart = BufStart + Entry.Offset;
983 uint64_t SecSize = Entry.Size;
984
985 // If the section is compressed, decompress it into a buffer
986 // DecompressBuf before reading the actual data. The pointee of
987 // 'Data' will be changed to buffer hold by DecompressBuf
988 // temporarily when reading the actual data.
989 bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress);
990 if (isCompressed) {
991 const uint8_t *DecompressBuf;
992 uint64_t DecompressBufSize;
993 if (std::error_code EC = decompressSection(
994 SecStart, SecSize, DecompressBuf, DecompressBufSize))
995 return EC;
996 SecStart = DecompressBuf;
997 SecSize = DecompressBufSize;
998 }
999
1000 if (std::error_code EC = readOneSection(SecStart, SecSize, Entry))
1001 return EC;
1002 if (Data != SecStart + SecSize)
1004
1005 // Change the pointee of 'Data' from DecompressBuf to original Buffer.
1006 if (isCompressed) {
1007 Data = BufStart + Entry.Offset;
1008 End = BufStart + Buffer->getBufferSize();
1009 }
1010 }
1011
1013}
1014
1016 // Collect functions used by current module if the Reader has been
1017 // given a module.
1018 bool LoadFuncsToBeUsed = collectFuncsFromModule();
1021 std::vector<uint64_t> OffsetsToUse;
1022 if (!LoadFuncsToBeUsed) {
1023 // load all the function profiles.
1024 for (auto FuncEntry : FuncOffsetTable) {
1025 OffsetsToUse.push_back(FuncEntry.second);
1026 }
1027 } else {
1028 // load function profiles on demand.
1029 for (auto Name : FuncsToUse) {
1030 auto GUID = std::to_string(MD5Hash(Name));
1031 auto iter = FuncOffsetTable.find(StringRef(GUID));
1032 if (iter == FuncOffsetTable.end())
1033 continue;
1034 OffsetsToUse.push_back(iter->second);
1035 }
1036 }
1037
1038 for (auto Offset : OffsetsToUse) {
1039 const uint8_t *SavedData = Data;
1040 if (std::error_code EC = readFuncProfile(
1041 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
1042 Offset))
1043 return EC;
1044 Data = SavedData;
1045 }
1047}
1048
1049std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
1050 if (Magic == SPMagic())
1053}
1054
1055std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
1056 if (Magic == SPMagic(SPF_Ext_Binary))
1059}
1060
1061std::error_code
1062SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) {
1063 if (Magic == SPMagic(SPF_Compact_Binary))
1066}
1067
1069 auto Size = readNumber<uint32_t>();
1070 if (std::error_code EC = Size.getError())
1071 return EC;
1072 NameTable.reserve(*Size + NameTable.size());
1073 for (uint32_t I = 0; I < *Size; ++I) {
1074 auto Name(readString());
1075 if (std::error_code EC = Name.getError())
1076 return EC;
1077 NameTable.push_back(*Name);
1078 }
1079
1081}
1082
1084 auto Size = readNumber<uint64_t>();
1085 if (std::error_code EC = Size.getError())
1086 return EC;
1087 MD5StringBuf = std::make_unique<std::vector<std::string>>();
1088 MD5StringBuf->reserve(*Size);
1089 if (FixedLengthMD5) {
1090 // Preallocate and initialize NameTable so we can check whether a name
1091 // index has been read before by checking whether the element in the
1092 // NameTable is empty, meanwhile readStringIndex can do the boundary
1093 // check using the size of NameTable.
1094 NameTable.resize(*Size + NameTable.size());
1095
1097 Data = Data + (*Size) * sizeof(uint64_t);
1099 }
1100 NameTable.reserve(*Size);
1101 for (uint64_t I = 0; I < *Size; ++I) {
1102 auto FID = readNumber<uint64_t>();
1103 if (std::error_code EC = FID.getError())
1104 return EC;
1105 MD5StringBuf->push_back(std::to_string(*FID));
1106 // NameTable is a vector of StringRef. Here it is pushing back a
1107 // StringRef initialized with the last string in MD5stringBuf.
1108 NameTable.push_back(MD5StringBuf->back());
1109 }
1111}
1112
1114 if (IsMD5)
1115 return readMD5NameTable();
1117}
1118
1119// Read in the CS name table section, which basically contains a list of context
1120// vectors. Each element of a context vector, aka a frame, refers to the
1121// underlying raw function names that are stored in the name table, as well as
1122// a callsite identifier that only makes sense for non-leaf frames.
1124 auto Size = readNumber<uint32_t>();
1125 if (std::error_code EC = Size.getError())
1126 return EC;
1127
1128 std::vector<SampleContextFrameVector> *PNameVec =
1129 new std::vector<SampleContextFrameVector>();
1130 PNameVec->reserve(*Size);
1131 for (uint32_t I = 0; I < *Size; ++I) {
1132 PNameVec->emplace_back(SampleContextFrameVector());
1133 auto ContextSize = readNumber<uint32_t>();
1134 if (std::error_code EC = ContextSize.getError())
1135 return EC;
1136 for (uint32_t J = 0; J < *ContextSize; ++J) {
1137 auto FName(readStringFromTable());
1138 if (std::error_code EC = FName.getError())
1139 return EC;
1140 auto LineOffset = readNumber<uint64_t>();
1141 if (std::error_code EC = LineOffset.getError())
1142 return EC;
1143
1144 if (!isOffsetLegal(*LineOffset))
1145 return std::error_code();
1146
1147 auto Discriminator = readNumber<uint64_t>();
1148 if (std::error_code EC = Discriminator.getError())
1149 return EC;
1150
1151 PNameVec->back().emplace_back(
1152 FName.get(), LineLocation(LineOffset.get(), Discriminator.get()));
1153 }
1154 }
1155
1156 // From this point the underlying object of CSNameTable should be immutable.
1157 CSNameTable.reset(PNameVec);
1159}
1160
1161std::error_code
1162
1164 FunctionSamples *FProfile) {
1165 if (Data < End) {
1166 if (ProfileIsProbeBased) {
1167 auto Checksum = readNumber<uint64_t>();
1168 if (std::error_code EC = Checksum.getError())
1169 return EC;
1170 if (FProfile)
1171 FProfile->setFunctionHash(*Checksum);
1172 }
1173
1174 if (ProfileHasAttribute) {
1175 auto Attributes = readNumber<uint32_t>();
1176 if (std::error_code EC = Attributes.getError())
1177 return EC;
1178 if (FProfile)
1180 }
1181
1182 if (!ProfileIsCS) {
1183 // Read all the attributes for inlined function calls.
1184 auto NumCallsites = readNumber<uint32_t>();
1185 if (std::error_code EC = NumCallsites.getError())
1186 return EC;
1187
1188 for (uint32_t J = 0; J < *NumCallsites; ++J) {
1189 auto LineOffset = readNumber<uint64_t>();
1190 if (std::error_code EC = LineOffset.getError())
1191 return EC;
1192
1193 auto Discriminator = readNumber<uint64_t>();
1194 if (std::error_code EC = Discriminator.getError())
1195 return EC;
1196
1197 auto FContext(readSampleContextFromTable());
1198 if (std::error_code EC = FContext.getError())
1199 return EC;
1200
1201 FunctionSamples *CalleeProfile = nullptr;
1202 if (FProfile) {
1203 CalleeProfile = const_cast<FunctionSamples *>(
1205 *LineOffset,
1206 *Discriminator))[std::string(FContext.get().getName())]);
1207 }
1208 if (std::error_code EC =
1209 readFuncMetadata(ProfileHasAttribute, CalleeProfile))
1210 return EC;
1211 }
1212 }
1213 }
1214
1216}
1217
1218std::error_code
1220 while (Data < End) {
1221 auto FContext(readSampleContextFromTable());
1222 if (std::error_code EC = FContext.getError())
1223 return EC;
1224 FunctionSamples *FProfile = nullptr;
1225 auto It = Profiles.find(*FContext);
1226 if (It != Profiles.end())
1227 FProfile = &It->second;
1228
1229 if (std::error_code EC = readFuncMetadata(ProfileHasAttribute, FProfile))
1230 return EC;
1231 }
1232
1233 assert(Data == End && "More data is read than expected");
1235}
1236
1237std::error_code SampleProfileReaderCompactBinary::readNameTable() {
1238 auto Size = readNumber<uint64_t>();
1239 if (std::error_code EC = Size.getError())
1240 return EC;
1241 NameTable.reserve(*Size);
1242 for (uint64_t I = 0; I < *Size; ++I) {
1243 auto FID = readNumber<uint64_t>();
1244 if (std::error_code EC = FID.getError())
1245 return EC;
1246 NameTable.push_back(std::to_string(*FID));
1247 }
1249}
1250
1251std::error_code
1253 SecHdrTableEntry Entry;
1254 auto Type = readUnencodedNumber<uint64_t>();
1255 if (std::error_code EC = Type.getError())
1256 return EC;
1257 Entry.Type = static_cast<SecType>(*Type);
1258
1259 auto Flags = readUnencodedNumber<uint64_t>();
1260 if (std::error_code EC = Flags.getError())
1261 return EC;
1262 Entry.Flags = *Flags;
1263
1264 auto Offset = readUnencodedNumber<uint64_t>();
1265 if (std::error_code EC = Offset.getError())
1266 return EC;
1267 Entry.Offset = *Offset;
1268
1269 auto Size = readUnencodedNumber<uint64_t>();
1270 if (std::error_code EC = Size.getError())
1271 return EC;
1272 Entry.Size = *Size;
1273
1274 Entry.LayoutIndex = Idx;
1275 SecHdrTable.push_back(std::move(Entry));
1277}
1278
1280 auto EntryNum = readUnencodedNumber<uint64_t>();
1281 if (std::error_code EC = EntryNum.getError())
1282 return EC;
1283
1284 for (uint64_t i = 0; i < (*EntryNum); i++)
1285 if (std::error_code EC = readSecHdrTableEntry(i))
1286 return EC;
1287
1289}
1290
1292 const uint8_t *BufStart =
1293 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1294 Data = BufStart;
1295 End = BufStart + Buffer->getBufferSize();
1296
1297 if (std::error_code EC = readMagicIdent())
1298 return EC;
1299
1300 if (std::error_code EC = readSecHdrTable())
1301 return EC;
1302
1304}
1305
1307 uint64_t Size = 0;
1308 for (auto &Entry : SecHdrTable) {
1309 if (Entry.Type == Type)
1310 Size += Entry.Size;
1311 }
1312 return Size;
1313}
1314
1316 // Sections in SecHdrTable is not necessarily in the same order as
1317 // sections in the profile because section like FuncOffsetTable needs
1318 // to be written after section LBRProfile but needs to be read before
1319 // section LBRProfile, so we cannot simply use the last entry in
1320 // SecHdrTable to calculate the file size.
1321 uint64_t FileSize = 0;
1322 for (auto &Entry : SecHdrTable) {
1323 FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
1324 }
1325 return FileSize;
1326}
1327
1328static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
1329 std::string Flags;
1331 Flags.append("{compressed,");
1332 else
1333 Flags.append("{");
1334
1336 Flags.append("flat,");
1337
1338 switch (Entry.Type) {
1339 case SecNameTable:
1341 Flags.append("fixlenmd5,");
1343 Flags.append("md5,");
1345 Flags.append("uniq,");
1346 break;
1347 case SecProfSummary:
1349 Flags.append("partial,");
1351 Flags.append("context,");
1353 Flags.append("preInlined,");
1355 Flags.append("fs-discriminator,");
1356 break;
1357 case SecFuncOffsetTable:
1359 Flags.append("ordered,");
1360 break;
1361 case SecFuncMetadata:
1363 Flags.append("probe,");
1365 Flags.append("attr,");
1366 break;
1367 default:
1368 break;
1369 }
1370 char &last = Flags.back();
1371 if (last == ',')
1372 last = '}';
1373 else
1374 Flags.append("}");
1375 return Flags;
1376}
1377
1379 uint64_t TotalSecsSize = 0;
1380 for (auto &Entry : SecHdrTable) {
1381 OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset
1382 << ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
1383 << "\n";
1384 ;
1385 TotalSecsSize += Entry.Size;
1386 }
1387 uint64_t HeaderSize = SecHdrTable.front().Offset;
1388 assert(HeaderSize + TotalSecsSize == getFileSize() &&
1389 "Size of 'header + sections' doesn't match the total size of profile");
1390
1391 OS << "Header Size: " << HeaderSize << "\n";
1392 OS << "Total Sections Size: " << TotalSecsSize << "\n";
1393 OS << "File Size: " << getFileSize() << "\n";
1394 return true;
1395}
1396
1398 // Read and check the magic identifier.
1399 auto Magic = readNumber<uint64_t>();
1400 if (std::error_code EC = Magic.getError())
1401 return EC;
1402 else if (std::error_code EC = verifySPMagic(*Magic))
1403 return EC;
1404
1405 // Read the version number.
1406 auto Version = readNumber<uint64_t>();
1407 if (std::error_code EC = Version.getError())
1408 return EC;
1409 else if (*Version != SPVersion())
1411
1413}
1414
1416 Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1417 End = Data + Buffer->getBufferSize();
1418
1419 if (std::error_code EC = readMagicIdent())
1420 return EC;
1421
1422 if (std::error_code EC = readSummary())
1423 return EC;
1424
1425 if (std::error_code EC = readNameTable())
1426 return EC;
1428}
1429
1430std::error_code SampleProfileReaderCompactBinary::readHeader() {
1432 if (std::error_code EC = readFuncOffsetTable())
1433 return EC;
1435}
1436
1437std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() {
1438 auto TableOffset = readUnencodedNumber<uint64_t>();
1439 if (std::error_code EC = TableOffset.getError())
1440 return EC;
1441
1442 const uint8_t *SavedData = Data;
1443 const uint8_t *TableStart =
1444 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
1445 *TableOffset;
1446 Data = TableStart;
1447
1448 auto Size = readNumber<uint64_t>();
1449 if (std::error_code EC = Size.getError())
1450 return EC;
1451
1452 FuncOffsetTable.reserve(*Size);
1453 for (uint64_t I = 0; I < *Size; ++I) {
1454 auto FName(readStringFromTable());
1455 if (std::error_code EC = FName.getError())
1456 return EC;
1457
1458 auto Offset = readNumber<uint64_t>();
1459 if (std::error_code EC = Offset.getError())
1460 return EC;
1461
1462 FuncOffsetTable[*FName] = *Offset;
1463 }
1464 End = TableStart;
1465 Data = SavedData;
1467}
1468
1470 if (!M)
1471 return false;
1472 FuncsToUse.clear();
1473 for (auto &F : *M)
1474 FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
1475 return true;
1476}
1477
1478std::error_code SampleProfileReaderBinary::readSummaryEntry(
1479 std::vector<ProfileSummaryEntry> &Entries) {
1480 auto Cutoff = readNumber<uint64_t>();
1481 if (std::error_code EC = Cutoff.getError())
1482 return EC;
1483
1484 auto MinBlockCount = readNumber<uint64_t>();
1485 if (std::error_code EC = MinBlockCount.getError())
1486 return EC;
1487
1488 auto NumBlocks = readNumber<uint64_t>();
1489 if (std::error_code EC = NumBlocks.getError())
1490 return EC;
1491
1492 Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks);
1494}
1495
1497 auto TotalCount = readNumber<uint64_t>();
1498 if (std::error_code EC = TotalCount.getError())
1499 return EC;
1500
1501 auto MaxBlockCount = readNumber<uint64_t>();
1502 if (std::error_code EC = MaxBlockCount.getError())
1503 return EC;
1504
1505 auto MaxFunctionCount = readNumber<uint64_t>();
1506 if (std::error_code EC = MaxFunctionCount.getError())
1507 return EC;
1508
1509 auto NumBlocks = readNumber<uint64_t>();
1510 if (std::error_code EC = NumBlocks.getError())
1511 return EC;
1512
1513 auto NumFunctions = readNumber<uint64_t>();
1514 if (std::error_code EC = NumFunctions.getError())
1515 return EC;
1516
1517 auto NumSummaryEntries = readNumber<uint64_t>();
1518 if (std::error_code EC = NumSummaryEntries.getError())
1519 return EC;
1520
1521 std::vector<ProfileSummaryEntry> Entries;
1522 for (unsigned i = 0; i < *NumSummaryEntries; i++) {
1523 std::error_code EC = readSummaryEntry(Entries);
1524 if (EC != sampleprof_error::success)
1525 return EC;
1526 }
1527 Summary = std::make_unique<ProfileSummary>(
1528 ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0,
1529 *MaxFunctionCount, *NumBlocks, *NumFunctions);
1530
1532}
1533
1535 const uint8_t *Data =
1536 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1537 uint64_t Magic = decodeULEB128(Data);
1538 return Magic == SPMagic();
1539}
1540
1542 const uint8_t *Data =
1543 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1544 uint64_t Magic = decodeULEB128(Data);
1545 return Magic == SPMagic(SPF_Ext_Binary);
1546}
1547
1549 const uint8_t *Data =
1550 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1551 uint64_t Magic = decodeULEB128(Data);
1552 return Magic == SPMagic(SPF_Compact_Binary);
1553}
1554
1556 uint32_t dummy;
1557 if (!GcovBuffer.readInt(dummy))
1560}
1561
1563 if (sizeof(T) <= sizeof(uint32_t)) {
1564 uint32_t Val;
1565 if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
1566 return static_cast<T>(Val);
1567 } else if (sizeof(T) <= sizeof(uint64_t)) {
1568 uint64_t Val;
1569 if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
1570 return static_cast<T>(Val);
1571 }
1572
1573 std::error_code EC = sampleprof_error::malformed;
1574 reportError(0, EC.message());
1575 return EC;
1576}
1577
1579 StringRef Str;
1580 if (!GcovBuffer.readString(Str))
1582 return Str;
1583}
1584
1586 // Read the magic identifier.
1589
1590 // Read the version number. Note - the GCC reader does not validate this
1591 // version, but the profile creator generates v704.
1592 GCOV::GCOVVersion version;
1593 if (!GcovBuffer.readGCOVVersion(version))
1595
1596 if (version != GCOV::V407)
1598
1599 // Skip the empty integer.
1600 if (std::error_code EC = skipNextWord())
1601 return EC;
1602
1604}
1605
1607 uint32_t Tag;
1608 if (!GcovBuffer.readInt(Tag))
1610
1611 if (Tag != Expected)
1613
1614 if (std::error_code EC = skipNextWord())
1615 return EC;
1616
1618}
1619
1621 if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
1622 return EC;
1623
1624 uint32_t Size;
1625 if (!GcovBuffer.readInt(Size))
1627
1628 for (uint32_t I = 0; I < Size; ++I) {
1629 StringRef Str;
1630 if (!GcovBuffer.readString(Str))
1632 Names.push_back(std::string(Str));
1633 }
1634
1636}
1637
1639 if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
1640 return EC;
1641
1642 uint32_t NumFunctions;
1643 if (!GcovBuffer.readInt(NumFunctions))
1645
1646 InlineCallStack Stack;
1647 for (uint32_t I = 0; I < NumFunctions; ++I)
1648 if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
1649 return EC;
1650
1653}
1654
1656 const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
1657 uint64_t HeadCount = 0;
1658 if (InlineStack.size() == 0)
1659 if (!GcovBuffer.readInt64(HeadCount))
1661
1662 uint32_t NameIdx;
1663 if (!GcovBuffer.readInt(NameIdx))
1665
1666 StringRef Name(Names[NameIdx]);
1667
1668 uint32_t NumPosCounts;
1669 if (!GcovBuffer.readInt(NumPosCounts))
1671
1672 uint32_t NumCallsites;
1673 if (!GcovBuffer.readInt(NumCallsites))
1675
1676 FunctionSamples *FProfile = nullptr;
1677 if (InlineStack.size() == 0) {
1678 // If this is a top function that we have already processed, do not
1679 // update its profile again. This happens in the presence of
1680 // function aliases. Since these aliases share the same function
1681 // body, there will be identical replicated profiles for the
1682 // original function. In this case, we simply not bother updating
1683 // the profile of the original function.
1684 FProfile = &Profiles[Name];
1685 FProfile->addHeadSamples(HeadCount);
1686 if (FProfile->getTotalSamples() > 0)
1687 Update = false;
1688 } else {
1689 // Otherwise, we are reading an inlined instance. The top of the
1690 // inline stack contains the profile of the caller. Insert this
1691 // callee in the caller's CallsiteMap.
1692 FunctionSamples *CallerProfile = InlineStack.front();
1693 uint32_t LineOffset = Offset >> 16;
1694 uint32_t Discriminator = Offset & 0xffff;
1695 FProfile = &CallerProfile->functionSamplesAt(
1696 LineLocation(LineOffset, Discriminator))[std::string(Name)];
1697 }
1698 FProfile->setName(Name);
1699
1700 for (uint32_t I = 0; I < NumPosCounts; ++I) {
1704
1705 uint32_t NumTargets;
1706 if (!GcovBuffer.readInt(NumTargets))
1708
1709 uint64_t Count;
1710 if (!GcovBuffer.readInt64(Count))
1712
1713 // The line location is encoded in the offset as:
1714 // high 16 bits: line offset to the start of the function.
1715 // low 16 bits: discriminator.
1716 uint32_t LineOffset = Offset >> 16;
1717 uint32_t Discriminator = Offset & 0xffff;
1718
1719 InlineCallStack NewStack;
1720 NewStack.push_back(FProfile);
1721 llvm::append_range(NewStack, InlineStack);
1722 if (Update) {
1723 // Walk up the inline stack, adding the samples on this line to
1724 // the total sample count of the callers in the chain.
1725 for (auto *CallerProfile : NewStack)
1726 CallerProfile->addTotalSamples(Count);
1727
1728 // Update the body samples for the current profile.
1729 FProfile->addBodySamples(LineOffset, Discriminator, Count);
1730 }
1731
1732 // Process the list of functions called at an indirect call site.
1733 // These are all the targets that a function pointer (or virtual
1734 // function) resolved at runtime.
1735 for (uint32_t J = 0; J < NumTargets; J++) {
1736 uint32_t HistVal;
1737 if (!GcovBuffer.readInt(HistVal))
1739
1740 if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
1742
1743 uint64_t TargetIdx;
1744 if (!GcovBuffer.readInt64(TargetIdx))
1746 StringRef TargetName(Names[TargetIdx]);
1747
1748 uint64_t TargetCount;
1749 if (!GcovBuffer.readInt64(TargetCount))
1751
1752 if (Update)
1753 FProfile->addCalledTargetSamples(LineOffset, Discriminator,
1754 TargetName, TargetCount);
1755 }
1756 }
1757
1758 // Process all the inlined callers into the current function. These
1759 // are all the callsites that were inlined into this function.
1760 for (uint32_t I = 0; I < NumCallsites; I++) {
1761 // The offset is encoded as:
1762 // high 16 bits: line offset to the start of the function.
1763 // low 16 bits: discriminator.
1767 InlineCallStack NewStack;
1768 NewStack.push_back(FProfile);
1769 llvm::append_range(NewStack, InlineStack);
1770 if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
1771 return EC;
1772 }
1773
1775}
1776
1777/// Read a GCC AutoFDO profile.
1778///
1779/// This format is generated by the Linux Perf conversion tool at
1780/// https://github.com/google/autofdo.
1782 assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator");
1783 // Read the string table.
1784 if (std::error_code EC = readNameTable())
1785 return EC;
1786
1787 // Read the source profile.
1788 if (std::error_code EC = readFunctionProfiles())
1789 return EC;
1790
1792}
1793
1795 StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart()));
1796 return Magic == "adcg*704";
1797}
1798
1800 // If the reader uses MD5 to represent string, we can't remap it because
1801 // we don't know what the original function names were.
1802 if (Reader.useMD5()) {
1804 Reader.getBuffer()->getBufferIdentifier(),
1805 "Profile data remapping cannot be applied to profile data "
1806 "in compact format (original mangled names are not available).",
1807 DS_Warning));
1808 return;
1809 }
1810
1811 // CSSPGO-TODO: Remapper is not yet supported.
1812 // We will need to remap the entire context string.
1813 assert(Remappings && "should be initialized while creating remapper");
1814 for (auto &Sample : Reader.getProfiles()) {
1815 DenseSet<StringRef> NamesInSample;
1816 Sample.second.findAllNames(NamesInSample);
1817 for (auto &Name : NamesInSample)
1818 if (auto Key = Remappings->insert(Name))
1819 NameMap.insert({Key, Name});
1820 }
1821
1822 RemappingApplied = true;
1823}
1824
1825std::optional<StringRef>
1827 if (auto Key = Remappings->lookup(Fname))
1828 return NameMap.lookup(Key);
1829 return std::nullopt;
1830}
1831
1832/// Prepare a memory buffer for the contents of \p Filename.
1833///
1834/// \returns an error code indicating the status of the buffer.
1837 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
1838 : FS.getBufferForFile(Filename);
1839 if (std::error_code EC = BufferOrErr.getError())
1840 return EC;
1841 auto Buffer = std::move(BufferOrErr.get());
1842
1843 return std::move(Buffer);
1844}
1845
1846/// Create a sample profile reader based on the format of the input file.
1847///
1848/// \param Filename The file to open.
1849///
1850/// \param C The LLVM context to use to emit diagnostics.
1851///
1852/// \param P The FSDiscriminatorPass.
1853///
1854/// \param RemapFilename The file used for profile remapping.
1855///
1856/// \returns an error code indicating the status of the created reader.
1858SampleProfileReader::create(const std::string Filename, LLVMContext &C,
1860 const std::string RemapFilename) {
1861 auto BufferOrError = setupMemoryBuffer(Filename, FS);
1862 if (std::error_code EC = BufferOrError.getError())
1863 return EC;
1864 return create(BufferOrError.get(), C, FS, P, RemapFilename);
1865}
1866
1867/// Create a sample profile remapper from the given input, to remap the
1868/// function names in the given profile data.
1869///
1870/// \param Filename The file to open.
1871///
1872/// \param Reader The profile reader the remapper is going to be applied to.
1873///
1874/// \param C The LLVM context to use to emit diagnostics.
1875///
1876/// \returns an error code indicating the status of the created reader.
1879 vfs::FileSystem &FS,
1880 SampleProfileReader &Reader,
1881 LLVMContext &C) {
1882 auto BufferOrError = setupMemoryBuffer(Filename, FS);
1883 if (std::error_code EC = BufferOrError.getError())
1884 return EC;
1885 return create(BufferOrError.get(), Reader, C);
1886}
1887
1888/// Create a sample profile remapper from the given input, to remap the
1889/// function names in the given profile data.
1890///
1891/// \param B The memory buffer to create the reader from (assumes ownership).
1892///
1893/// \param C The LLVM context to use to emit diagnostics.
1894///
1895/// \param Reader The profile reader the remapper is going to be applied to.
1896///
1897/// \returns an error code indicating the status of the created reader.
1899SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B,
1900 SampleProfileReader &Reader,
1901 LLVMContext &C) {
1902 auto Remappings = std::make_unique<SymbolRemappingReader>();
1903 if (Error E = Remappings->read(*B)) {
1905 std::move(E), [&](const SymbolRemappingParseError &ParseError) {
1906 C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(),
1907 ParseError.getLineNum(),
1908 ParseError.getMessage()));
1909 });
1911 }
1912
1913 return std::make_unique<SampleProfileReaderItaniumRemapper>(
1914 std::move(B), std::move(Remappings), Reader);
1915}
1916
1917/// Create a sample profile reader based on the format of the input data.
1918///
1919/// \param B The memory buffer to create the reader from (assumes ownership).
1920///
1921/// \param C The LLVM context to use to emit diagnostics.
1922///
1923/// \param P The FSDiscriminatorPass.
1924///
1925/// \param RemapFilename The file used for profile remapping.
1926///
1927/// \returns an error code indicating the status of the created reader.
1929SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
1931 const std::string RemapFilename) {
1932 std::unique_ptr<SampleProfileReader> Reader;
1934 Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
1936 Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
1938 Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C));
1940 Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
1942 Reader.reset(new SampleProfileReaderText(std::move(B), C));
1943 else
1945
1946 if (!RemapFilename.empty()) {
1948 RemapFilename, FS, *Reader, C);
1949 if (std::error_code EC = ReaderOrErr.getError()) {
1950 std::string Msg = "Could not create remapper: " + EC.message();
1951 C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg));
1952 return EC;
1953 }
1954 Reader->Remapper = std::move(ReaderOrErr.get());
1955 }
1956
1957 if (std::error_code EC = Reader->readHeader()) {
1958 return EC;
1959 }
1960
1961 Reader->setDiscriminatorMaskedBitFrom(P);
1962
1963 return std::move(Reader);
1964}
1965
1966// For text and GCC file formats, we compute the summary after reading the
1967// profile. Binary format has the profile summary in its header.
1970 Summary = Builder.computeSummaryForProfiles(Profiles);
1971}
AMDGPU Kernel Attributes
assume Assume Builder
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseMap class.
std::string Name
uint64_t Size
Provides ErrorOr<T> smart pointer.
static Expected< std::unique_ptr< MemoryBuffer > > setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS)
This file supports working with JSON data.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Module.h This file contains the declarations for the Module class.
#define P(N)
static bool isDigit(const char C)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
static bool ParseHead(const StringRef &Input, StringRef &FName, uint64_t &NumSamples, uint64_t &NumHeadSamples)
Parse Input as function head.
static void dumpFunctionProfileJson(const FunctionSamples &S, json::OStream &JOS, bool TopLevel=false)
static bool isOffsetLegal(unsigned L)
Returns true if line offset L is legal (only has 16 bits).
static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth, uint64_t &NumSamples, uint32_t &LineOffset, uint32_t &Discriminator, StringRef &CalleeName, DenseMap< StringRef, uint64_t > &TargetCountMap, uint64_t &FunctionHash, uint32_t &Attributes)
Parse Input as line sample.
static cl::opt< bool > ProfileIsFSDisciminator("profile-isfs", cl::Hidden, cl::init(false), cl::desc("Profile uses flow sensitive discriminators"))
static std::string getSecFlagsStr(const SecHdrTableEntry &Entry)
static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash, uint32_t &Attributes)
Parse Input that contains metadata.
@ CallSiteProfile
raw_pwrite_stream & OS
@ Flags
Definition: TextStubV5.cpp:93
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
LLVM_ATTRIBUTE_RETURNS_NONNULL void * Allocate(size_t Size, Align Alignment)
Allocate space at the specified alignment.
Definition: Allocator.h:148
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Diagnostic information for the sample profiler.
Represents either an error or a value T.
Definition: ErrorOr.h:56
std::error_code getError() const
Definition: ErrorOr.h:153
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
Tagged union holding either a T or a Error.
Definition: Error.h:470
bool readInt(uint32_t &Val)
Definition: GCOV.h:151
bool readInt64(uint64_t &Val)
Definition: GCOV.h:161
bool readGCOVVersion(GCOV::GCOVVersion &version)
readGCOVVersion - Read GCOV version.
Definition: GCOV.h:107
bool readString(StringRef &str)
Definition: GCOV.h:169
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
Definition: GCOV.h:93
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
Definition: GlobalValue.h:591
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:51
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
Definition: MemoryBuffer.h:76
static ErrorOr< std::unique_ptr< MemoryBuffer > > getSTDIN()
Read all of stdin into a file buffer, and return it.
Root of the metadata hierarchy.
Definition: Metadata.h:61
static const ArrayRef< uint32_t > DefaultCutoffs
A vector of useful cutoff values for detailed summary.
Definition: ProfileCommon.h:65
size_t size() const
Definition: SmallVector.h:91
void push_back(const T &Elt)
Definition: SmallVector.h:416
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
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:468
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:558
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
size_t find_last_of(char C, size_t From=npos) const
Find the last character in the string that is C, or npos if not found.
Definition: StringRef.h:398
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
size_t find_first_of(char C, size_t From=0) const
Find the first character in the string that is C, or npos if not found.
Definition: StringRef.h:375
size_t rfind(char C, size_t From=npos) const
Search for the last character C in the string.
Definition: StringRef.h:345
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:295
StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
Definition: StringRef.h:802
static constexpr size_t npos
Definition: StringRef.h:52
size_t find_first_not_of(char C, size_t From=0) const
Find the first character in the string that is not C or npos if not found.
Definition: StringRef.cpp:251
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition: DenseSet.h:97
json::OStream allows writing well-formed JSON without materializing all structures as json::Value ahe...
Definition: JSON.h:956
void object(Block Contents)
Emit an object whose elements are emitted in the provided Block.
Definition: JSON.h:986
void attribute(llvm::StringRef Key, const Value &Contents)
Emit an attribute whose value is self-contained (number, vector<int> etc).
Definition: JSON.h:1011
void arrayBegin()
Definition: JSON.cpp:842
void attributeArray(llvm::StringRef Key, Block Contents)
Emit an attribute whose value is an array with elements from the Block.
Definition: JSON.h:1015
A forward iterator which reads text lines from a buffer.
Definition: LineIterator.h:33
int64_t line_number() const
Return the current line number. May return any number at EOF.
Definition: LineIterator.h:66
bool is_at_eof() const
Return true if we've reached EOF or are an "end" iterator.
Definition: LineIterator.h:60
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
Representation of the samples collected for a function.
Definition: SampleProf.h:726
void setName(StringRef FunctionName)
Set the name of the function.
Definition: SampleProf.h:1022
sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:733
uint64_t getHeadSamples() const
For top-level functions, return the total number of branch samples that have the function as the bran...
Definition: SampleProf.h:899
sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:750
FunctionSamplesMap & functionSamplesAt(const LineLocation &Loc)
Return the function samples at the given callsite location.
Definition: SampleProf.h:865
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
Definition: SampleProf.h:1036
sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator, uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:758
void setFunctionHash(uint64_t Hash)
Definition: SampleProf.h:1030
static bool ProfileIsFS
If this profile uses flow sensitive discriminators.
Definition: SampleProf.h:1143
sampleprof_error addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator, StringRef FName, uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:764
SampleContext & getContext() const
Definition: SampleProf.h:1132
static bool HasUniqSuffix
Whether the profile contains any ".__uniq." suffix in a name.
Definition: SampleProf.h:1140
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
Definition: SampleProf.h:891
const CallsiteSampleMap & getCallsiteSamples() const
Return all the callsite samples collected in the body of the function.
Definition: SampleProf.h:933
void setContext(const SampleContext &FContext)
Definition: SampleProf.h:1134
StringRef getName() const
Return the function name.
Definition: SampleProf.h:1025
const BodySampleMap & getBodySamples() const
Return all the samples collected in the body of the function.
Definition: SampleProf.h:930
void setAllAttributes(uint32_t A)
Definition: SampleProf.h:599
bool IsPrefixOf(const SampleContext &That) const
Definition: SampleProf.h:683
std::string toString() const
Definition: SampleProf.h:621
std::error_code readProfile(FunctionSamples &FProfile)
Read the contents of the given profile instance.
virtual std::error_code readNameTable()
Read the whole name table.
const uint8_t * Data
Points to the current location in the buffer.
ErrorOr< StringRef > readString()
Read a string from the profile.
std::vector< StringRef > NameTable
Function name table.
ErrorOr< T > readNumber()
Read a numeric value of type T from the profile.
std::error_code readHeader() override
Read and validate the file header.
virtual ErrorOr< StringRef > readStringFromTable()
Read a string indirectly via the name table.
bool at_eof() const
Return true if we've reached the end of file.
std::error_code readImpl() override
Read sample profiles from the associated file.
ErrorOr< uint32_t > readStringIndex(T &Table)
Read the string index and check whether it overflows the table.
virtual ErrorOr< SampleContext > readSampleContextFromTable()
const uint8_t * End
Points to the end of the buffer.
ErrorOr< T > readUnencodedNumber()
Read a numeric value of type T from the profile.
std::error_code readFuncProfile(const uint8_t *Start)
Read the next function profile instance.
std::error_code readSummary()
Read profile summary.
std::error_code readMagicIdent()
Read the contents of Magic number and Version number.
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if Buffer is in the format supported by this class.
std::error_code readImpl() override
Read samples only for functions to use.
bool collectFuncsFromModule() override
Collect functions with definitions in Module M.
ErrorOr< StringRef > readStringFromTable() override
Read a string indirectly via the name table.
std::error_code readFuncMetadata(bool ProfileHasAttribute)
bool collectFuncsFromModule() override
Collect functions with definitions in Module M.
uint64_t getSectionSize(SecType Type)
Get the total size of all Type sections.
virtual std::error_code readCustomSection(const SecHdrTableEntry &Entry)=0
std::unique_ptr< const std::vector< SampleContextFrameVector > > CSNameTable
CSNameTable is used to save full context vectors.
bool FixedLengthMD5
Use fixed length MD5 instead of ULEB128 encoding so NameTable doesn't need to be read in up front and...
DenseSet< StringRef > FuncsToUse
The set containing the functions to use when compiling a module.
ErrorOr< SampleContextFrames > readContextFromTable()
std::unique_ptr< ProfileSymbolList > ProfSymList
std::unique_ptr< std::vector< std::string > > MD5StringBuf
If MD5 is used in NameTable section, the section saves uint64_t data.
std::error_code readImpl() override
Read sample profiles in extensible format from the associated file.
bool useMD5() override
Return whether names in the profile are all MD5 numbers.
const uint8_t * MD5NameMemStart
The starting address of NameTable containing fixed length MD5.
virtual std::error_code readOneSection(const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry)
bool dumpSectionInfo(raw_ostream &OS=dbgs()) override
bool SkipFlatProf
If SkipFlatProf is true, skip the sections with SecFlagFlat flag.
std::error_code readHeader() override
Read and validate the file header.
uint64_t getFileSize()
Get the total size of header and all sections.
DenseMap< SampleContext, uint64_t > FuncOffsetTable
The table mapping from function context to the offset of its FunctionSample towards file start.
std::unique_ptr< std::vector< std::pair< SampleContext, uint64_t > > > OrderedFuncOffsets
Function offset mapping ordered by contexts.
ErrorOr< SampleContext > readSampleContextFromTable() override
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if Buffer is in the format supported by this class.
GCOVBuffer GcovBuffer
GCOV buffer containing the profile.
std::vector< std::string > Names
Function names in this profile.
std::error_code readImpl() override
Read sample profiles from the associated file.
std::error_code readHeader() override
Read and validate the file header.
std::error_code readOneFunctionProfile(const InlineCallStack &InlineStack, bool Update, uint32_t Offset)
static const uint32_t GCOVTagAFDOFileNames
GCOV tags used to separate sections in the profile file.
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if Buffer is in the format supported by this class.
std::error_code readSectionTag(uint32_t Expected)
Read the section tag and check that it's the same as Expected.
static ErrorOr< std::unique_ptr< SampleProfileReaderItaniumRemapper > > create(const std::string Filename, vfs::FileSystem &FS, SampleProfileReader &Reader, LLVMContext &C)
Create a remapper from the given remapping file.
void applyRemapping(LLVMContext &Ctx)
Apply remappings to the profile read by Reader.
std::optional< StringRef > lookUpNameInProfile(StringRef FunctionName)
Return the equivalent name in the profile for FunctionName if it exists.
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if Buffer is in the format supported by this class.
std::error_code readImpl() override
Read sample profiles from the associated file.
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if Buffer is in the format supported by this class.
Sample-based profile reader.
bool ProfileIsPreInlined
Whether function profile contains ShouldBeInlined contexts.
void dumpFunctionProfile(SampleContext FContext, raw_ostream &OS=dbgs())
Print the profile for FContext on stream OS.
SampleProfileMap & getProfiles()
Return all the profiles.
uint32_t CSProfileCount
Number of context-sensitive profiles.
void dump(raw_ostream &OS=dbgs())
Print all the profiles on stream OS.
const Module * M
The current module being compiled if SampleProfileReader is used by compiler.
std::unique_ptr< MemoryBuffer > Buffer
Memory buffer holding the profile file.
std::unique_ptr< SampleProfileReaderItaniumRemapper > Remapper
virtual bool useMD5()
Return whether names in the profile are all MD5 numbers.
bool ProfileIsCS
Whether function profiles are context-sensitive flat profiles.
std::unique_ptr< ProfileSummary > Summary
Profile summary information.
void computeSummary()
Compute summary for this profile.
uint32_t getDiscriminatorMask() const
Get the bitmask the discriminators: For FS profiles, return the bit mask for this pass.
bool ProfileIsFS
Whether the function profiles use FS discriminators.
void dumpJson(raw_ostream &OS=dbgs())
Print all the profiles on stream OS in the JSON format.
static ErrorOr< std::unique_ptr< SampleProfileReader > > create(const std::string Filename, LLVMContext &C, vfs::FileSystem &FS, FSDiscriminatorPass P=FSDiscriminatorPass::Base, const std::string RemapFilename="")
Create a sample profile reader appropriate to the file format.
SampleProfileMap Profiles
Map every function to its associated profile.
bool ProfileIsProbeBased
Whether samples are collected based on pseudo probes.
void reportError(int64_t LineNumber, const Twine &Msg) const
Report a parse error message.
Representation of a single sample record.
Definition: SampleProf.h:325
uint64_t getSamples() const
Definition: SampleProf.h:392
const SortedCallTargetSet getSortedCallTargets() const
Definition: SampleProf.h:394
The virtual file system interface.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
GCOVVersion
Definition: GCOV.h:41
@ V407
Definition: GCOV.h:41
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
Error decompress(ArrayRef< uint8_t > Input, uint8_t *Output, size_t &UncompressedSize)
void sortFuncProfiles(const SampleProfileMap &ProfileMap, std::vector< NameFunctionSamples > &SortedProfiles)
Definition: SampleProf.cpp:201
static uint64_t SPMagic(SampleProfileFormat Format=SPF_Binary)
Definition: SampleProf.h:99
static bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag)
Definition: SampleProf.h:267
std::map< LineLocation, FunctionSamplesMap > CallsiteSampleMap
Definition: SampleProf.h:719
std::map< LineLocation, SampleRecord > BodySampleMap
Definition: SampleProf.h:715
@ SecFlagIsPreInlined
SecFlagIsPreInlined means this profile contains ShouldBeInlined contexts thus this is CS preinliner c...
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
@ SecFlagFSDiscriminator
SecFlagFSDiscriminator means this profile uses flow-sensitive discriminators.
@ SecFlagFullContext
SecFlagContext means this is context-sensitive flat profile for CSSPGO.
SmallVector< SampleContextFrame, 1 > SampleContextFrameVector
Definition: SampleProf.h:498
static std::string getSecName(SecType Type)
Definition: SampleProf.h:134
static uint64_t SPVersion()
Definition: SampleProf.h:116
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:406
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition: Error.h:966
uint64_t decodeULEB128(const uint8_t *p, unsigned *n=nullptr, const uint8_t *end=nullptr, const char **error=nullptr)
Utility function to decode a ULEB128 value.
Definition: LEB128.h:128
void append_range(Container &C, Range &&R)
Wrapper function to append a range to a container.
Definition: STLExtras.h:2092
sampleprof_error
Definition: SampleProf.h:46
sampleprof_error MergeResult(sampleprof_error &Accumulator, sampleprof_error Result)
Definition: SampleProf.h:68
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:1974
uint64_t MD5Hash(StringRef Str)
Helper to compute and return lower 64 bits of the given string's MD5 hash.
Definition: MD5.h:109
@ DS_Warning
Represents the relative location of an instruction.
Definition: SampleProf.h:283