LLVM 18.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, and 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: " << FS.getContext().toString() << ": " << FS;
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.second, 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 FunctionSamples &FProfile = Profiles.Create(FContext);
359 MergeResult(Result, FProfile.addTotalSamples(NumSamples));
360 MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
361 InlineStack.clear();
362 InlineStack.push_back(&FProfile);
363 } else {
364 uint64_t NumSamples;
365 StringRef FName;
366 DenseMap<StringRef, uint64_t> TargetCountMap;
367 uint32_t Depth, LineOffset, Discriminator;
368 LineType LineTy;
369 uint64_t FunctionHash = 0;
371 if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
372 Discriminator, FName, TargetCountMap, FunctionHash,
373 Attributes)) {
374 reportError(LineIt.line_number(),
375 "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
376 *LineIt);
378 }
379 if (LineTy != LineType::Metadata && Depth == DepthMetadata) {
380 // Metadata must be put at the end of a function profile.
381 reportError(LineIt.line_number(),
382 "Found non-metadata after metadata: " + *LineIt);
384 }
385
386 // Here we handle FS discriminators.
387 Discriminator &= getDiscriminatorMask();
388
389 while (InlineStack.size() > Depth) {
390 InlineStack.pop_back();
391 }
392 switch (LineTy) {
393 case LineType::CallSiteProfile: {
394 FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
395 LineLocation(LineOffset, Discriminator))[std::string(FName)];
396 FSamples.setName(FName);
397 MergeResult(Result, FSamples.addTotalSamples(NumSamples));
398 InlineStack.push_back(&FSamples);
399 DepthMetadata = 0;
400 break;
401 }
402 case LineType::BodyProfile: {
403 while (InlineStack.size() > Depth) {
404 InlineStack.pop_back();
405 }
406 FunctionSamples &FProfile = *InlineStack.back();
407 for (const auto &name_count : TargetCountMap) {
408 MergeResult(Result, FProfile.addCalledTargetSamples(
409 LineOffset, Discriminator, name_count.first,
410 name_count.second));
411 }
412 MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
413 NumSamples));
414 break;
415 }
416 case LineType::Metadata: {
417 FunctionSamples &FProfile = *InlineStack.back();
418 if (FunctionHash) {
419 FProfile.setFunctionHash(FunctionHash);
420 if (Depth == 1)
421 ++TopLevelProbeProfileCount;
422 }
425 ProfileIsPreInlined = true;
426 DepthMetadata = Depth;
427 break;
428 }
429 }
430 }
431 }
432
433 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
434 "Cannot have both context-sensitive and regular profile");
436 assert((TopLevelProbeProfileCount == 0 ||
437 TopLevelProbeProfileCount == Profiles.size()) &&
438 "Cannot have both probe-based profiles and regular profiles");
439 ProfileIsProbeBased = (TopLevelProbeProfileCount > 0);
443
444 if (Result == sampleprof_error::success)
446
447 return Result;
448}
449
451 bool result = false;
452
453 // Check that the first non-comment line is a valid function header.
454 line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
455 if (!LineIt.is_at_eof()) {
456 if ((*LineIt)[0] != ' ') {
457 uint64_t NumSamples, NumHeadSamples;
458 StringRef FName;
459 result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
460 }
461 }
462
463 return result;
464}
465
467 unsigned NumBytesRead = 0;
468 std::error_code EC;
469 uint64_t Val = decodeULEB128(Data, &NumBytesRead);
470
471 if (Val > std::numeric_limits<T>::max())
473 else if (Data + NumBytesRead > End)
475 else
477
478 if (EC) {
479 reportError(0, EC.message());
480 return EC;
481 }
482
483 Data += NumBytesRead;
484 return static_cast<T>(Val);
485}
486
488 std::error_code EC;
489 StringRef Str(reinterpret_cast<const char *>(Data));
490 if (Data + Str.size() + 1 > End) {
492 reportError(0, EC.message());
493 return EC;
494 }
495
496 Data += Str.size() + 1;
497 return Str;
498}
499
500template <typename T>
502 std::error_code EC;
503
504 if (Data + sizeof(T) > End) {
506 reportError(0, EC.message());
507 return EC;
508 }
509
510 using namespace support;
511 T Val = endian::readNext<T, little, unaligned>(Data);
512 return Val;
513}
514
515template <typename T>
517 std::error_code EC;
518 auto Idx = readNumber<size_t>();
519 if (std::error_code EC = Idx.getError())
520 return EC;
521 if (*Idx >= Table.size())
523 return *Idx;
524}
525
529 if (std::error_code EC = Idx.getError())
530 return EC;
531
532 // Lazy loading, if the string has not been materialized from memory storing
533 // MD5 values, then it is default initialized with the null pointer. This can
534 // only happen when using fixed length MD5, that bounds check is performed
535 // while parsing the name table to ensure MD5NameMemStart points to an array
536 // with enough MD5 entries.
537 StringRef &SR = NameTable[*Idx];
538 if (!SR.data()) {
540 using namespace support;
541 uint64_t FID = endian::read<uint64_t, little, unaligned>(
542 MD5NameMemStart + (*Idx) * sizeof(uint64_t));
543 SR = MD5StringBuf.emplace_back(std::to_string(FID));
544 }
545 if (RetIdx)
546 *RetIdx = *Idx;
547 return SR;
548}
549
552 auto ContextIdx = readNumber<size_t>();
553 if (std::error_code EC = ContextIdx.getError())
554 return EC;
555 if (*ContextIdx >= CSNameTable.size())
557 if (RetIdx)
558 *RetIdx = *ContextIdx;
559 return CSNameTable[*ContextIdx];
560}
561
565 size_t Idx;
566 if (ProfileIsCS) {
567 auto FContext(readContextFromTable(&Idx));
568 if (std::error_code EC = FContext.getError())
569 return EC;
570 Context = SampleContext(*FContext);
571 } else {
572 auto FName(readStringFromTable(&Idx));
573 if (std::error_code EC = FName.getError())
574 return EC;
575 Context = SampleContext(*FName);
576 }
577 // Since MD5SampleContextStart may point to the profile's file data, need to
578 // make sure it is reading the same value on big endian CPU.
580 // Lazy computing of hash value, write back to the table to cache it. Only
581 // compute the context's hash value if it is being referenced for the first
582 // time.
583 if (Hash == 0) {
585 Hash = Context.getHashCode();
587 }
588 return std::make_pair(Context, Hash);
589}
590
591std::error_code
593 auto NumSamples = readNumber<uint64_t>();
594 if (std::error_code EC = NumSamples.getError())
595 return EC;
596 FProfile.addTotalSamples(*NumSamples);
597
598 // Read the samples in the body.
599 auto NumRecords = readNumber<uint32_t>();
600 if (std::error_code EC = NumRecords.getError())
601 return EC;
602
603 for (uint32_t I = 0; I < *NumRecords; ++I) {
604 auto LineOffset = readNumber<uint64_t>();
605 if (std::error_code EC = LineOffset.getError())
606 return EC;
607
608 if (!isOffsetLegal(*LineOffset)) {
609 return std::error_code();
610 }
611
612 auto Discriminator = readNumber<uint64_t>();
613 if (std::error_code EC = Discriminator.getError())
614 return EC;
615
616 auto NumSamples = readNumber<uint64_t>();
617 if (std::error_code EC = NumSamples.getError())
618 return EC;
619
620 auto NumCalls = readNumber<uint32_t>();
621 if (std::error_code EC = NumCalls.getError())
622 return EC;
623
624 // Here we handle FS discriminators:
625 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
626
627 for (uint32_t J = 0; J < *NumCalls; ++J) {
628 auto CalledFunction(readStringFromTable());
629 if (std::error_code EC = CalledFunction.getError())
630 return EC;
631
632 auto CalledFunctionSamples = readNumber<uint64_t>();
633 if (std::error_code EC = CalledFunctionSamples.getError())
634 return EC;
635
636 FProfile.addCalledTargetSamples(*LineOffset, DiscriminatorVal,
637 *CalledFunction, *CalledFunctionSamples);
638 }
639
640 FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples);
641 }
642
643 // Read all the samples for inlined function calls.
644 auto NumCallsites = readNumber<uint32_t>();
645 if (std::error_code EC = NumCallsites.getError())
646 return EC;
647
648 for (uint32_t J = 0; J < *NumCallsites; ++J) {
649 auto LineOffset = readNumber<uint64_t>();
650 if (std::error_code EC = LineOffset.getError())
651 return EC;
652
653 auto Discriminator = readNumber<uint64_t>();
654 if (std::error_code EC = Discriminator.getError())
655 return EC;
656
657 auto FName(readStringFromTable());
658 if (std::error_code EC = FName.getError())
659 return EC;
660
661 // Here we handle FS discriminators:
662 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
663
664 FunctionSamples &CalleeProfile = FProfile.functionSamplesAt(
665 LineLocation(*LineOffset, DiscriminatorVal))[std::string(*FName)];
666 CalleeProfile.setName(*FName);
667 if (std::error_code EC = readProfile(CalleeProfile))
668 return EC;
669 }
670
672}
673
674std::error_code
676 Data = Start;
677 auto NumHeadSamples = readNumber<uint64_t>();
678 if (std::error_code EC = NumHeadSamples.getError())
679 return EC;
680
681 auto FContextHash(readSampleContextFromTable());
682 if (std::error_code EC = FContextHash.getError())
683 return EC;
684
685 auto &[FContext, Hash] = *FContextHash;
686 // Use the cached hash value for insertion instead of recalculating it.
687 auto Res = Profiles.try_emplace(Hash, FContext, FunctionSamples());
688 FunctionSamples &FProfile = Res.first->second;
689 FProfile.setContext(FContext);
690 FProfile.addHeadSamples(*NumHeadSamples);
691
692 if (FContext.hasContext())
694
695 if (std::error_code EC = readProfile(FProfile))
696 return EC;
698}
699
703 while (Data < End) {
704 if (std::error_code EC = readFuncProfile(Data))
705 return EC;
706 }
707
709}
710
712 const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
713 Data = Start;
714 End = Start + Size;
715 switch (Entry.Type) {
716 case SecProfSummary:
717 if (std::error_code EC = readSummary())
718 return EC;
720 Summary->setPartialProfile(true);
727 break;
728 case SecNameTable: {
729 bool FixedLengthMD5 =
731 bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
732 // UseMD5 means if THIS section uses MD5, ProfileIsMD5 means if the entire
733 // profile uses MD5 for function name matching in IPO passes.
734 ProfileIsMD5 = ProfileIsMD5 || UseMD5;
737 if (std::error_code EC = readNameTableSec(UseMD5, FixedLengthMD5))
738 return EC;
739 break;
740 }
741 case SecCSNameTable: {
742 if (std::error_code EC = readCSNameTableSec())
743 return EC;
744 break;
745 }
746 case SecLBRProfile:
747 if (std::error_code EC = readFuncProfiles())
748 return EC;
749 break;
751 // If module is absent, we are using LLVM tools, and need to read all
752 // profiles, so skip reading the function offset table.
753 if (!M) {
754 Data = End;
755 } else {
758 "func offset table should always be sorted in CS profile");
759 if (std::error_code EC = readFuncOffsetTable())
760 return EC;
761 }
762 break;
763 case SecFuncMetadata: {
767 bool HasAttribute =
769 if (std::error_code EC = readFuncMetadata(HasAttribute))
770 return EC;
771 break;
772 }
774 if (std::error_code EC = readProfileSymbolList())
775 return EC;
776 break;
777 default:
778 if (std::error_code EC = readCustomSection(Entry))
779 return EC;
780 break;
781 }
783}
784
786 // If profile is CS, the function offset section is expected to consist of
787 // sequences of contexts in pre-order layout
788 // (e.g. [A, A:1 @ B, A:1 @ B:2.3 @ C] [D, D:1 @ E]), so that when a matched
789 // context in the module is found, the profiles of all its callees are
790 // recursively loaded. A list is needed since the order of profiles matters.
791 if (ProfileIsCS)
792 return true;
793
794 // If the profile is MD5, use the map container to lookup functions in
795 // the module. A remapper has no use on MD5 names.
796 if (useMD5())
797 return false;
798
799 // Profile is not MD5 and if a remapper is present, the remapped name of
800 // every function needed to be matched against the module, so use the list
801 // container since each entry is accessed.
802 if (Remapper)
803 return true;
804
805 // Otherwise use the map container for faster lookup.
806 // TODO: If the cardinality of the function offset section is much smaller
807 // than the number of functions in the module, using the list container can
808 // be always faster, but we need to figure out the constant factor to
809 // determine the cutoff.
810 return false;
811}
812
813
815 if (!M)
816 return false;
817 FuncsToUse.clear();
818 for (auto &F : *M)
820 return true;
821}
822
824 // If there are more than one function offset section, the profile associated
825 // with the previous section has to be done reading before next one is read.
826 FuncOffsetTable.clear();
827 FuncOffsetList.clear();
828
829 auto Size = readNumber<uint64_t>();
830 if (std::error_code EC = Size.getError())
831 return EC;
832
833 bool UseFuncOffsetList = useFuncOffsetList();
834 if (UseFuncOffsetList)
835 FuncOffsetList.reserve(*Size);
836 else
837 FuncOffsetTable.reserve(*Size);
838
839 for (uint64_t I = 0; I < *Size; ++I) {
840 auto FContextHash(readSampleContextFromTable());
841 if (std::error_code EC = FContextHash.getError())
842 return EC;
843
844 auto &[FContext, Hash] = *FContextHash;
845 auto Offset = readNumber<uint64_t>();
846 if (std::error_code EC = Offset.getError())
847 return EC;
848
849 if (UseFuncOffsetList)
850 FuncOffsetList.emplace_back(FContext, *Offset);
851 else
852 // Because Porfiles replace existing value with new value if collision
853 // happens, we also use the latest offset so that they are consistent.
854 FuncOffsetTable[Hash] = *Offset;
855 }
856
858}
859
861 // Collect functions used by current module if the Reader has been
862 // given a module.
863 // collectFuncsFromModule uses FunctionSamples::getCanonicalFnName
864 // which will query FunctionSamples::HasUniqSuffix, so it has to be
865 // called after FunctionSamples::HasUniqSuffix is set, i.e. after
866 // NameTable section is read.
867 bool LoadFuncsToBeUsed = collectFuncsFromModule();
868
869 // When LoadFuncsToBeUsed is false, we are using LLVM tool, need to read all
870 // profiles.
871 const uint8_t *Start = Data;
872 if (!LoadFuncsToBeUsed) {
873 while (Data < End) {
874 if (std::error_code EC = readFuncProfile(Data))
875 return EC;
876 }
877 assert(Data == End && "More data is read than expected");
878 } else {
879 // Load function profiles on demand.
880 if (Remapper) {
881 for (auto Name : FuncsToUse) {
882 Remapper->insert(Name);
883 }
884 }
885
886 if (ProfileIsCS) {
888 DenseSet<uint64_t> FuncGuidsToUse;
889 if (useMD5()) {
890 for (auto Name : FuncsToUse)
891 FuncGuidsToUse.insert(Function::getGUID(Name));
892 }
893
894 // For each function in current module, load all context profiles for
895 // the function as well as their callee contexts which can help profile
896 // guided importing for ThinLTO. This can be achieved by walking
897 // through an ordered context container, where contexts are laid out
898 // as if they were walked in preorder of a context trie. While
899 // traversing the trie, a link to the highest common ancestor node is
900 // kept so that all of its decendants will be loaded.
901 const SampleContext *CommonContext = nullptr;
902 for (const auto &NameOffset : FuncOffsetList) {
903 const auto &FContext = NameOffset.first;
904 auto FName = FContext.getName();
905 // For function in the current module, keep its farthest ancestor
906 // context. This can be used to load itself and its child and
907 // sibling contexts.
908 if ((useMD5() && FuncGuidsToUse.count(std::stoull(FName.data()))) ||
909 (!useMD5() && (FuncsToUse.count(FName) ||
910 (Remapper && Remapper->exist(FName))))) {
911 if (!CommonContext || !CommonContext->IsPrefixOf(FContext))
912 CommonContext = &FContext;
913 }
914
915 if (CommonContext == &FContext ||
916 (CommonContext && CommonContext->IsPrefixOf(FContext))) {
917 // Load profile for the current context which originated from
918 // the common ancestor.
919 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
920 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
921 return EC;
922 }
923 }
924 } else if (useMD5()) {
926 for (auto Name : FuncsToUse) {
927 auto GUID = MD5Hash(Name);
928 auto iter = FuncOffsetTable.find(GUID);
929 if (iter == FuncOffsetTable.end())
930 continue;
931 const uint8_t *FuncProfileAddr = Start + iter->second;
932 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
933 return EC;
934 }
935 } else if (Remapper) {
937 for (auto NameOffset : FuncOffsetList) {
938 SampleContext FContext(NameOffset.first);
939 auto FuncName = FContext.getName();
940 if (!FuncsToUse.count(FuncName) && !Remapper->exist(FuncName))
941 continue;
942 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
943 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
944 return EC;
945 }
946 } else {
948 for (auto Name : FuncsToUse) {
949 auto iter = FuncOffsetTable.find(MD5Hash(Name));
950 if (iter == FuncOffsetTable.end())
951 continue;
952 const uint8_t *FuncProfileAddr = Start + iter->second;
953 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
954 return EC;
955 }
956 }
957 Data = End;
958 }
959 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
960 "Cannot have both context-sensitive and regular profile");
962 "Section flag should be consistent with actual profile");
964}
965
967 if (!ProfSymList)
968 ProfSymList = std::make_unique<ProfileSymbolList>();
969
970 if (std::error_code EC = ProfSymList->read(Data, End - Data))
971 return EC;
972
973 Data = End;
975}
976
977std::error_code SampleProfileReaderExtBinaryBase::decompressSection(
978 const uint8_t *SecStart, const uint64_t SecSize,
979 const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) {
980 Data = SecStart;
981 End = SecStart + SecSize;
982 auto DecompressSize = readNumber<uint64_t>();
983 if (std::error_code EC = DecompressSize.getError())
984 return EC;
985 DecompressBufSize = *DecompressSize;
986
987 auto CompressSize = readNumber<uint64_t>();
988 if (std::error_code EC = CompressSize.getError())
989 return EC;
990
993
994 uint8_t *Buffer = Allocator.Allocate<uint8_t>(DecompressBufSize);
995 size_t UCSize = DecompressBufSize;
997 Buffer, UCSize);
998 if (E)
1000 DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer);
1002}
1003
1005 const uint8_t *BufStart =
1006 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1007
1008 for (auto &Entry : SecHdrTable) {
1009 // Skip empty section.
1010 if (!Entry.Size)
1011 continue;
1012
1013 // Skip sections without context when SkipFlatProf is true.
1015 continue;
1016
1017 const uint8_t *SecStart = BufStart + Entry.Offset;
1018 uint64_t SecSize = Entry.Size;
1019
1020 // If the section is compressed, decompress it into a buffer
1021 // DecompressBuf before reading the actual data. The pointee of
1022 // 'Data' will be changed to buffer hold by DecompressBuf
1023 // temporarily when reading the actual data.
1024 bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress);
1025 if (isCompressed) {
1026 const uint8_t *DecompressBuf;
1027 uint64_t DecompressBufSize;
1028 if (std::error_code EC = decompressSection(
1029 SecStart, SecSize, DecompressBuf, DecompressBufSize))
1030 return EC;
1031 SecStart = DecompressBuf;
1032 SecSize = DecompressBufSize;
1033 }
1034
1035 if (std::error_code EC = readOneSection(SecStart, SecSize, Entry))
1036 return EC;
1037 if (Data != SecStart + SecSize)
1039
1040 // Change the pointee of 'Data' from DecompressBuf to original Buffer.
1041 if (isCompressed) {
1042 Data = BufStart + Entry.Offset;
1043 End = BufStart + Buffer->getBufferSize();
1044 }
1045 }
1046
1048}
1049
1050std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
1051 if (Magic == SPMagic())
1054}
1055
1056std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
1057 if (Magic == SPMagic(SPF_Ext_Binary))
1060}
1061
1063 auto Size = readNumber<size_t>();
1064 if (std::error_code EC = Size.getError())
1065 return EC;
1066
1067 // Normally if useMD5 is true, the name table should have MD5 values, not
1068 // strings, however in the case that ExtBinary profile has multiple name
1069 // tables mixing string and MD5, all of them have to be normalized to use MD5,
1070 // because optimization passes can only handle either type.
1071 bool UseMD5 = useMD5();
1072 if (UseMD5)
1073 MD5StringBuf.reserve(MD5StringBuf.size() + *Size);
1074
1075 NameTable.clear();
1076 NameTable.reserve(*Size);
1077 if (!ProfileIsCS) {
1078 MD5SampleContextTable.clear();
1079 if (UseMD5)
1080 MD5SampleContextTable.reserve(*Size);
1081 else
1082 // If we are using strings, delay MD5 computation since only a portion of
1083 // names are used by top level functions. Use 0 to indicate MD5 value is
1084 // to be calculated as no known string has a MD5 value of 0.
1085 MD5SampleContextTable.resize(*Size);
1086 }
1087 for (size_t I = 0; I < *Size; ++I) {
1088 auto Name(readString());
1089 if (std::error_code EC = Name.getError())
1090 return EC;
1091 if (UseMD5) {
1092 uint64_t FID = hashFuncName(*Name);
1093 if (!ProfileIsCS)
1094 MD5SampleContextTable.emplace_back(FID);
1095 NameTable.emplace_back(MD5StringBuf.emplace_back(std::to_string(FID)));
1096 } else
1097 NameTable.push_back(*Name);
1098 }
1099 if (!ProfileIsCS)
1102}
1103
1104std::error_code
1106 bool FixedLengthMD5) {
1107 if (FixedLengthMD5) {
1108 if (!IsMD5)
1109 errs() << "If FixedLengthMD5 is true, UseMD5 has to be true";
1110 auto Size = readNumber<size_t>();
1111 if (std::error_code EC = Size.getError())
1112 return EC;
1113
1114 assert(Data + (*Size) * sizeof(uint64_t) == End &&
1115 "Fixed length MD5 name table does not contain specified number of "
1116 "entries");
1117 if (Data + (*Size) * sizeof(uint64_t) > End)
1119
1120 // Preallocate and initialize NameTable so we can check whether a name
1121 // index has been read before by checking whether the element in the
1122 // NameTable is empty, meanwhile readStringIndex can do the boundary
1123 // check using the size of NameTable.
1124 MD5StringBuf.reserve(MD5StringBuf.size() + *Size);
1125 NameTable.clear();
1126 NameTable.resize(*Size);
1128 if (!ProfileIsCS)
1129 MD5SampleContextStart = reinterpret_cast<const uint64_t *>(Data);
1130 Data = Data + (*Size) * sizeof(uint64_t);
1132 }
1133
1134 if (IsMD5) {
1135 assert(!FixedLengthMD5 && "FixedLengthMD5 should be unreachable here");
1136 auto Size = readNumber<size_t>();
1137 if (std::error_code EC = Size.getError())
1138 return EC;
1139
1140 MD5StringBuf.reserve(MD5StringBuf.size() + *Size);
1141 NameTable.clear();
1142 NameTable.reserve(*Size);
1143 if (!ProfileIsCS)
1144 MD5SampleContextTable.resize(*Size);
1145 for (size_t I = 0; I < *Size; ++I) {
1146 auto FID = readNumber<uint64_t>();
1147 if (std::error_code EC = FID.getError())
1148 return EC;
1149 if (!ProfileIsCS)
1151 NameTable.emplace_back(MD5StringBuf.emplace_back(std::to_string(*FID)));
1152 }
1153 if (!ProfileIsCS)
1156 }
1157
1159}
1160
1161// Read in the CS name table section, which basically contains a list of context
1162// vectors. Each element of a context vector, aka a frame, refers to the
1163// underlying raw function names that are stored in the name table, as well as
1164// a callsite identifier that only makes sense for non-leaf frames.
1166 auto Size = readNumber<size_t>();
1167 if (std::error_code EC = Size.getError())
1168 return EC;
1169
1170 CSNameTable.clear();
1171 CSNameTable.reserve(*Size);
1172 if (ProfileIsCS) {
1173 // Delay MD5 computation of CS context until they are needed. Use 0 to
1174 // indicate MD5 value is to be calculated as no known string has a MD5
1175 // value of 0.
1176 MD5SampleContextTable.clear();
1177 MD5SampleContextTable.resize(*Size);
1179 }
1180 for (size_t I = 0; I < *Size; ++I) {
1181 CSNameTable.emplace_back(SampleContextFrameVector());
1182 auto ContextSize = readNumber<uint32_t>();
1183 if (std::error_code EC = ContextSize.getError())
1184 return EC;
1185 for (uint32_t J = 0; J < *ContextSize; ++J) {
1186 auto FName(readStringFromTable());
1187 if (std::error_code EC = FName.getError())
1188 return EC;
1189 auto LineOffset = readNumber<uint64_t>();
1190 if (std::error_code EC = LineOffset.getError())
1191 return EC;
1192
1193 if (!isOffsetLegal(*LineOffset))
1194 return std::error_code();
1195
1196 auto Discriminator = readNumber<uint64_t>();
1197 if (std::error_code EC = Discriminator.getError())
1198 return EC;
1199
1200 CSNameTable.back().emplace_back(
1201 FName.get(), LineLocation(LineOffset.get(), Discriminator.get()));
1202 }
1203 }
1204
1206}
1207
1208std::error_code
1210 FunctionSamples *FProfile) {
1211 if (Data < End) {
1212 if (ProfileIsProbeBased) {
1213 auto Checksum = readNumber<uint64_t>();
1214 if (std::error_code EC = Checksum.getError())
1215 return EC;
1216 if (FProfile)
1217 FProfile->setFunctionHash(*Checksum);
1218 }
1219
1220 if (ProfileHasAttribute) {
1221 auto Attributes = readNumber<uint32_t>();
1222 if (std::error_code EC = Attributes.getError())
1223 return EC;
1224 if (FProfile)
1226 }
1227
1228 if (!ProfileIsCS) {
1229 // Read all the attributes for inlined function calls.
1230 auto NumCallsites = readNumber<uint32_t>();
1231 if (std::error_code EC = NumCallsites.getError())
1232 return EC;
1233
1234 for (uint32_t J = 0; J < *NumCallsites; ++J) {
1235 auto LineOffset = readNumber<uint64_t>();
1236 if (std::error_code EC = LineOffset.getError())
1237 return EC;
1238
1239 auto Discriminator = readNumber<uint64_t>();
1240 if (std::error_code EC = Discriminator.getError())
1241 return EC;
1242
1243 auto FContextHash(readSampleContextFromTable());
1244 if (std::error_code EC = FContextHash.getError())
1245 return EC;
1246
1247 auto &[FContext, Hash] = *FContextHash;
1248 FunctionSamples *CalleeProfile = nullptr;
1249 if (FProfile) {
1250 CalleeProfile = const_cast<FunctionSamples *>(
1252 *LineOffset,
1253 *Discriminator))[std::string(FContext.getName())]);
1254 }
1255 if (std::error_code EC =
1256 readFuncMetadata(ProfileHasAttribute, CalleeProfile))
1257 return EC;
1258 }
1259 }
1260 }
1261
1263}
1264
1265std::error_code
1267 while (Data < End) {
1268 auto FContextHash(readSampleContextFromTable());
1269 if (std::error_code EC = FContextHash.getError())
1270 return EC;
1271 auto &[FContext, Hash] = *FContextHash;
1272 FunctionSamples *FProfile = nullptr;
1273 auto It = Profiles.find(FContext);
1274 if (It != Profiles.end())
1275 FProfile = &It->second;
1276
1277 if (std::error_code EC = readFuncMetadata(ProfileHasAttribute, FProfile))
1278 return EC;
1279 }
1280
1281 assert(Data == End && "More data is read than expected");
1283}
1284
1285std::error_code
1287 SecHdrTableEntry Entry;
1288 auto Type = readUnencodedNumber<uint64_t>();
1289 if (std::error_code EC = Type.getError())
1290 return EC;
1291 Entry.Type = static_cast<SecType>(*Type);
1292
1293 auto Flags = readUnencodedNumber<uint64_t>();
1294 if (std::error_code EC = Flags.getError())
1295 return EC;
1296 Entry.Flags = *Flags;
1297
1298 auto Offset = readUnencodedNumber<uint64_t>();
1299 if (std::error_code EC = Offset.getError())
1300 return EC;
1301 Entry.Offset = *Offset;
1302
1303 auto Size = readUnencodedNumber<uint64_t>();
1304 if (std::error_code EC = Size.getError())
1305 return EC;
1306 Entry.Size = *Size;
1307
1308 Entry.LayoutIndex = Idx;
1309 SecHdrTable.push_back(std::move(Entry));
1311}
1312
1314 auto EntryNum = readUnencodedNumber<uint64_t>();
1315 if (std::error_code EC = EntryNum.getError())
1316 return EC;
1317
1318 for (uint64_t i = 0; i < (*EntryNum); i++)
1319 if (std::error_code EC = readSecHdrTableEntry(i))
1320 return EC;
1321
1323}
1324
1326 const uint8_t *BufStart =
1327 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1328 Data = BufStart;
1329 End = BufStart + Buffer->getBufferSize();
1330
1331 if (std::error_code EC = readMagicIdent())
1332 return EC;
1333
1334 if (std::error_code EC = readSecHdrTable())
1335 return EC;
1336
1338}
1339
1341 uint64_t Size = 0;
1342 for (auto &Entry : SecHdrTable) {
1343 if (Entry.Type == Type)
1344 Size += Entry.Size;
1345 }
1346 return Size;
1347}
1348
1350 // Sections in SecHdrTable is not necessarily in the same order as
1351 // sections in the profile because section like FuncOffsetTable needs
1352 // to be written after section LBRProfile but needs to be read before
1353 // section LBRProfile, so we cannot simply use the last entry in
1354 // SecHdrTable to calculate the file size.
1355 uint64_t FileSize = 0;
1356 for (auto &Entry : SecHdrTable) {
1357 FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
1358 }
1359 return FileSize;
1360}
1361
1362static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
1363 std::string Flags;
1365 Flags.append("{compressed,");
1366 else
1367 Flags.append("{");
1368
1370 Flags.append("flat,");
1371
1372 switch (Entry.Type) {
1373 case SecNameTable:
1375 Flags.append("fixlenmd5,");
1377 Flags.append("md5,");
1379 Flags.append("uniq,");
1380 break;
1381 case SecProfSummary:
1383 Flags.append("partial,");
1385 Flags.append("context,");
1387 Flags.append("preInlined,");
1389 Flags.append("fs-discriminator,");
1390 break;
1391 case SecFuncOffsetTable:
1393 Flags.append("ordered,");
1394 break;
1395 case SecFuncMetadata:
1397 Flags.append("probe,");
1399 Flags.append("attr,");
1400 break;
1401 default:
1402 break;
1403 }
1404 char &last = Flags.back();
1405 if (last == ',')
1406 last = '}';
1407 else
1408 Flags.append("}");
1409 return Flags;
1410}
1411
1413 uint64_t TotalSecsSize = 0;
1414 for (auto &Entry : SecHdrTable) {
1415 OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset
1416 << ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
1417 << "\n";
1418 ;
1419 TotalSecsSize += Entry.Size;
1420 }
1421 uint64_t HeaderSize = SecHdrTable.front().Offset;
1422 assert(HeaderSize + TotalSecsSize == getFileSize() &&
1423 "Size of 'header + sections' doesn't match the total size of profile");
1424
1425 OS << "Header Size: " << HeaderSize << "\n";
1426 OS << "Total Sections Size: " << TotalSecsSize << "\n";
1427 OS << "File Size: " << getFileSize() << "\n";
1428 return true;
1429}
1430
1432 // Read and check the magic identifier.
1433 auto Magic = readNumber<uint64_t>();
1434 if (std::error_code EC = Magic.getError())
1435 return EC;
1436 else if (std::error_code EC = verifySPMagic(*Magic))
1437 return EC;
1438
1439 // Read the version number.
1440 auto Version = readNumber<uint64_t>();
1441 if (std::error_code EC = Version.getError())
1442 return EC;
1443 else if (*Version != SPVersion())
1445
1447}
1448
1450 Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1451 End = Data + Buffer->getBufferSize();
1452
1453 if (std::error_code EC = readMagicIdent())
1454 return EC;
1455
1456 if (std::error_code EC = readSummary())
1457 return EC;
1458
1459 if (std::error_code EC = readNameTable())
1460 return EC;
1462}
1463
1464std::error_code SampleProfileReaderBinary::readSummaryEntry(
1465 std::vector<ProfileSummaryEntry> &Entries) {
1466 auto Cutoff = readNumber<uint64_t>();
1467 if (std::error_code EC = Cutoff.getError())
1468 return EC;
1469
1470 auto MinBlockCount = readNumber<uint64_t>();
1471 if (std::error_code EC = MinBlockCount.getError())
1472 return EC;
1473
1474 auto NumBlocks = readNumber<uint64_t>();
1475 if (std::error_code EC = NumBlocks.getError())
1476 return EC;
1477
1478 Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks);
1480}
1481
1483 auto TotalCount = readNumber<uint64_t>();
1484 if (std::error_code EC = TotalCount.getError())
1485 return EC;
1486
1487 auto MaxBlockCount = readNumber<uint64_t>();
1488 if (std::error_code EC = MaxBlockCount.getError())
1489 return EC;
1490
1491 auto MaxFunctionCount = readNumber<uint64_t>();
1492 if (std::error_code EC = MaxFunctionCount.getError())
1493 return EC;
1494
1495 auto NumBlocks = readNumber<uint64_t>();
1496 if (std::error_code EC = NumBlocks.getError())
1497 return EC;
1498
1499 auto NumFunctions = readNumber<uint64_t>();
1500 if (std::error_code EC = NumFunctions.getError())
1501 return EC;
1502
1503 auto NumSummaryEntries = readNumber<uint64_t>();
1504 if (std::error_code EC = NumSummaryEntries.getError())
1505 return EC;
1506
1507 std::vector<ProfileSummaryEntry> Entries;
1508 for (unsigned i = 0; i < *NumSummaryEntries; i++) {
1509 std::error_code EC = readSummaryEntry(Entries);
1510 if (EC != sampleprof_error::success)
1511 return EC;
1512 }
1513 Summary = std::make_unique<ProfileSummary>(
1514 ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0,
1515 *MaxFunctionCount, *NumBlocks, *NumFunctions);
1516
1518}
1519
1521 const uint8_t *Data =
1522 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1523 uint64_t Magic = decodeULEB128(Data);
1524 return Magic == SPMagic();
1525}
1526
1528 const uint8_t *Data =
1529 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1530 uint64_t Magic = decodeULEB128(Data);
1531 return Magic == SPMagic(SPF_Ext_Binary);
1532}
1533
1535 uint32_t dummy;
1536 if (!GcovBuffer.readInt(dummy))
1539}
1540
1542 if (sizeof(T) <= sizeof(uint32_t)) {
1543 uint32_t Val;
1544 if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
1545 return static_cast<T>(Val);
1546 } else if (sizeof(T) <= sizeof(uint64_t)) {
1547 uint64_t Val;
1548 if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
1549 return static_cast<T>(Val);
1550 }
1551
1552 std::error_code EC = sampleprof_error::malformed;
1553 reportError(0, EC.message());
1554 return EC;
1555}
1556
1558 StringRef Str;
1559 if (!GcovBuffer.readString(Str))
1561 return Str;
1562}
1563
1565 // Read the magic identifier.
1568
1569 // Read the version number. Note - the GCC reader does not validate this
1570 // version, but the profile creator generates v704.
1571 GCOV::GCOVVersion version;
1572 if (!GcovBuffer.readGCOVVersion(version))
1574
1575 if (version != GCOV::V407)
1577
1578 // Skip the empty integer.
1579 if (std::error_code EC = skipNextWord())
1580 return EC;
1581
1583}
1584
1586 uint32_t Tag;
1587 if (!GcovBuffer.readInt(Tag))
1589
1590 if (Tag != Expected)
1592
1593 if (std::error_code EC = skipNextWord())
1594 return EC;
1595
1597}
1598
1600 if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
1601 return EC;
1602
1603 uint32_t Size;
1604 if (!GcovBuffer.readInt(Size))
1606
1607 for (uint32_t I = 0; I < Size; ++I) {
1608 StringRef Str;
1609 if (!GcovBuffer.readString(Str))
1611 Names.push_back(std::string(Str));
1612 }
1613
1615}
1616
1618 if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
1619 return EC;
1620
1621 uint32_t NumFunctions;
1622 if (!GcovBuffer.readInt(NumFunctions))
1624
1625 InlineCallStack Stack;
1626 for (uint32_t I = 0; I < NumFunctions; ++I)
1627 if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
1628 return EC;
1629
1632}
1633
1635 const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
1636 uint64_t HeadCount = 0;
1637 if (InlineStack.size() == 0)
1638 if (!GcovBuffer.readInt64(HeadCount))
1640
1641 uint32_t NameIdx;
1642 if (!GcovBuffer.readInt(NameIdx))
1644
1645 StringRef Name(Names[NameIdx]);
1646
1647 uint32_t NumPosCounts;
1648 if (!GcovBuffer.readInt(NumPosCounts))
1650
1651 uint32_t NumCallsites;
1652 if (!GcovBuffer.readInt(NumCallsites))
1654
1655 FunctionSamples *FProfile = nullptr;
1656 if (InlineStack.size() == 0) {
1657 // If this is a top function that we have already processed, do not
1658 // update its profile again. This happens in the presence of
1659 // function aliases. Since these aliases share the same function
1660 // body, there will be identical replicated profiles for the
1661 // original function. In this case, we simply not bother updating
1662 // the profile of the original function.
1663 FProfile = &Profiles[Name];
1664 FProfile->addHeadSamples(HeadCount);
1665 if (FProfile->getTotalSamples() > 0)
1666 Update = false;
1667 } else {
1668 // Otherwise, we are reading an inlined instance. The top of the
1669 // inline stack contains the profile of the caller. Insert this
1670 // callee in the caller's CallsiteMap.
1671 FunctionSamples *CallerProfile = InlineStack.front();
1672 uint32_t LineOffset = Offset >> 16;
1673 uint32_t Discriminator = Offset & 0xffff;
1674 FProfile = &CallerProfile->functionSamplesAt(
1675 LineLocation(LineOffset, Discriminator))[std::string(Name)];
1676 }
1677 FProfile->setName(Name);
1678
1679 for (uint32_t I = 0; I < NumPosCounts; ++I) {
1683
1684 uint32_t NumTargets;
1685 if (!GcovBuffer.readInt(NumTargets))
1687
1688 uint64_t Count;
1689 if (!GcovBuffer.readInt64(Count))
1691
1692 // The line location is encoded in the offset as:
1693 // high 16 bits: line offset to the start of the function.
1694 // low 16 bits: discriminator.
1695 uint32_t LineOffset = Offset >> 16;
1696 uint32_t Discriminator = Offset & 0xffff;
1697
1698 InlineCallStack NewStack;
1699 NewStack.push_back(FProfile);
1700 llvm::append_range(NewStack, InlineStack);
1701 if (Update) {
1702 // Walk up the inline stack, adding the samples on this line to
1703 // the total sample count of the callers in the chain.
1704 for (auto *CallerProfile : NewStack)
1705 CallerProfile->addTotalSamples(Count);
1706
1707 // Update the body samples for the current profile.
1708 FProfile->addBodySamples(LineOffset, Discriminator, Count);
1709 }
1710
1711 // Process the list of functions called at an indirect call site.
1712 // These are all the targets that a function pointer (or virtual
1713 // function) resolved at runtime.
1714 for (uint32_t J = 0; J < NumTargets; J++) {
1715 uint32_t HistVal;
1716 if (!GcovBuffer.readInt(HistVal))
1718
1719 if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
1721
1722 uint64_t TargetIdx;
1723 if (!GcovBuffer.readInt64(TargetIdx))
1725 StringRef TargetName(Names[TargetIdx]);
1726
1727 uint64_t TargetCount;
1728 if (!GcovBuffer.readInt64(TargetCount))
1730
1731 if (Update)
1732 FProfile->addCalledTargetSamples(LineOffset, Discriminator,
1733 TargetName, TargetCount);
1734 }
1735 }
1736
1737 // Process all the inlined callers into the current function. These
1738 // are all the callsites that were inlined into this function.
1739 for (uint32_t I = 0; I < NumCallsites; I++) {
1740 // The offset is encoded as:
1741 // high 16 bits: line offset to the start of the function.
1742 // low 16 bits: discriminator.
1746 InlineCallStack NewStack;
1747 NewStack.push_back(FProfile);
1748 llvm::append_range(NewStack, InlineStack);
1749 if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
1750 return EC;
1751 }
1752
1754}
1755
1756/// Read a GCC AutoFDO profile.
1757///
1758/// This format is generated by the Linux Perf conversion tool at
1759/// https://github.com/google/autofdo.
1761 assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator");
1762 // Read the string table.
1763 if (std::error_code EC = readNameTable())
1764 return EC;
1765
1766 // Read the source profile.
1767 if (std::error_code EC = readFunctionProfiles())
1768 return EC;
1769
1771}
1772
1774 StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart()));
1775 return Magic == "adcg*704";
1776}
1777
1779 // If the reader uses MD5 to represent string, we can't remap it because
1780 // we don't know what the original function names were.
1781 if (Reader.useMD5()) {
1783 Reader.getBuffer()->getBufferIdentifier(),
1784 "Profile data remapping cannot be applied to profile data "
1785 "using MD5 names (original mangled names are not available).",
1786 DS_Warning));
1787 return;
1788 }
1789
1790 // CSSPGO-TODO: Remapper is not yet supported.
1791 // We will need to remap the entire context string.
1792 assert(Remappings && "should be initialized while creating remapper");
1793 for (auto &Sample : Reader.getProfiles()) {
1794 DenseSet<StringRef> NamesInSample;
1795 Sample.second.findAllNames(NamesInSample);
1796 for (auto &Name : NamesInSample)
1797 if (auto Key = Remappings->insert(Name))
1798 NameMap.insert({Key, Name});
1799 }
1800
1801 RemappingApplied = true;
1802}
1803
1804std::optional<StringRef>
1806 if (auto Key = Remappings->lookup(Fname))
1807 return NameMap.lookup(Key);
1808 return std::nullopt;
1809}
1810
1811/// Prepare a memory buffer for the contents of \p Filename.
1812///
1813/// \returns an error code indicating the status of the buffer.
1816 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
1817 : FS.getBufferForFile(Filename);
1818 if (std::error_code EC = BufferOrErr.getError())
1819 return EC;
1820 auto Buffer = std::move(BufferOrErr.get());
1821
1822 return std::move(Buffer);
1823}
1824
1825/// Create a sample profile reader based on the format of the input file.
1826///
1827/// \param Filename The file to open.
1828///
1829/// \param C The LLVM context to use to emit diagnostics.
1830///
1831/// \param P The FSDiscriminatorPass.
1832///
1833/// \param RemapFilename The file used for profile remapping.
1834///
1835/// \returns an error code indicating the status of the created reader.
1837SampleProfileReader::create(const std::string Filename, LLVMContext &C,
1839 const std::string RemapFilename) {
1840 auto BufferOrError = setupMemoryBuffer(Filename, FS);
1841 if (std::error_code EC = BufferOrError.getError())
1842 return EC;
1843 return create(BufferOrError.get(), C, FS, P, RemapFilename);
1844}
1845
1846/// Create a sample profile remapper from the given input, to remap the
1847/// function names in the given profile data.
1848///
1849/// \param Filename The file to open.
1850///
1851/// \param Reader The profile reader the remapper is going to be applied to.
1852///
1853/// \param C The LLVM context to use to emit diagnostics.
1854///
1855/// \returns an error code indicating the status of the created reader.
1858 vfs::FileSystem &FS,
1859 SampleProfileReader &Reader,
1860 LLVMContext &C) {
1861 auto BufferOrError = setupMemoryBuffer(Filename, FS);
1862 if (std::error_code EC = BufferOrError.getError())
1863 return EC;
1864 return create(BufferOrError.get(), Reader, C);
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 B The memory buffer to create the reader from (assumes ownership).
1871///
1872/// \param C The LLVM context to use to emit diagnostics.
1873///
1874/// \param Reader The profile reader the remapper is going to be applied to.
1875///
1876/// \returns an error code indicating the status of the created reader.
1878SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B,
1879 SampleProfileReader &Reader,
1880 LLVMContext &C) {
1881 auto Remappings = std::make_unique<SymbolRemappingReader>();
1882 if (Error E = Remappings->read(*B)) {
1884 std::move(E), [&](const SymbolRemappingParseError &ParseError) {
1885 C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(),
1886 ParseError.getLineNum(),
1887 ParseError.getMessage()));
1888 });
1890 }
1891
1892 return std::make_unique<SampleProfileReaderItaniumRemapper>(
1893 std::move(B), std::move(Remappings), Reader);
1894}
1895
1896/// Create a sample profile reader based on the format of the input data.
1897///
1898/// \param B The memory buffer to create the reader from (assumes ownership).
1899///
1900/// \param C The LLVM context to use to emit diagnostics.
1901///
1902/// \param P The FSDiscriminatorPass.
1903///
1904/// \param RemapFilename The file used for profile remapping.
1905///
1906/// \returns an error code indicating the status of the created reader.
1908SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
1910 const std::string RemapFilename) {
1911 std::unique_ptr<SampleProfileReader> Reader;
1913 Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
1915 Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
1917 Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
1919 Reader.reset(new SampleProfileReaderText(std::move(B), C));
1920 else
1922
1923 if (!RemapFilename.empty()) {
1925 RemapFilename, FS, *Reader, C);
1926 if (std::error_code EC = ReaderOrErr.getError()) {
1927 std::string Msg = "Could not create remapper: " + EC.message();
1928 C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg));
1929 return EC;
1930 }
1931 Reader->Remapper = std::move(ReaderOrErr.get());
1932 }
1933
1934 if (std::error_code EC = Reader->readHeader()) {
1935 return EC;
1936 }
1937
1938 Reader->setDiscriminatorMaskedBitFrom(P);
1939
1940 return std::move(Reader);
1941}
1942
1943// For text and GCC file formats, we compute the summary after reading the
1944// profile. Binary format has the profile summary in its header.
1947 Summary = Builder.computeSummaryForProfiles(Profiles);
1948}
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.
LLVMContext & Context
#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
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
Lightweight error class with error context and mandatory checking.
Definition: Error.h:154
Tagged union holding either a T or a Error.
Definition: Error.h:468
bool readInt(uint32_t &Val)
Definition: GCOV.h:152
bool readInt64(uint64_t &Val)
Definition: GCOV.h:162
bool readGCOVVersion(GCOV::GCOVVersion &version)
readGCOVVersion - Read GCOV version.
Definition: GCOV.h:108
bool readString(StringRef &str)
Definition: GCOV.h:170
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
Definition: GCOV.h:94
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:62
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: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 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:404
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:381
size_t rfind(char C, size_t From=npos) const
Search for the last character C in the string.
Definition: StringRef.h:351
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:301
StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
Definition: StringRef.h:819
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
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
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:964
void object(Block Contents)
Emit an object whose elements are emitted in the provided Block.
Definition: JSON.h:994
void attribute(llvm::StringRef Key, const Value &Contents)
Emit an attribute whose value is self-contained (number, vector<int> etc).
Definition: JSON.h:1019
void arrayBegin()
Definition: JSON.cpp:844
void attributeArray(llvm::StringRef Key, Block Contents)
Emit an attribute whose value is an array with elements from the Block.
Definition: JSON.h:1023
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:751
void setName(StringRef FunctionName)
Set the name of the function.
Definition: SampleProf.h:1068
sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:758
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:945
sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:777
FunctionSamplesMap & functionSamplesAt(const LineLocation &Loc)
Return the function samples at the given callsite location.
Definition: SampleProf.h:911
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
Definition: SampleProf.h:1087
sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator, uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:785
void setFunctionHash(uint64_t Hash)
Definition: SampleProf.h:1076
static bool ProfileIsFS
If this profile uses flow sensitive discriminators.
Definition: SampleProf.h:1194
sampleprof_error addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator, StringRef FName, uint64_t Num, uint64_t Weight=1)
Definition: SampleProf.h:791
SampleContext & getContext() const
Definition: SampleProf.h:1183
static bool HasUniqSuffix
Whether the profile contains any ".__uniq." suffix in a name.
Definition: SampleProf.h:1191
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
Definition: SampleProf.h:937
const CallsiteSampleMap & getCallsiteSamples() const
Return all the callsite samples collected in the body of the function.
Definition: SampleProf.h:979
void setContext(const SampleContext &FContext)
Definition: SampleProf.h:1185
StringRef getName() const
Return the function name.
Definition: SampleProf.h:1071
const BodySampleMap & getBodySamples() const
Return all the samples collected in the body of the function.
Definition: SampleProf.h:976
std::pair< iterator, bool > try_emplace(const key_type &Hash, const original_key_type &Key, Ts &&...Args)
Definition: SampleProf.h:1328
void setAllAttributes(uint32_t A)
Definition: SampleProf.h:615
bool IsPrefixOf(const SampleContext &That) const
Definition: SampleProf.h:703
iterator find(const SampleContext &Ctx)
Definition: SampleProf.h:1393
mapped_type & Create(const SampleContext &Ctx)
Definition: SampleProf.h:1386
std::error_code readProfile(FunctionSamples &FProfile)
Read the contents of the given profile instance.
std::error_code readNameTable()
Read the whole name table.
const uint8_t * Data
Points to the current location in the buffer.
std::vector< std::string > MD5StringBuf
If MD5 is used in NameTable section, the section saves uint64_t data.
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.
const uint8_t * MD5NameMemStart
The starting address of fixed length MD5 name table section.
ErrorOr< SampleContextFrames > readContextFromTable(size_t *RetIdx=nullptr)
Read a context indirectly via the CSNameTable.
ErrorOr< std::pair< SampleContext, uint64_t > > readSampleContextFromTable()
Read a context indirectly via the CSNameTable if the profile has context, otherwise same as readStrin...
std::error_code readHeader() override
Read and validate the file header.
const uint64_t * MD5SampleContextStart
The starting address of the table of MD5 values of sample contexts.
std::vector< SampleContextFrameVector > CSNameTable
CSNameTable is used to save full context vectors.
ErrorOr< StringRef > readStringFromTable(size_t *RetIdx=nullptr)
Read a string indirectly via the name table. Optionally return the index.
std::error_code readImpl() override
Read sample profiles from the associated file.
std::vector< uint64_t > MD5SampleContextTable
Table to cache MD5 values of sample contexts corresponding to readSampleContextFromTable(),...
ErrorOr< size_t > readStringIndex(T &Table)
Read the string index and check whether it overflows the table.
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.
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::vector< std::pair< SampleContext, uint64_t > > FuncOffsetList
The list version of FuncOffsetTable.
DenseSet< StringRef > FuncsToUse
The set containing the functions to use when compiling a module.
std::unique_ptr< ProfileSymbolList > ProfSymList
bool useFuncOffsetList() const
Determine which container readFuncOffsetTable() should populate, the list FuncOffsetList or the map F...
std::error_code readNameTableSec(bool IsMD5, bool FixedLengthMD5)
std::error_code readImpl() override
Read sample profiles in extensible format from the associated file.
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.
DenseMap< hash_code, uint64_t > FuncOffsetTable
The table mapping from a function context's MD5 to the offset of its FunctionSample towards file star...
std::error_code readHeader() override
Read and validate the file header.
uint64_t getFileSize()
Get the total size of header and all sections.
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.
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.
bool useMD5() const
Return whether names in the profile are all MD5 numbers.
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
bool ProfileIsCS
Whether function profiles are context-sensitive flat profiles.
bool ProfileIsMD5
Whether the profile uses MD5 for Sample Contexts and function names.
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.
void dumpFunctionProfile(const FunctionSamples &FS, raw_ostream &OS=dbgs())
Print the profile for FunctionSamples on stream OS.
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:339
uint64_t getSamples() const
Definition: SampleProf.h:406
const SortedCallTargetSet getSortedCallTargets() const
Definition: SampleProf.h:408
The virtual file system interface.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
GCOVVersion
Definition: GCOV.h:42
@ V407
Definition: GCOV.h:42
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
Error decompress(ArrayRef< uint8_t > Input, uint8_t *Output, size_t &UncompressedSize)
static uint64_t hashFuncName(StringRef F)
Definition: SampleProf.h:321
void sortFuncProfiles(const SampleProfileMap &ProfileMap, std::vector< NameFunctionSamples > &SortedProfiles)
Definition: SampleProf.cpp:201
static uint64_t SPMagic(SampleProfileFormat Format=SPF_Binary)
Definition: SampleProf.h:105
static bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag)
Definition: SampleProf.h:273
std::map< LineLocation, FunctionSamplesMap > CallsiteSampleMap
Definition: SampleProf.h:742
std::map< LineLocation, SampleRecord > BodySampleMap
Definition: SampleProf.h:738
@ 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:512
static std::string getSecName(SecType Type)
Definition: SampleProf.h:140
static uint64_t SPVersion()
Definition: SampleProf.h:122
uint64_t read64le(const void *P)
Definition: Endian.h:378
void write64le(void *P, uint64_t V)
Definition: Endian.h:409
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:440
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:964
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:2037
sampleprof_error
Definition: SampleProf.h:46
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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:1919
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:289