LLVM 24.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
60static cl::opt<bool>
61 LazyLoadNameTable("sample-profile-lazy-load-name-table", cl::init(true),
63 cl::desc("Lazy load the name table from the profile."));
64
65/// Dump the function profile for \p FName.
66///
67/// \param FContext Name + context of the function to print.
68/// \param OS Stream to emit the output to.
70 raw_ostream &OS) {
71 OS << "Function: " << FS.getContext().toString() << ": " << FS;
72}
73
74/// Dump all the function profiles found on stream \p OS.
76 std::vector<NameFunctionSamples> V;
78 for (const auto &I : V)
79 dumpFunctionProfile(*I.second, OS);
80}
81
83 json::OStream &JOS, bool TopLevel = false) {
84 auto DumpBody = [&](const BodySampleMap &BodySamples) {
85 for (const auto &I : BodySamples) {
86 const LineLocation &Loc = I.first;
87 const SampleRecord &Sample = I.second;
88 JOS.object([&] {
89 JOS.attribute("line", Loc.LineOffset);
90 if (Loc.Discriminator)
91 JOS.attribute("discriminator", Loc.Discriminator);
92 JOS.attribute("samples", Sample.getSamples());
93
94 auto CallTargets = Sample.getSortedCallTargets();
95 if (!CallTargets.empty()) {
96 JOS.attributeArray("calls", [&] {
97 for (const auto &J : CallTargets) {
98 JOS.object([&] {
99 JOS.attribute("function", J.first.str());
100 JOS.attribute("samples", J.second);
101 });
102 }
103 });
104 }
105 });
106 }
107 };
108
109 auto DumpCallsiteSamples = [&](const CallsiteSampleMap &CallsiteSamples) {
110 for (const auto &I : CallsiteSamples)
111 for (const auto &FS : I.second) {
112 const LineLocation &Loc = I.first;
113 const FunctionSamples &CalleeSamples = FS.second;
114 JOS.object([&] {
115 JOS.attribute("line", Loc.LineOffset);
116 if (Loc.Discriminator)
117 JOS.attribute("discriminator", Loc.Discriminator);
118 JOS.attributeArray(
119 "samples", [&] { dumpFunctionProfileJson(CalleeSamples, JOS); });
120 });
121 }
122 };
123
124 JOS.object([&] {
125 JOS.attribute("name", S.getFunction().str());
126 JOS.attribute("total", S.getTotalSamples());
127 if (TopLevel)
128 JOS.attribute("head", S.getHeadSamples());
129
130 const auto &BodySamples = S.getBodySamples();
131 if (!BodySamples.empty())
132 JOS.attributeArray("body", [&] { DumpBody(BodySamples); });
133
134 const auto &CallsiteSamples = S.getCallsiteSamples();
135 if (!CallsiteSamples.empty())
136 JOS.attributeArray("callsites",
137 [&] { DumpCallsiteSamples(CallsiteSamples); });
138 });
139}
140
141/// Dump all the function profiles found on stream \p OS in the JSON format.
143 std::vector<NameFunctionSamples> V;
145 json::OStream JOS(OS, 2);
146 JOS.arrayBegin();
147 for (const auto &F : V)
148 dumpFunctionProfileJson(*F.second, JOS, true);
149 JOS.arrayEnd();
150
151 // Emit a newline character at the end as json::OStream doesn't emit one.
152 OS << "\n";
153}
154
155/// Parse \p Input as function head.
156///
157/// Parse one line of \p Input, and update function name in \p FName,
158/// function's total sample count in \p NumSamples, function's entry
159/// count in \p NumHeadSamples.
160///
161/// \returns true if parsing is successful.
162static bool ParseHead(const StringRef &Input, StringRef &FName,
163 uint64_t &NumSamples, uint64_t &NumHeadSamples) {
164 if (Input[0] == ' ')
165 return false;
166 size_t n2 = Input.rfind(':');
167 size_t n1 = Input.rfind(':', n2 - 1);
168 FName = Input.substr(0, n1);
169 if (Input.substr(n1 + 1, n2 - n1 - 1).getAsInteger(10, NumSamples))
170 return false;
171 if (Input.substr(n2 + 1).getAsInteger(10, NumHeadSamples))
172 return false;
173 return true;
174}
175
176/// Returns true if line offset \p L is legal (only has 16 bits).
177static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; }
178
179/// Parse \p Input that contains metadata.
180/// Possible metadata:
181/// - CFG Checksum information:
182/// !CFGChecksum: 12345
183/// - CFG Checksum information:
184/// !Attributes: 1
185/// Stores the FunctionHash (a.k.a. CFG Checksum) into \p FunctionHash.
186static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash,
187 uint32_t &Attributes) {
188 if (Input.starts_with("!CFGChecksum:")) {
189 StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim();
190 return !CFGInfo.getAsInteger(10, FunctionHash);
191 }
192
193 if (Input.starts_with("!Attributes:")) {
194 StringRef Attrib = Input.substr(strlen("!Attributes:")).trim();
195 return !Attrib.getAsInteger(10, Attributes);
196 }
197
198 return false;
199}
200
207
208// Parse `Input` as a white-space separated list of `vtable:count` pairs. An
209// example input line is `_ZTVbar:1471 _ZTVfoo:630`.
212 for (size_t Index = Input.find_first_not_of(' '); Index != StringRef::npos;) {
213 size_t ColonIndex = Input.find(':', Index);
214 if (ColonIndex == StringRef::npos)
215 return false; // No colon found, invalid format.
216 StringRef TypeName = Input.substr(Index, ColonIndex - Index);
217 // CountIndex is the start index of count.
218 size_t CountStartIndex = ColonIndex + 1;
219 // NextIndex is the start index after the 'target:count' pair.
220 size_t NextIndex = Input.find_first_of(' ', CountStartIndex);
222 if (Input.substr(CountStartIndex, NextIndex - CountStartIndex)
223 .getAsInteger(10, Count))
224 return false; // Invalid count.
225 // Error on duplicated type names in one line of input.
226 auto [Iter, Inserted] = TypeCountMap.insert({TypeName, Count});
227 if (!Inserted)
228 return false;
229 Index = (NextIndex == StringRef::npos)
231 : Input.find_first_not_of(' ', NextIndex);
232 }
233 return true;
234}
235
236/// Parse \p Input as line sample.
237///
238/// \param Input input line.
239/// \param LineTy Type of this line.
240/// \param Depth the depth of the inline stack.
241/// \param NumSamples total samples of the line/inlined callsite.
242/// \param LineOffset line offset to the start of the function.
243/// \param Discriminator discriminator of the line.
244/// \param TargetCountMap map from indirect call target to count.
245/// \param FunctionHash the function's CFG hash, used by pseudo probe.
246///
247/// returns true if parsing is successful.
248static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth,
249 uint64_t &NumSamples, uint32_t &LineOffset,
250 uint32_t &Discriminator, StringRef &CalleeName,
251 DenseMap<StringRef, uint64_t> &TargetCountMap,
253 uint64_t &FunctionHash, uint32_t &Attributes,
254 bool &IsFlat) {
255 for (Depth = 0; Input[Depth] == ' '; Depth++)
256 ;
257 if (Depth == 0)
258 return false;
259
260 if (Input[Depth] == '!') {
261 LineTy = LineType::Metadata;
262 // This metadata is only for manual inspection only. We already created a
263 // FunctionSamples and put it in the profile map, so there is no point
264 // to skip profiles even they have no use for ThinLTO.
265 if (Input == StringRef(" !Flat")) {
266 IsFlat = true;
267 return true;
268 }
269 return parseMetadata(Input.substr(Depth), FunctionHash, Attributes);
270 }
271
272 size_t n1 = Input.find(':');
273 StringRef Loc = Input.substr(Depth, n1 - Depth);
274 size_t n2 = Loc.find('.');
275 if (n2 == StringRef::npos) {
276 if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset))
277 return false;
278 Discriminator = 0;
279 } else {
280 if (Loc.substr(0, n2).getAsInteger(10, LineOffset))
281 return false;
282 if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator))
283 return false;
284 }
285
286 StringRef Rest = Input.substr(n1 + 2);
287 if (isDigit(Rest[0])) {
288 LineTy = LineType::BodyProfile;
289 size_t n3 = Rest.find(' ');
290 if (n3 == StringRef::npos) {
291 if (Rest.getAsInteger(10, NumSamples))
292 return false;
293 } else {
294 if (Rest.substr(0, n3).getAsInteger(10, NumSamples))
295 return false;
296 }
297 // Find call targets and their sample counts.
298 // Note: In some cases, there are symbols in the profile which are not
299 // mangled. To accommodate such cases, use colon + integer pairs as the
300 // anchor points.
301 // An example:
302 // _M_construct<char *>:1000 string_view<std::allocator<char> >:437
303 // ":1000" and ":437" are used as anchor points so the string above will
304 // be interpreted as
305 // target: _M_construct<char *>
306 // count: 1000
307 // target: string_view<std::allocator<char> >
308 // count: 437
309 while (n3 != StringRef::npos) {
310 n3 += Rest.substr(n3).find_first_not_of(' ');
311 Rest = Rest.substr(n3);
312 n3 = Rest.find_first_of(':');
313 if (n3 == StringRef::npos || n3 == 0)
314 return false;
315
317 uint64_t count, n4;
318 while (true) {
319 // Get the segment after the current colon.
320 StringRef AfterColon = Rest.substr(n3 + 1);
321 // Get the target symbol before the current colon.
322 Target = Rest.substr(0, n3);
323 // Check if the word after the current colon is an integer.
324 n4 = AfterColon.find_first_of(' ');
325 n4 = (n4 != StringRef::npos) ? n3 + n4 + 1 : Rest.size();
326 StringRef WordAfterColon = Rest.substr(n3 + 1, n4 - n3 - 1);
327 if (!WordAfterColon.getAsInteger(10, count))
328 break;
329
330 // Try to find the next colon.
331 uint64_t n5 = AfterColon.find_first_of(':');
332 if (n5 == StringRef::npos)
333 return false;
334 n3 += n5 + 1;
335 }
336
337 // An anchor point is found. Save the {target, count} pair
338 TargetCountMap[Target] = count;
339 if (n4 == Rest.size())
340 break;
341 // Change n3 to the next blank space after colon + integer pair.
342 n3 = n4;
343 }
344 } else if (Rest.starts_with(kVTableProfPrefix)) {
346 return parseTypeCountMap(Rest.substr(strlen(kVTableProfPrefix)),
348 } else {
350 size_t n3 = Rest.find_last_of(':');
351 CalleeName = Rest.substr(0, n3);
352 if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
353 return false;
354 }
355 return true;
356}
357
358/// Load samples from a text file.
359///
360/// See the documentation at the top of the file for an explanation of
361/// the expected format.
362///
363/// \returns true if the file was loaded successfully, false otherwise.
365 line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
367
368 InlineCallStack InlineStack;
369 uint32_t TopLevelProbeProfileCount = 0;
370
371 // DepthMetadata tracks whether we have processed metadata for the current
372 // top-level or nested function profile.
373 uint32_t DepthMetadata = 0;
374
375 std::vector<SampleContext *> FlatSamples;
376
379 for (; !LineIt.is_at_eof(); ++LineIt) {
380 size_t pos = LineIt->find_first_not_of(' ');
381 if (pos == LineIt->npos || (*LineIt)[pos] == '#')
382 continue;
383 // Read the header of each function.
384 //
385 // Note that for function identifiers we are actually expecting
386 // mangled names, but we may not always get them. This happens when
387 // the compiler decides not to emit the function (e.g., it was inlined
388 // and removed). In this case, the binary will not have the linkage
389 // name for the function, so the profiler will emit the function's
390 // unmangled name, which may contain characters like ':' and '>' in its
391 // name (member functions, templates, etc).
392 //
393 // The only requirement we place on the identifier, then, is that it
394 // should not begin with a number.
395 if ((*LineIt)[0] != ' ') {
396 uint64_t NumSamples, NumHeadSamples;
397 StringRef FName;
398 if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) {
399 reportError(LineIt.line_number(),
400 "Expected 'mangled_name:NUM:NUM', found " + *LineIt);
402 }
403 DepthMetadata = 0;
404 SampleContext FContext(FName, CSNameTable);
405 if (FContext.hasContext())
407 FunctionSamples &FProfile = Profiles.create(FContext);
408 mergeSampleProfErrors(Result, FProfile.addTotalSamples(NumSamples));
409 mergeSampleProfErrors(Result, FProfile.addHeadSamples(NumHeadSamples));
410 InlineStack.clear();
411 InlineStack.push_back(&FProfile);
412 } else {
413 uint64_t NumSamples;
414 StringRef FName;
415 DenseMap<StringRef, uint64_t> TargetCountMap;
417 uint32_t Depth, LineOffset, Discriminator;
419 uint64_t FunctionHash = 0;
420 uint32_t Attributes = 0;
421 bool IsFlat = false;
422 // TODO: Update ParseLine to return an error code instead of a bool and
423 // report it.
424 if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
425 Discriminator, FName, TargetCountMap, TypeCountMap,
426 FunctionHash, Attributes, IsFlat)) {
427 switch (LineTy) {
429 reportError(LineIt.line_number(),
430 "Cannot parse metadata: " + *LineIt);
431 break;
433 reportError(LineIt.line_number(),
434 "Expected 'vtables [mangled_vtable:NUM]+', found " +
435 *LineIt);
436 break;
437 default:
438 reportError(LineIt.line_number(),
439 "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
440 *LineIt);
441 }
443 }
444 if (LineTy != LineType::Metadata && Depth == DepthMetadata) {
445 // Metadata must be put at the end of a function profile.
446 reportError(LineIt.line_number(),
447 "Found non-metadata after metadata: " + *LineIt);
449 }
450
451 // Here we handle FS discriminators.
452 Discriminator &= getDiscriminatorMask();
453
454 while (InlineStack.size() > Depth) {
455 InlineStack.pop_back();
456 }
457 switch (LineTy) {
459 FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
460 LineLocation(LineOffset, Discriminator))[FunctionId(FName)];
461 FSamples.setFunction(FunctionId(FName));
462 mergeSampleProfErrors(Result, FSamples.addTotalSamples(NumSamples));
463 InlineStack.push_back(&FSamples);
464 DepthMetadata = 0;
465 break;
466 }
467
470 Result, InlineStack.back()->addCallsiteVTableTypeProfAt(
471 LineLocation(LineOffset, Discriminator), TypeCountMap));
472 break;
473 }
474
476 FunctionSamples &FProfile = *InlineStack.back();
477 for (const auto &name_count : TargetCountMap) {
479 LineOffset, Discriminator,
480 FunctionId(name_count.first),
481 name_count.second));
482 }
484 Result,
485 FProfile.addBodySamples(LineOffset, Discriminator, NumSamples));
486 break;
487 }
488 case LineType::Metadata: {
489 FunctionSamples &FProfile = *InlineStack.back();
490 if (FunctionHash) {
491 FProfile.setFunctionHash(FunctionHash);
492 if (Depth == 1)
493 ++TopLevelProbeProfileCount;
494 }
495 FProfile.getContext().setAllAttributes(Attributes);
496 if (Attributes & (uint32_t)ContextShouldBeInlined)
497 ProfileIsPreInlined = true;
498 DepthMetadata = Depth;
499 if (IsFlat) {
500 if (Depth == 1)
501 FlatSamples.push_back(&FProfile.getContext());
502 else
504 Buffer->getBufferIdentifier(), LineIt.line_number(),
505 "!Flat may only be used at top level function.", DS_Warning));
506 }
507 break;
508 }
509 }
510 }
511 }
512
513 // Honor the option to skip flat functions. Since they are already added to
514 // the profile map, remove them all here.
515 if (SkipFlatProf)
516 for (SampleContext *FlatSample : FlatSamples)
517 Profiles.erase(*FlatSample);
518
519 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
520 "Cannot have both context-sensitive and regular profile");
522 assert((TopLevelProbeProfileCount == 0 ||
523 TopLevelProbeProfileCount == Profiles.size()) &&
524 "Cannot have both probe-based profiles and regular profiles");
525 ProfileIsProbeBased = (TopLevelProbeProfileCount > 0);
529
530 if (Result == sampleprof_error::success)
532
533 return Result;
534}
535
537 bool result = false;
538
539 // Check that the first non-comment line is a valid function header.
540 line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
541 if (!LineIt.is_at_eof()) {
542 if ((*LineIt)[0] != ' ') {
543 uint64_t NumSamples, NumHeadSamples;
544 StringRef FName;
545 result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
546 }
547 }
548
549 return result;
550}
551
553 unsigned NumBytesRead = 0;
554 uint64_t Val = decodeULEB128(Data, &NumBytesRead);
555
556 if (Val > std::numeric_limits<T>::max()) {
557 std::error_code EC = sampleprof_error::malformed;
558 reportError(0, EC.message());
559 return EC;
560 } else if (Data + NumBytesRead > End) {
561 std::error_code EC = sampleprof_error::truncated;
562 reportError(0, EC.message());
563 return EC;
564 }
565
566 Data += NumBytesRead;
567 return static_cast<T>(Val);
568}
569
571 StringRef Str(reinterpret_cast<const char *>(Data));
572 if (Data + Str.size() + 1 > End) {
573 std::error_code EC = sampleprof_error::truncated;
574 reportError(0, EC.message());
575 return EC;
576 }
577
578 Data += Str.size() + 1;
579 return Str;
580}
581
582template <typename T>
584 if (Data + sizeof(T) > End) {
585 std::error_code EC = sampleprof_error::truncated;
586 reportError(0, EC.message());
587 return EC;
588 }
589
590 using namespace support;
592 return Val;
593}
594
595template <typename T>
597 auto Idx = readNumber<size_t>();
598 if (std::error_code EC = Idx.getError())
599 return EC;
600 if (*Idx >= Table.size())
602 return *Idx;
603}
604
607 if (!NameTable)
609 auto Idx = readStringIndex(*NameTable);
610 if (std::error_code EC = Idx.getError())
611 return EC;
612 if (RetIdx)
613 *RetIdx = *Idx;
614 return (*NameTable)[*Idx];
615}
616
619 auto ContextIdx = readNumber<size_t>();
620 if (std::error_code EC = ContextIdx.getError())
621 return EC;
622 if (*ContextIdx >= CSNameTable.size())
624 if (RetIdx)
625 *RetIdx = *ContextIdx;
626 return CSNameTable[*ContextIdx];
627}
628
631 SampleContext Context;
632 size_t Idx;
633 if (ProfileIsCS) {
634 auto FContext(readContextFromTable(&Idx));
635 if (std::error_code EC = FContext.getError())
636 return EC;
637 Context = SampleContext(*FContext);
638 } else {
639 auto FName(readStringFromTable(&Idx));
640 if (std::error_code EC = FName.getError())
641 return EC;
642 Context = SampleContext(*FName);
643 }
644 // Since MD5SampleContextStart may point to the profile's file data, need to
645 // make sure it is reading the same value on big endian CPU.
647 // Lazy computing of hash value, write back to the table to cache it. Only
648 // compute the context's hash value if it is being referenced for the first
649 // time.
650 if (Hash == 0) {
652 Hash = Context.getHashCode();
654 }
655 return std::make_pair(Context, Hash);
656}
657
658std::error_code
660 auto NumVTableTypes = readNumber<uint32_t>();
661 if (std::error_code EC = NumVTableTypes.getError())
662 return EC;
663
664 for (uint32_t I = 0; I < *NumVTableTypes; ++I) {
665 auto VTableType(readStringFromTable());
666 if (std::error_code EC = VTableType.getError())
667 return EC;
668
669 auto VTableSamples = readNumber<uint64_t>();
670 if (std::error_code EC = VTableSamples.getError())
671 return EC;
672 // The source profile should not have duplicate vtable records at the same
673 // location. In case duplicate vtables are found, reader can emit a warning
674 // but continue processing the profile.
675 if (!M.insert(std::make_pair(*VTableType, *VTableSamples)).second) {
677 Buffer->getBufferIdentifier(), 0,
678 "Duplicate vtable type " + VTableType->str() +
679 " at the same location. Additional counters will be ignored.",
680 DS_Warning));
681 continue;
682 }
683 }
685}
686
687std::error_code
690 "Cannot read vtable profiles if ReadVTableProf is false");
691
692 // Read the vtable type profile for the callsite.
693 auto NumCallsites = readNumber<uint32_t>();
694 if (std::error_code EC = NumCallsites.getError())
695 return EC;
696
697 for (uint32_t I = 0; I < *NumCallsites; ++I) {
698 auto LineOffset = readNumber<uint64_t>();
699 if (std::error_code EC = LineOffset.getError())
700 return EC;
701
702 if (!isOffsetLegal(*LineOffset))
704
705 auto Discriminator = readNumber<uint64_t>();
706 if (std::error_code EC = Discriminator.getError())
707 return EC;
708
709 // Here we handle FS discriminators:
710 const uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
711
712 if (std::error_code EC = readVTableTypeCountMap(FProfile.getTypeSamplesAt(
713 LineLocation(*LineOffset, DiscriminatorVal))))
714 return EC;
715 }
717}
718
719std::error_code
721 auto NumSamples = readNumber<uint64_t>();
722 if (std::error_code EC = NumSamples.getError())
723 return EC;
724 FProfile.addTotalSamples(*NumSamples);
725
726 // Read the samples in the body.
727 auto NumRecords = readNumber<uint32_t>();
728 if (std::error_code EC = NumRecords.getError())
729 return EC;
730
731 for (uint32_t I = 0; I < *NumRecords; ++I) {
732 auto LineOffset = readNumber<uint64_t>();
733 if (std::error_code EC = LineOffset.getError())
734 return EC;
735
736 if (!isOffsetLegal(*LineOffset)) {
738 }
739
740 auto Discriminator = readNumber<uint64_t>();
741 if (std::error_code EC = Discriminator.getError())
742 return EC;
743
744 auto NumSamples = readNumber<uint64_t>();
745 if (std::error_code EC = NumSamples.getError())
746 return EC;
747
748 auto NumCalls = readNumber<uint32_t>();
749 if (std::error_code EC = NumCalls.getError())
750 return EC;
751
752 // Here we handle FS discriminators:
753 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
754
755 for (uint32_t J = 0; J < *NumCalls; ++J) {
756 auto CalledFunction(readStringFromTable());
757 if (std::error_code EC = CalledFunction.getError())
758 return EC;
759
760 auto CalledFunctionSamples = readNumber<uint64_t>();
761 if (std::error_code EC = CalledFunctionSamples.getError())
762 return EC;
763
764 FProfile.addCalledTargetSamples(*LineOffset, DiscriminatorVal,
765 *CalledFunction, *CalledFunctionSamples);
766 }
767
768 FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples);
769 }
770
771 // Read all the samples for inlined function calls.
772 auto NumCallsites = readNumber<uint32_t>();
773 if (std::error_code EC = NumCallsites.getError())
774 return EC;
775
776 for (uint32_t J = 0; J < *NumCallsites; ++J) {
777 auto LineOffset = readNumber<uint64_t>();
778 if (std::error_code EC = LineOffset.getError())
779 return EC;
780
781 auto Discriminator = readNumber<uint64_t>();
782 if (std::error_code EC = Discriminator.getError())
783 return EC;
784
785 auto FName(readStringFromTable());
786 if (std::error_code EC = FName.getError())
787 return EC;
788
789 // Here we handle FS discriminators:
790 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
791
792 FunctionSamples &CalleeProfile = FProfile.functionSamplesAt(
793 LineLocation(*LineOffset, DiscriminatorVal))[*FName];
794 CalleeProfile.setFunction(*FName);
795 if (std::error_code EC = readProfile(CalleeProfile))
796 return EC;
797 }
798
799 if (ReadVTableProf)
800 return readCallsiteVTableProf(FProfile);
801
803}
804
805std::error_code
808 Data = Start;
809 auto NumHeadSamples = readNumber<uint64_t>();
810 if (std::error_code EC = NumHeadSamples.getError())
811 return EC;
812
813 auto FContextHash(readSampleContextFromTable());
814 if (std::error_code EC = FContextHash.getError())
815 return EC;
816
817 auto &[FContext, Hash] = *FContextHash;
818 // Use the cached hash value for insertion instead of recalculating it.
819 auto Res = Profiles.try_emplace(Hash, FContext, FunctionSamples());
820 FunctionSamples &FProfile = Res.first->second;
821 FProfile.setContext(FContext);
822 FProfile.addHeadSamples(*NumHeadSamples);
823
824 if (FContext.hasContext())
826
827 if (std::error_code EC = readProfile(FProfile))
828 return EC;
830}
831
832std::error_code
836
840 while (Data < End) {
841 if (std::error_code EC = readFuncProfile(Data))
842 return EC;
843 }
844
846}
847
849 const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
850 Data = Start;
851 End = Start + Size;
852 switch (Entry.Type) {
853 case SecProfSummary:
854 if (std::error_code EC = readSummary())
855 return EC;
857 Summary->setPartialProfile(true);
865 ReadVTableProf = true;
866 break;
867 case SecNameTable: {
868 bool FixedLengthMD5 =
870 bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
871 // UseMD5 means if THIS section uses MD5, ProfileIsMD5 means if the entire
872 // profile uses MD5 for function name matching in IPO passes.
873 ProfileIsMD5 = ProfileIsMD5 || UseMD5;
876 bool IsEytzinger = hasSecFlag(Entry, SecNameTableFlags::SecFlagEytzinger);
877 if (std::error_code EC =
878 readNameTableSec(UseMD5, FixedLengthMD5, IsEytzinger))
879 return EC;
880 break;
881 }
882 case SecCSNameTable: {
883 if (std::error_code EC = readCSNameTableSec())
884 return EC;
885 break;
886 }
887 case SecLBRProfile:
888 ProfileSecRange = std::make_pair(Data, End);
889 if (std::error_code EC = readFuncProfiles())
890 return EC;
891 break;
893 // If module is absent, we are using LLVM tools, and need to read all
894 // profiles, so skip reading the function offset table.
895 if (!M) {
896 Data = End;
897 } else {
900 "func offset table should always be sorted in CS profile");
901 if (std::error_code EC = readFuncOffsetTable())
902 return EC;
903 }
904 break;
905 case SecFuncMetadata: {
911 if (std::error_code EC = readFuncMetadata())
912 return EC;
913 break;
914 }
916 if (std::error_code EC = readProfileSymbolList(
918 return EC;
919 break;
920 default:
921 if (std::error_code EC = readCustomSection(Entry))
922 return EC;
923 break;
924 }
926}
927
929 // If profile is CS, the function offset section is expected to consist of
930 // sequences of contexts in pre-order layout
931 // (e.g. [A, A:1 @ B, A:1 @ B:2.3 @ C] [D, D:1 @ E]), so that when a matched
932 // context in the module is found, the profiles of all its callees are
933 // recursively loaded. A list is needed since the order of profiles matters.
934 if (ProfileIsCS)
935 return true;
936
937 // If the profile is MD5, use the map container to lookup functions in
938 // the module. A remapper has no use on MD5 names.
939 if (useMD5())
940 return false;
941
942 // Profile is not MD5 and if a remapper is present, the remapped name of
943 // every function needed to be matched against the module, so use the list
944 // container since each entry is accessed.
945 if (Remapper)
946 return true;
947
948 // Otherwise use the map container for faster lookup.
949 // TODO: If the cardinality of the function offset section is much smaller
950 // than the number of functions in the module, using the list container can
951 // be always faster, but we need to figure out the constant factor to
952 // determine the cutoff.
953 return false;
954}
955
956std::error_code
958 SampleProfileMap &Profiles) {
959 if (FuncsToUse.empty())
961
962 Data = ProfileSecRange.first;
963 End = ProfileSecRange.second;
964 if (std::error_code EC = readFuncProfiles(FuncsToUse, Profiles))
965 return EC;
966 End = Data;
967 DenseSet<FunctionSamples *> ProfilesToReadMetadata;
968 for (auto FName : FuncsToUse) {
969 auto I = Profiles.find(FName);
970 if (I != Profiles.end())
971 ProfilesToReadMetadata.insert(&I->second);
972 }
973
974 if (std::error_code EC = readFuncMetadata(ProfilesToReadMetadata))
975 return EC;
977}
978
980 if (!M)
981 return false;
982 FuncsToUse.clear();
983 for (auto &F : *M)
985 return true;
986}
987
989 // If there are more than one function offset section, the profile associated
990 // with the previous section has to be done reading before next one is read.
991 FuncOffsetTable.reset();
992 FuncOffsetList.clear();
993
994 auto Size = readNumber<uint64_t>();
995 if (std::error_code EC = Size.getError())
996 return EC;
997
998 bool UseFuncOffsetList = useFuncOffsetList();
999 if (UseFuncOffsetList)
1000 FuncOffsetList.reserve(*Size);
1001 else
1003
1004 for (uint64_t I = 0; I < *Size; ++I) {
1005 auto FContextHash(readSampleContextFromTable());
1006 if (std::error_code EC = FContextHash.getError())
1007 return EC;
1008
1009 auto &[FContext, Hash] = *FContextHash;
1011 if (std::error_code EC = Offset.getError())
1012 return EC;
1013
1014 if (UseFuncOffsetList)
1015 FuncOffsetList.emplace_back(FContext, *Offset);
1016 else
1017 // Because Porfiles replace existing value with new value if collision
1018 // happens, we also use the latest offset so that they are consistent.
1019 FuncOffsetTable->insert(Hash, *Offset);
1020 }
1021
1023}
1024
1027 const uint8_t *Start = Data;
1028
1029 if (Remapper) {
1030 for (auto Name : FuncsToUse) {
1031 Remapper->insert(Name);
1032 }
1033 }
1034
1035 if (ProfileIsCS) {
1037 DenseSet<uint64_t> FuncGuidsToUse;
1038 if (useMD5()) {
1039 for (auto Name : FuncsToUse)
1041 }
1042
1043 // For each function in current module, load all context profiles for
1044 // the function as well as their callee contexts which can help profile
1045 // guided importing for ThinLTO. This can be achieved by walking
1046 // through an ordered context container, where contexts are laid out
1047 // as if they were walked in preorder of a context trie. While
1048 // traversing the trie, a link to the highest common ancestor node is
1049 // kept so that all of its decendants will be loaded.
1050 const SampleContext *CommonContext = nullptr;
1051 for (const auto &NameOffset : FuncOffsetList) {
1052 const auto &FContext = NameOffset.first;
1053 FunctionId FName = FContext.getFunction();
1054 StringRef FNameString;
1055 if (!useMD5())
1056 FNameString = FName.stringRef();
1057
1058 // For function in the current module, keep its farthest ancestor
1059 // context. This can be used to load itself and its child and
1060 // sibling contexts.
1061 if ((useMD5() && FuncGuidsToUse.count(FName.getHashCode())) ||
1062 (!useMD5() && (FuncsToUse.count(FNameString) ||
1063 (Remapper && Remapper->exist(FNameString))))) {
1064 if (!CommonContext || !CommonContext->isPrefixOf(FContext))
1065 CommonContext = &FContext;
1066 }
1067
1068 if (CommonContext == &FContext ||
1069 (CommonContext && CommonContext->isPrefixOf(FContext))) {
1070 // Load profile for the current context which originated from
1071 // the common ancestor.
1072 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
1073 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
1074 return EC;
1075 }
1076 }
1077 } else if (useMD5()) {
1079 for (auto Name : FuncsToUse) {
1080 auto GUID = MD5Hash(Name);
1081 if (auto Offset = FuncOffsetTable->lookup(GUID)) {
1082 const uint8_t *FuncProfileAddr = Start + *Offset;
1083 if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
1084 return EC;
1085 }
1086 }
1087 } else if (Remapper) {
1089 for (auto NameOffset : FuncOffsetList) {
1090 SampleContext FContext(NameOffset.first);
1091 auto FuncName = FContext.getFunction();
1092 StringRef FuncNameStr = FuncName.stringRef();
1093 if (!FuncsToUse.count(FuncNameStr) && !Remapper->exist(FuncNameStr))
1094 continue;
1095 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
1096 if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
1097 return EC;
1098 }
1099 } else {
1101 for (auto Name : FuncsToUse) {
1102 if (auto Offset = FuncOffsetTable->lookup(MD5Hash(Name))) {
1103 const uint8_t *FuncProfileAddr = Start + *Offset;
1104 if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
1105 return EC;
1106 }
1107 }
1108 }
1109
1111}
1112
1114 // Collect functions used by current module if the Reader has been
1115 // given a module.
1116 // collectFuncsFromModule uses FunctionSamples::getCanonicalFnName
1117 // which will query FunctionSamples::HasUniqSuffix, so it has to be
1118 // called after FunctionSamples::HasUniqSuffix is set, i.e. after
1119 // NameTable section is read.
1120 bool LoadFuncsToBeUsed = collectFuncsFromModule();
1121
1122 // When LoadFuncsToBeUsed is false, we are using LLVM tool, need to read all
1123 // profiles.
1124 if (!LoadFuncsToBeUsed) {
1125 while (Data < End) {
1126 if (std::error_code EC = readFuncProfile(Data))
1127 return EC;
1128 }
1129 assert(Data == End && "More data is read than expected");
1130 } else {
1131 // Load function profiles on demand.
1132 if (std::error_code EC = readFuncProfiles(FuncsToUse, Profiles))
1133 return EC;
1134 Data = End;
1135 }
1136 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
1137 "Cannot have both context-sensitive and regular profile");
1139 "Section flag should be consistent with actual profile");
1141}
1142
1143std::error_code
1149
1151 size_t Size = End - Data;
1152 if (Size % sizeof(uint64_t) != 0)
1154 const auto *Table = reinterpret_cast<const support::ulittle64_t *>(Data);
1155 size_t NumEntries = Size / sizeof(uint64_t);
1156 if (!ProfSymList)
1157 ProfSymList = std::make_unique<ProfileSymbolList>();
1158 ProfSymList->setColdGUIDTable(
1160 Data = End;
1162}
1163
1164std::error_code
1166 if (!ProfSymList)
1167 ProfSymList = std::make_unique<ProfileSymbolList>();
1168
1169 if (std::error_code EC = ProfSymList->read(Data, End - Data))
1170 return EC;
1171
1172 Data = End;
1174}
1175
1176std::error_code SampleProfileReaderExtBinaryBase::decompressSection(
1177 const uint8_t *SecStart, const uint64_t SecSize,
1178 const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) {
1179 Data = SecStart;
1180 End = SecStart + SecSize;
1181 auto DecompressSize = readNumber<uint64_t>();
1182 if (std::error_code EC = DecompressSize.getError())
1183 return EC;
1184 DecompressBufSize = *DecompressSize;
1185
1186 auto CompressSize = readNumber<uint64_t>();
1187 if (std::error_code EC = CompressSize.getError())
1188 return EC;
1189
1192
1193 uint8_t *Buffer = Allocator.Allocate<uint8_t>(DecompressBufSize);
1194 size_t UCSize = DecompressBufSize;
1196 Buffer, UCSize);
1197 if (E)
1199 DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer);
1201}
1202
1204 const uint8_t *BufStart =
1205 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1206
1207 for (auto &Entry : SecHdrTable) {
1208 // Skip empty section.
1209 if (!Entry.Size)
1210 continue;
1211
1212 // Skip sections without inlined functions when SkipFlatProf is true.
1214 continue;
1215
1216 const uint8_t *SecStart = BufStart + Entry.Offset;
1217 uint64_t SecSize = Entry.Size;
1218
1219 // If the section is compressed, decompress it into a buffer
1220 // DecompressBuf before reading the actual data. The pointee of
1221 // 'Data' will be changed to buffer hold by DecompressBuf
1222 // temporarily when reading the actual data.
1223 bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress);
1224 if (isCompressed) {
1225 const uint8_t *DecompressBuf;
1226 uint64_t DecompressBufSize;
1227 if (std::error_code EC = decompressSection(
1228 SecStart, SecSize, DecompressBuf, DecompressBufSize))
1229 return EC;
1230 SecStart = DecompressBuf;
1231 SecSize = DecompressBufSize;
1232 }
1233
1234 if (std::error_code EC = readOneSection(SecStart, SecSize, Entry))
1235 return EC;
1236 if (Data != SecStart + SecSize)
1238
1239 // Change the pointee of 'Data' from DecompressBuf to original Buffer.
1240 if (isCompressed) {
1241 Data = BufStart + Entry.Offset;
1242 End = BufStart + Buffer->getBufferSize();
1243 }
1244 }
1245
1247}
1248
1249std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
1250 if (Magic == SPMagic())
1253}
1254
1255std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
1256 if (Magic == SPMagic(SPF_Ext_Binary))
1259}
1260
1262 auto Size = readNumber<size_t>();
1263 if (std::error_code EC = Size.getError())
1264 return EC;
1265
1266 // Normally if useMD5 is true, the name table should have MD5 values, not
1267 // strings, however in the case that ExtBinary profile has multiple name
1268 // tables mixing string and MD5, all of them have to be normalized to use MD5,
1269 // because optimization passes can only handle either type.
1270 bool UseMD5 = useMD5();
1271
1272 std::vector<FunctionId> TableVec;
1273 TableVec.reserve(*Size);
1274 if (!ProfileIsCS) {
1275 MD5SampleContextTable.clear();
1276 if (UseMD5)
1277 MD5SampleContextTable.reserve(*Size);
1278 else
1279 // If we are using strings, delay MD5 computation since only a portion of
1280 // names are used by top level functions. Use 0 to indicate MD5 value is
1281 // to be calculated as no known string has a MD5 value of 0.
1282 MD5SampleContextTable.resize(*Size);
1283 }
1284 for (size_t I = 0; I < *Size; ++I) {
1285 auto Name(readString());
1286 if (std::error_code EC = Name.getError())
1287 return EC;
1288 if (UseMD5) {
1289 FunctionId FID(*Name);
1290 if (!ProfileIsCS)
1291 MD5SampleContextTable.emplace_back(FID.getHashCode());
1292 TableVec.emplace_back(FID);
1293 } else
1294 TableVec.push_back(FunctionId(*Name));
1295 }
1296 if (!ProfileIsCS)
1298 if (UseMD5)
1299 NameTable =
1300 std::make_unique<MD5SampleProfileNameTable>(std::move(TableVec));
1301 else
1302 NameTable =
1303 std::make_unique<StringSampleProfileNameTable>(std::move(TableVec));
1305}
1306
1308 bool IsMD5, bool FixedLengthMD5, bool IsEytzinger) {
1309 if (IsEytzinger)
1310 return readNameTableSecEytzinger(IsMD5, FixedLengthMD5);
1311 return readNameTableSecLegacy(IsMD5, FixedLengthMD5);
1312}
1313
1314// Read the Eytzinger layout for SecNameTable from an ExtBinary MD5 profile.
1315//
1316// The section consists of three sequential ULEB128 symbol counts (CS, Flat, and
1317// Inlinees) followed by their corresponding arrays of 64-bit MD5 hash keys laid
1318// out in Eytzinger order.
1320 bool IsMD5, bool FixedLengthMD5) {
1321 assert(IsMD5 && "Eytzinger name tables require MD5 representation");
1322 if (!IsMD5)
1324
1325 // Read the table sizes for CS, flat, and inlinee symbols.
1326 std::array<uint64_t, static_cast<size_t>(EytzingerSpan::NumSpans)> Counts;
1327 for (uint64_t &Count : Counts) {
1328 auto ValOrErr = readNumber<uint64_t>();
1329 if (std::error_code EC = ValOrErr.getError())
1330 return EC;
1331 Count = *ValOrErr;
1332 }
1333 auto [NumCS, NumFlat, NumInlinees] = Counts;
1334
1335 // Guard against unsigned overflow in total entry computation.
1336 if (NumCS > std::numeric_limits<uint32_t>::max() ||
1337 NumFlat > std::numeric_limits<uint32_t>::max() ||
1338 NumInlinees > std::numeric_limits<uint32_t>::max())
1340
1341 uint64_t TotalEntries = NumCS + NumFlat + NumInlinees;
1342 if (static_cast<size_t>(End - Data) < TotalEntries * sizeof(uint64_t))
1344
1345 NameTable = std::make_unique<EytzingerSampleProfileNameTable>(
1346 reinterpret_cast<const support::ulittle64_t *>(Data), NumCS, NumFlat,
1347 NumInlinees);
1348
1349 if (!ProfileIsCS)
1350 MD5SampleContextStart = reinterpret_cast<const uint64_t *>(Data);
1351 Data = Data + TotalEntries * sizeof(uint64_t);
1353}
1354
1355std::error_code
1357 bool FixedLengthMD5) {
1358 if (FixedLengthMD5) {
1359 if (!IsMD5)
1360 errs() << "If FixedLengthMD5 is true, UseMD5 has to be true";
1361 auto Size = readNumber<size_t>();
1362 if (std::error_code EC = Size.getError())
1363 return EC;
1364
1365 assert(Data + (*Size) * sizeof(uint64_t) == End &&
1366 "Fixed length MD5 name table does not contain specified number of "
1367 "entries");
1368 if (Data + (*Size) * sizeof(uint64_t) > End)
1370
1371 if (LazyLoadNameTable) {
1372 NameTable = std::make_unique<LazySampleProfileNameTable>(Data, *Size);
1373 } else {
1374 std::vector<FunctionId> TableVec;
1375 TableVec.reserve(*Size);
1376 for (size_t I = 0; I < *Size; ++I) {
1377 using namespace support;
1379 Data + I * sizeof(uint64_t), endianness::little);
1380 TableVec.emplace_back(FunctionId(FID));
1381 }
1382 NameTable =
1383 std::make_unique<MD5SampleProfileNameTable>(std::move(TableVec));
1384 }
1385 if (!ProfileIsCS)
1386 MD5SampleContextStart = reinterpret_cast<const uint64_t *>(Data);
1387 Data = Data + (*Size) * sizeof(uint64_t);
1389 }
1390
1391 if (IsMD5) {
1392 assert(!FixedLengthMD5 && "FixedLengthMD5 should be unreachable here");
1393 auto Size = readNumber<size_t>();
1394 if (std::error_code EC = Size.getError())
1395 return EC;
1396
1397 std::vector<FunctionId> TableVec;
1398 TableVec.reserve(*Size);
1399 if (!ProfileIsCS)
1400 MD5SampleContextTable.resize(*Size);
1401 for (size_t I = 0; I < *Size; ++I) {
1402 auto FID = readNumber<uint64_t>();
1403 if (std::error_code EC = FID.getError())
1404 return EC;
1405 if (!ProfileIsCS)
1407 TableVec.emplace_back(FunctionId(*FID));
1408 }
1409 if (!ProfileIsCS)
1411 NameTable =
1412 std::make_unique<MD5SampleProfileNameTable>(std::move(TableVec));
1414 }
1415
1417}
1418
1419// Read in the CS name table section, which basically contains a list of context
1420// vectors. Each element of a context vector, aka a frame, refers to the
1421// underlying raw function names that are stored in the name table, as well as
1422// a callsite identifier that only makes sense for non-leaf frames.
1424 auto Size = readNumber<size_t>();
1425 if (std::error_code EC = Size.getError())
1426 return EC;
1427
1428 CSNameTable.clear();
1429 CSNameTable.reserve(*Size);
1430 if (ProfileIsCS) {
1431 // Delay MD5 computation of CS context until they are needed. Use 0 to
1432 // indicate MD5 value is to be calculated as no known string has a MD5
1433 // value of 0.
1434 MD5SampleContextTable.clear();
1435 MD5SampleContextTable.resize(*Size);
1437 }
1438 for (size_t I = 0; I < *Size; ++I) {
1439 CSNameTable.emplace_back(SampleContextFrameVector());
1440 auto ContextSize = readNumber<uint32_t>();
1441 if (std::error_code EC = ContextSize.getError())
1442 return EC;
1443 for (uint32_t J = 0; J < *ContextSize; ++J) {
1444 auto FName(readStringFromTable());
1445 if (std::error_code EC = FName.getError())
1446 return EC;
1447 auto LineOffset = readNumber<uint64_t>();
1448 if (std::error_code EC = LineOffset.getError())
1449 return EC;
1450
1451 if (!isOffsetLegal(*LineOffset))
1453
1454 auto Discriminator = readNumber<uint64_t>();
1455 if (std::error_code EC = Discriminator.getError())
1456 return EC;
1457
1458 CSNameTable.back().emplace_back(
1459 FName.get(), LineLocation(LineOffset.get(), Discriminator.get()));
1460 }
1461 }
1462
1464}
1465
1466std::error_code
1468 if (Data < End) {
1469 if (ProfileIsProbeBased) {
1470 auto Checksum = readNumber<uint64_t>();
1471 if (std::error_code EC = Checksum.getError())
1472 return EC;
1473 if (FProfile)
1474 FProfile->setFunctionHash(*Checksum);
1475 }
1476
1477 if (ProfileHasAttribute) {
1478 auto Attributes = readNumber<uint32_t>();
1479 if (std::error_code EC = Attributes.getError())
1480 return EC;
1481 if (FProfile)
1482 FProfile->getContext().setAllAttributes(*Attributes);
1483 }
1484
1485 if (!ProfileIsCS) {
1486 // Read all the attributes for inlined function calls.
1487 auto NumCallsites = readNumber<uint32_t>();
1488 if (std::error_code EC = NumCallsites.getError())
1489 return EC;
1490
1491 for (uint32_t J = 0; J < *NumCallsites; ++J) {
1492 auto LineOffset = readNumber<uint64_t>();
1493 if (std::error_code EC = LineOffset.getError())
1494 return EC;
1495
1496 auto Discriminator = readNumber<uint64_t>();
1497 if (std::error_code EC = Discriminator.getError())
1498 return EC;
1499
1500 auto FContextHash(readSampleContextFromTable());
1501 if (std::error_code EC = FContextHash.getError())
1502 return EC;
1503
1504 auto &[FContext, Hash] = *FContextHash;
1505 FunctionSamples *CalleeProfile = nullptr;
1506 if (FProfile) {
1507 CalleeProfile = const_cast<FunctionSamples *>(
1509 *LineOffset, *Discriminator))[FContext.getFunction()]);
1510 }
1511 if (std::error_code EC = readFuncMetadata(CalleeProfile))
1512 return EC;
1513 }
1514 }
1515 }
1516
1518}
1519
1522 if (FuncMetadataIndex.empty())
1524
1525 for (auto *FProfile : Profiles) {
1526 auto R = FuncMetadataIndex.find(FProfile->getContext().getHashCode());
1527 if (R == FuncMetadataIndex.end())
1528 continue;
1529
1530 Data = R->second.first;
1531 End = R->second.second;
1532 if (std::error_code EC = readFuncMetadata(FProfile))
1533 return EC;
1534 assert(Data == End && "More data is read than expected");
1535 }
1537}
1538
1540 while (Data < End) {
1541 auto FContextHash(readSampleContextFromTable());
1542 if (std::error_code EC = FContextHash.getError())
1543 return EC;
1544 auto &[FContext, Hash] = *FContextHash;
1545 FunctionSamples *FProfile = nullptr;
1546 auto It = Profiles.find(FContext);
1547 if (It != Profiles.end())
1548 FProfile = &It->second;
1549
1550 const uint8_t *Start = Data;
1551 if (std::error_code EC = readFuncMetadata(FProfile))
1552 return EC;
1553
1554 FuncMetadataIndex[FContext.getHashCode()] = {Start, Data};
1555 }
1556
1557 assert(Data == End && "More data is read than expected");
1559}
1560
1561std::error_code
1563 SecHdrTableEntry Entry;
1565 if (std::error_code EC = Type.getError())
1566 return EC;
1567 Entry.Type = static_cast<SecType>(*Type);
1568
1569 auto Flags = readUnencodedNumber<uint64_t>();
1570 if (std::error_code EC = Flags.getError())
1571 return EC;
1572 Entry.Flags = *Flags;
1573
1575 if (std::error_code EC = Offset.getError())
1576 return EC;
1577 Entry.Offset = *Offset;
1578
1580 if (std::error_code EC = Size.getError())
1581 return EC;
1582 Entry.Size = *Size;
1583
1584 Entry.LayoutIndex = Idx;
1585 SecHdrTable.push_back(std::move(Entry));
1587}
1588
1590 auto EntryNum = readUnencodedNumber<uint64_t>();
1591 if (std::error_code EC = EntryNum.getError())
1592 return EC;
1593
1594 for (uint64_t i = 0; i < (*EntryNum); i++)
1595 if (std::error_code EC = readSecHdrTableEntry(i))
1596 return EC;
1597
1599}
1600
1602 const uint8_t *BufStart =
1603 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1604 Data = BufStart;
1605 End = BufStart + Buffer->getBufferSize();
1606
1607 if (std::error_code EC = readMagicIdent())
1608 return EC;
1609
1610 if (std::error_code EC = readSecHdrTable())
1611 return EC;
1612
1614}
1615
1617 uint64_t Size = 0;
1618 for (auto &Entry : SecHdrTable) {
1619 if (Entry.Type == Type)
1620 Size += Entry.Size;
1621 }
1622 return Size;
1623}
1624
1626 // Sections in SecHdrTable is not necessarily in the same order as
1627 // sections in the profile because section like FuncOffsetTable needs
1628 // to be written after section LBRProfile but needs to be read before
1629 // section LBRProfile, so we cannot simply use the last entry in
1630 // SecHdrTable to calculate the file size.
1631 uint64_t FileSize = 0;
1632 for (auto &Entry : SecHdrTable) {
1633 FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
1634 }
1635 return FileSize;
1636}
1637
1638static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
1639 std::string Flags;
1641 Flags.append("{compressed,");
1642 else
1643 Flags.append("{");
1644
1646 Flags.append("flat,");
1647
1648 switch (Entry.Type) {
1649 case SecNameTable:
1651 Flags.append("eytzinger,");
1653 Flags.append("fixlenmd5,");
1655 Flags.append("md5,");
1657 Flags.append("uniq,");
1658 break;
1659 case SecProfSummary:
1661 Flags.append("partial,");
1663 Flags.append("context,");
1665 Flags.append("preInlined,");
1667 Flags.append("fs-discriminator,");
1668 break;
1669 case SecFuncOffsetTable:
1671 Flags.append("ordered,");
1672 break;
1673 case SecFuncMetadata:
1675 Flags.append("probe,");
1677 Flags.append("attr,");
1678 break;
1681 Flags.append("md5,");
1682 break;
1683 default:
1684 break;
1685 }
1686 char &last = Flags.back();
1687 if (last == ',')
1688 last = '}';
1689 else
1690 Flags.append("}");
1691 return Flags;
1692}
1693
1695 uint64_t TotalSecsSize = 0;
1696 for (auto &Entry : SecHdrTable) {
1697 OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset
1698 << ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
1699 << "\n";
1700 ;
1701 TotalSecsSize += Entry.Size;
1702 }
1703 uint64_t HeaderSize = SecHdrTable.front().Offset;
1704 assert(HeaderSize + TotalSecsSize == getFileSize() &&
1705 "Size of 'header + sections' doesn't match the total size of profile");
1706
1707 OS << "Header Size: " << HeaderSize << "\n";
1708 OS << "Total Sections Size: " << TotalSecsSize << "\n";
1709 OS << "File Size: " << getFileSize() << "\n";
1710 return true;
1711}
1712
1714 // Read and check the magic identifier.
1715 auto Magic = readNumber<uint64_t>();
1716 if (std::error_code EC = Magic.getError())
1717 return EC;
1718 else if (std::error_code EC = verifySPMagic(*Magic))
1719 return EC;
1720
1721 // Read the version number.
1723 if (std::error_code EC = Version.getError())
1724 return EC;
1728
1730}
1731
1733 Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1734 End = Data + Buffer->getBufferSize();
1735
1736 if (std::error_code EC = readMagicIdent())
1737 return EC;
1738
1739 if (std::error_code EC = readSummary())
1740 return EC;
1741
1742 if (std::error_code EC = readNameTable())
1743 return EC;
1745}
1746
1747std::error_code SampleProfileReaderBinary::readSummaryEntry(
1748 std::vector<ProfileSummaryEntry> &Entries) {
1749 auto Cutoff = readNumber<uint64_t>();
1750 if (std::error_code EC = Cutoff.getError())
1751 return EC;
1752
1753 auto MinBlockCount = readNumber<uint64_t>();
1754 if (std::error_code EC = MinBlockCount.getError())
1755 return EC;
1756
1757 auto NumBlocks = readNumber<uint64_t>();
1758 if (std::error_code EC = NumBlocks.getError())
1759 return EC;
1760
1761 Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks);
1763}
1764
1766 auto TotalCount = readNumber<uint64_t>();
1767 if (std::error_code EC = TotalCount.getError())
1768 return EC;
1769
1770 auto MaxBlockCount = readNumber<uint64_t>();
1771 if (std::error_code EC = MaxBlockCount.getError())
1772 return EC;
1773
1774 auto MaxFunctionCount = readNumber<uint64_t>();
1775 if (std::error_code EC = MaxFunctionCount.getError())
1776 return EC;
1777
1778 auto NumBlocks = readNumber<uint64_t>();
1779 if (std::error_code EC = NumBlocks.getError())
1780 return EC;
1781
1782 auto NumFunctions = readNumber<uint64_t>();
1783 if (std::error_code EC = NumFunctions.getError())
1784 return EC;
1785
1786 auto NumSummaryEntries = readNumber<uint64_t>();
1787 if (std::error_code EC = NumSummaryEntries.getError())
1788 return EC;
1789
1790 std::vector<ProfileSummaryEntry> Entries;
1791 for (unsigned i = 0; i < *NumSummaryEntries; i++) {
1792 std::error_code EC = readSummaryEntry(Entries);
1793 if (EC != sampleprof_error::success)
1794 return EC;
1795 }
1796 Summary = std::make_unique<ProfileSummary>(
1797 ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0,
1798 *MaxFunctionCount, *NumBlocks, *NumFunctions);
1799
1801}
1802
1804 const uint8_t *Data =
1805 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1806 uint64_t Magic = decodeULEB128(Data);
1807 return Magic == SPMagic();
1808}
1809
1811 const uint8_t *Data =
1812 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1813 uint64_t Magic = decodeULEB128(Data);
1814 return Magic == SPMagic(SPF_Ext_Binary);
1815}
1816
1818 uint32_t dummy;
1819 if (!GcovBuffer.readInt(dummy))
1822}
1823
1825 if (sizeof(T) <= sizeof(uint32_t)) {
1826 uint32_t Val;
1827 if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
1828 return static_cast<T>(Val);
1829 } else if (sizeof(T) <= sizeof(uint64_t)) {
1830 uint64_t Val;
1831 if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
1832 return static_cast<T>(Val);
1833 }
1834
1835 std::error_code EC = sampleprof_error::malformed;
1836 reportError(0, EC.message());
1837 return EC;
1838}
1839
1841 StringRef Str;
1842 if (!GcovBuffer.readString(Str))
1844 return Str;
1845}
1846
1848 // Read the magic identifier.
1849 if (!GcovBuffer.readGCDAFormat())
1851
1852 // Read the version number. Note - the GCC reader does not validate this
1853 // version, but the profile creator generates v704.
1854 GCOV::GCOVVersion version;
1855 if (!GcovBuffer.readGCOVVersion(version))
1857
1858 if (version != GCOV::V407)
1860
1861 // Skip the empty integer.
1862 if (std::error_code EC = skipNextWord())
1863 return EC;
1864
1866}
1867
1869 uint32_t Tag;
1870 if (!GcovBuffer.readInt(Tag))
1872
1873 if (Tag != Expected)
1875
1876 if (std::error_code EC = skipNextWord())
1877 return EC;
1878
1880}
1881
1883 if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
1884 return EC;
1885
1886 uint32_t Size;
1887 if (!GcovBuffer.readInt(Size))
1889
1890 for (uint32_t I = 0; I < Size; ++I) {
1891 StringRef Str;
1892 if (!GcovBuffer.readString(Str))
1894 Names.push_back(std::string(Str));
1895 }
1896
1898}
1899
1901 if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
1902 return EC;
1903
1904 uint32_t NumFunctions;
1905 if (!GcovBuffer.readInt(NumFunctions))
1907
1908 InlineCallStack Stack;
1909 for (uint32_t I = 0; I < NumFunctions; ++I)
1910 if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
1911 return EC;
1912
1915}
1916
1918 const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
1919 uint64_t HeadCount = 0;
1920 if (InlineStack.size() == 0)
1921 if (!GcovBuffer.readInt64(HeadCount))
1923
1924 uint32_t NameIdx;
1925 if (!GcovBuffer.readInt(NameIdx))
1927
1928 StringRef Name(Names[NameIdx]);
1929
1930 uint32_t NumPosCounts;
1931 if (!GcovBuffer.readInt(NumPosCounts))
1933
1934 uint32_t NumCallsites;
1935 if (!GcovBuffer.readInt(NumCallsites))
1937
1938 FunctionSamples *FProfile = nullptr;
1939 if (InlineStack.size() == 0) {
1940 // If this is a top function that we have already processed, do not
1941 // update its profile again. This happens in the presence of
1942 // function aliases. Since these aliases share the same function
1943 // body, there will be identical replicated profiles for the
1944 // original function. In this case, we simply not bother updating
1945 // the profile of the original function.
1946 FProfile = &Profiles[FunctionId(Name)];
1947 FProfile->addHeadSamples(HeadCount);
1948 if (FProfile->getTotalSamples() > 0)
1949 Update = false;
1950 } else {
1951 // Otherwise, we are reading an inlined instance. The top of the
1952 // inline stack contains the profile of the caller. Insert this
1953 // callee in the caller's CallsiteMap.
1954 FunctionSamples *CallerProfile = InlineStack.front();
1955 uint32_t LineOffset = Offset >> 16;
1956 uint32_t Discriminator = Offset & 0xffff;
1957 FProfile = &CallerProfile->functionSamplesAt(
1958 LineLocation(LineOffset, Discriminator))[FunctionId(Name)];
1959 }
1960 FProfile->setFunction(FunctionId(Name));
1961
1962 for (uint32_t I = 0; I < NumPosCounts; ++I) {
1964 if (!GcovBuffer.readInt(Offset))
1966
1967 uint32_t NumTargets;
1968 if (!GcovBuffer.readInt(NumTargets))
1970
1972 if (!GcovBuffer.readInt64(Count))
1974
1975 // The line location is encoded in the offset as:
1976 // high 16 bits: line offset to the start of the function.
1977 // low 16 bits: discriminator.
1978 uint32_t LineOffset = Offset >> 16;
1979 uint32_t Discriminator = Offset & 0xffff;
1980
1981 InlineCallStack NewStack;
1982 NewStack.push_back(FProfile);
1983 llvm::append_range(NewStack, InlineStack);
1984 if (Update) {
1985 // Walk up the inline stack, adding the samples on this line to
1986 // the total sample count of the callers in the chain.
1987 for (auto *CallerProfile : NewStack)
1988 CallerProfile->addTotalSamples(Count);
1989
1990 // Update the body samples for the current profile.
1991 FProfile->addBodySamples(LineOffset, Discriminator, Count);
1992 }
1993
1994 // Process the list of functions called at an indirect call site.
1995 // These are all the targets that a function pointer (or virtual
1996 // function) resolved at runtime.
1997 for (uint32_t J = 0; J < NumTargets; J++) {
1998 uint32_t HistVal;
1999 if (!GcovBuffer.readInt(HistVal))
2001
2002 if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
2004
2005 uint64_t TargetIdx;
2006 if (!GcovBuffer.readInt64(TargetIdx))
2008 StringRef TargetName(Names[TargetIdx]);
2009
2010 uint64_t TargetCount;
2011 if (!GcovBuffer.readInt64(TargetCount))
2013
2014 if (Update)
2015 FProfile->addCalledTargetSamples(LineOffset, Discriminator,
2016 FunctionId(TargetName), TargetCount);
2017 }
2018 }
2019
2020 // Process all the inlined callers into the current function. These
2021 // are all the callsites that were inlined into this function.
2022 for (uint32_t I = 0; I < NumCallsites; I++) {
2023 // The offset is encoded as:
2024 // high 16 bits: line offset to the start of the function.
2025 // low 16 bits: discriminator.
2027 if (!GcovBuffer.readInt(Offset))
2029 InlineCallStack NewStack;
2030 NewStack.push_back(FProfile);
2031 llvm::append_range(NewStack, InlineStack);
2032 if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
2033 return EC;
2034 }
2035
2037}
2038
2039/// Read a GCC AutoFDO profile.
2040///
2041/// This format is generated by the Linux Perf conversion tool at
2042/// https://github.com/google/autofdo.
2044 assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator");
2045 // Read the string table.
2046 if (std::error_code EC = readNameTable())
2047 return EC;
2048
2049 // Read the source profile.
2050 if (std::error_code EC = readFunctionProfiles())
2051 return EC;
2052
2054}
2055
2057 StringRef Magic(Buffer.getBufferStart());
2058 return Magic == "adcg*704";
2059}
2060
2062 // If the reader uses MD5 to represent string, we can't remap it because
2063 // we don't know what the original function names were.
2064 if (Reader.useMD5()) {
2065 Ctx.diagnose(DiagnosticInfoSampleProfile(
2066 Reader.getBuffer()->getBufferIdentifier(),
2067 "Profile data remapping cannot be applied to profile data "
2068 "using MD5 names (original mangled names are not available).",
2069 DS_Warning));
2070 return;
2071 }
2072
2073 // CSSPGO-TODO: Remapper is not yet supported.
2074 // We will need to remap the entire context string.
2075 assert(Remappings && "should be initialized while creating remapper");
2076 for (auto &Sample : Reader.getProfiles()) {
2077 DenseSet<FunctionId> NamesInSample;
2078 Sample.second.findAllNames(NamesInSample);
2079 for (auto &Name : NamesInSample) {
2080 StringRef NameStr = Name.stringRef();
2081 if (auto Key = Remappings->insert(NameStr))
2082 NameMap.insert({Key, NameStr});
2083 }
2084 }
2085
2086 RemappingApplied = true;
2087}
2088
2089std::optional<StringRef>
2091 if (auto Key = Remappings->lookup(Fname)) {
2092 StringRef Result = NameMap.lookup(Key);
2093 if (!Result.empty())
2094 return Result;
2095 }
2096 return std::nullopt;
2097}
2098
2099/// Prepare a memory buffer for the contents of \p Filename.
2100///
2101/// \returns an error code indicating the status of the buffer.
2104 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
2105 : FS.getBufferForFile(Filename);
2106 if (std::error_code EC = BufferOrErr.getError())
2107 return EC;
2108 auto Buffer = std::move(BufferOrErr.get());
2109
2110 return std::move(Buffer);
2111}
2112
2113/// Create a sample profile reader based on the format of the input file.
2114///
2115/// \param Filename The file to open.
2116///
2117/// \param C The LLVM context to use to emit diagnostics.
2118///
2119/// \param P The FSDiscriminatorPass.
2120///
2121/// \param RemapFilename The file used for profile remapping.
2122///
2123/// \returns an error code indicating the status of the created reader.
2124ErrorOr<std::unique_ptr<SampleProfileReader>>
2127 StringRef RemapFilename) {
2128 auto BufferOrError = setupMemoryBuffer(Filename, FS);
2129 if (std::error_code EC = BufferOrError.getError())
2130 return EC;
2131 return create(BufferOrError.get(), C, FS, P, RemapFilename);
2132}
2133
2134/// Create a sample profile remapper from the given input, to remap the
2135/// function names in the given profile data.
2136///
2137/// \param Filename The file to open.
2138///
2139/// \param Reader The profile reader the remapper is going to be applied to.
2140///
2141/// \param C The LLVM context to use to emit diagnostics.
2142///
2143/// \returns an error code indicating the status of the created reader.
2146 vfs::FileSystem &FS,
2147 SampleProfileReader &Reader,
2148 LLVMContext &C) {
2149 auto BufferOrError = setupMemoryBuffer(Filename, FS);
2150 if (std::error_code EC = BufferOrError.getError())
2151 return EC;
2152 return create(BufferOrError.get(), Reader, C);
2153}
2154
2155/// Create a sample profile remapper from the given input, to remap the
2156/// function names in the given profile data.
2157///
2158/// \param B The memory buffer to create the reader from (assumes ownership).
2159///
2160/// \param C The LLVM context to use to emit diagnostics.
2161///
2162/// \param Reader The profile reader the remapper is going to be applied to.
2163///
2164/// \returns an error code indicating the status of the created reader.
2166SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B,
2167 SampleProfileReader &Reader,
2168 LLVMContext &C) {
2169 auto Remappings = std::make_unique<SymbolRemappingReader>();
2170 if (Error E = Remappings->read(*B)) {
2172 std::move(E), [&](const SymbolRemappingParseError &ParseError) {
2173 C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(),
2174 ParseError.getLineNum(),
2175 ParseError.getMessage()));
2176 });
2178 }
2179
2180 return std::make_unique<SampleProfileReaderItaniumRemapper>(
2181 std::move(B), std::move(Remappings), Reader);
2182}
2183
2184/// Create a sample profile reader based on the format of the input data.
2185///
2186/// \param B The memory buffer to create the reader from (assumes ownership).
2187///
2188/// \param C The LLVM context to use to emit diagnostics.
2189///
2190/// \param P The FSDiscriminatorPass.
2191///
2192/// \param RemapFilename The file used for profile remapping.
2193///
2194/// \returns an error code indicating the status of the created reader.
2196SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
2198 StringRef RemapFilename) {
2199 std::unique_ptr<SampleProfileReader> Reader;
2201 Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
2203 Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
2205 Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
2207 Reader.reset(new SampleProfileReaderText(std::move(B), C));
2208 else
2210
2211 if (!RemapFilename.empty()) {
2213 RemapFilename, FS, *Reader, C);
2214 if (std::error_code EC = ReaderOrErr.getError()) {
2215 std::string Msg = "Could not create remapper: " + EC.message();
2216 C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg));
2217 return EC;
2218 }
2219 Reader->Remapper = std::move(ReaderOrErr.get());
2220 }
2221
2222 if (std::error_code EC = Reader->readHeader()) {
2223 return EC;
2224 }
2225
2226 Reader->setDiscriminatorMaskedBitFrom(P);
2227
2228 return std::move(Reader);
2229}
2230
2231// For text and GCC file formats, we compute the summary after reading the
2232// profile. Binary format has the profile summary in its header.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseMap class.
Provides ErrorOr<T> smart pointer.
Module.h This file contains the declarations for the Module class.
This file supports working with JSON data.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
static constexpr StringLiteral Filename
#define P(N)
const char * Msg
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, DenseMap< StringRef, uint64_t > &TypeCountMap, uint64_t &FunctionHash, uint32_t &Attributes, bool &IsFlat)
Parse Input as line sample.
static cl::opt< bool > LazyLoadNameTable("sample-profile-lazy-load-name-table", cl::init(true), cl::Hidden, cl::desc("Lazy load the name table from the profile."))
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 parseTypeCountMap(StringRef Input, DenseMap< StringRef, uint64_t > &TypeCountMap)
static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash, uint32_t &Attributes)
Parse Input that contains metadata.
Defines the virtual file system interface vfs::FileSystem.
The Input class is used to parse a yaml document into in-memory structs and vectors.
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
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:159
Tagged union holding either a T or a Error.
Definition Error.h:485
Non-owning view of a buffer formatted as a complete binary search tree in Eytzinger (breadth-first) o...
Definition Eytzinger.h:30
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
Definition Globals.cpp:80
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
This interface provides simple read-only access to a block of memory, and provides simple methods for...
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:64
static LLVM_ABI const ArrayRef< uint32_t > DefaultCutoffs
A vector of useful cutoff values for detailed summary.
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
static constexpr size_t npos
Definition StringRef.h:58
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition StringRef.h:490
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition StringRef.h:597
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
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:421
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:396
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition StringRef.h:290
LLVM_ABI 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.
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
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:187
json::OStream allows writing well-formed JSON without materializing all structures as json::Value ahe...
Definition JSON.h:983
void object(Block Contents)
Emit an object whose elements are emitted in the provided Block.
Definition JSON.h:1013
void attribute(llvm::StringRef Key, const Value &Contents)
Emit an attribute whose value is self-contained (number, vector<int> etc).
Definition JSON.h:1038
LLVM_ABI void arrayBegin()
Definition JSON.cpp:845
void attributeArray(llvm::StringRef Key, Block Contents)
Emit an attribute whose value is an array with elements from the Block.
Definition JSON.h:1042
LLVM_ABI void arrayEnd()
Definition JSON.cpp:853
A forward iterator which reads text lines from a buffer.
int64_t line_number() const
Return the current line number. May return any number at EOF.
bool is_at_eof() const
Return true if we've reached EOF or are an "end" iterator.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
This class represents a function that is read from a sample profile.
Definition FunctionId.h:36
StringRef stringRef() const
Convert to StringRef.
Definition FunctionId.h:108
uint64_t getHashCode() const
Get hash code of this object.
Definition FunctionId.h:123
std::string str() const
Convert to a string, usually for output purpose.
Definition FunctionId.h:97
Representation of the samples collected for a function.
Definition SampleProf.h:816
static LLVM_ABI std::atomic< bool > ProfileIsFS
If this profile uses flow sensitive discriminators.
static LLVM_ABI std::atomic< bool > ProfileIsPreInlined
sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight=1)
Definition SampleProf.h:823
uint64_t getHeadSamples() const
For top-level functions, return the total number of branch samples that have the function as the bran...
void setFunction(FunctionId NewFunctionID)
Set the name of the function.
FunctionId getFunction() const
Return the function name.
sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight=1)
Definition SampleProf.h:842
sampleprof_error addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator, FunctionId Func, uint64_t Num, uint64_t Weight=1)
Definition SampleProf.h:856
FunctionSamplesMap & functionSamplesAt(const LineLocation &Loc)
Return the function samples at the given callsite location.
Definition SampleProf.h:985
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator, uint64_t Num, uint64_t Weight=1)
Definition SampleProf.h:850
static LLVM_ABI std::atomic< bool > HasUniqSuffix
Whether the profile contains any ".__uniq." suffix in a name.
void setFunctionHash(uint64_t Hash)
static LLVM_ABI std::atomic< bool > ProfileIsProbeBased
SampleContext & getContext() const
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
const CallsiteSampleMap & getCallsiteSamples() const
Return all the callsite samples collected in the body of the function.
void setContext(const SampleContext &FContext)
static LLVM_ABI std::atomic< bool > ProfileIsCS
TypeCountMap & getTypeSamplesAt(const LineLocation &Loc)
Returns the vtable access samples for the C++ types for Loc.
const BodySampleMap & getBodySamples() const
Return all the samples collected in the body of the function.
void setAllAttributes(uint32_t A)
Definition SampleProf.h:682
FunctionId getFunction() const
Definition SampleProf.h:688
bool isPrefixOf(const SampleContext &That) const
Definition SampleProf.h:767
This class provides operator overloads to the map container using MD5 as the key type,...
iterator find(const SampleContext &Ctx)
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.
ErrorOr< StringRef > readString()
Read a string from the profile.
std::unique_ptr< SampleProfileNameTable > NameTable
Function name table.
ErrorOr< T > readNumber()
Read a numeric value of type T from the profile.
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.
std::error_code readImpl() override
Read sample profiles from the associated file.
ErrorOr< FunctionId > readStringFromTable(size_t *RetIdx=nullptr)
Read a string indirectly via the name table. Optionally return the index.
std::vector< uint64_t > MD5SampleContextTable
Table to cache MD5 values of sample contexts corresponding to readSampleContextFromTable(),...
std::error_code readCallsiteVTableProf(FunctionSamples &FProfile)
Read all virtual functions' vtable access counts for FProfile.
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 readVTableTypeCountMap(TypeCountMap &M)
Read bytes from the input buffer pointed by Data and decode them into M.
std::error_code readSummary()
Read profile summary.
std::error_code readMagicIdent()
Read the contents of Magic number and Version number.
std::error_code readNameTableSecEytzinger(bool IsMD5, bool FixedLengthMD5)
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
std::optional< SampleProfileFuncOffsetTable > FuncOffsetTable
The table mapping from a function context's MD5 to the offset of its FunctionSample towards file star...
std::error_code readNameTableSec(bool IsMD5, bool FixedLengthMD5, bool IsEytzinger=false)
bool useFuncOffsetList() const
Determine which container readFuncOffsetTable() should populate, the list FuncOffsetList or the map F...
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
std::error_code readNameTableSecLegacy(bool IsMD5, bool FixedLengthMD5)
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 LLVM_ABI ErrorOr< std::unique_ptr< SampleProfileReaderItaniumRemapper > > create(StringRef Filename, vfs::FileSystem &FS, SampleProfileReader &Reader, LLVMContext &C)
Create a remapper from the given remapping file.
LLVM_ABI void applyRemapping(LLVMContext &Ctx)
Apply remappings to the profile read by Reader.
LLVM_ABI 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.
std::pair< const uint8_t *, const uint8_t * > ProfileSecRange
bool ReadVTableProf
If true, the profile has vtable profiles and reader should decode them to parse profiles correctly.
bool ProfileIsPreInlined
Whether function profile contains ShouldBeInlined contexts.
DenseMap< uint64_t, std::pair< const uint8_t *, const uint8_t * > > FuncMetadataIndex
uint32_t CSProfileCount
Number of context-sensitive profiles.
static LLVM_ABI ErrorOr< std::unique_ptr< SampleProfileReader > > create(StringRef Filename, LLVMContext &C, vfs::FileSystem &FS, FSDiscriminatorPass P=FSDiscriminatorPass::Base, StringRef RemapFilename="")
Create a sample profile reader appropriate to the file format.
LLVM_ABI 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 ProfileHasAttribute
Whether the profile has attribute metadata.
bool SkipFlatProf
If SkipFlatProf is true, skip functions marked with !Flat in text mode or sections with SecFlagFlat f...
std::error_code read()
The interface to read sample profiles from the associated file.
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.
LLVM_ABI 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.
LLVM_ABI void dumpJson(raw_ostream &OS=dbgs())
Print all the profiles on stream OS in the JSON format.
SampleProfileMap Profiles
Map every function to its associated profile.
uint64_t FormatVersion
Format version of the profile.
LLVM_ABI 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.
LLVMContext & Ctx
LLVM context used to emit diagnostics.
Representation of a single sample record.
Definition SampleProf.h:390
SortedCallTargetSet getSortedCallTargets() const
Definition SampleProf.h:459
The virtual file system interface.
GCOVVersion
Definition GCOV.h:43
@ V407
Definition GCOV.h:43
initializer< Ty > init(const Ty &Val)
LLVM_ABI Error decompress(ArrayRef< uint8_t > Input, uint8_t *Output, size_t &UncompressedSize)
LLVM_ABI bool isAvailable()
LLVM_ABI void sortFuncProfiles(const SampleProfileMap &ProfileMap, std::vector< NameFunctionSamples > &SortedProfiles)
static uint64_t SPMagic(SampleProfileFormat Format=SPF_Binary)
Definition SampleProf.h:113
static bool formatVersionIsSupported(uint64_t Version)
Definition SampleProf.h:131
std::map< LineLocation, FunctionSamplesMap > CallsiteSampleMap
Definition SampleProf.h:807
static bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:303
uint64_t MD5Hash(const FunctionId &Obj)
Definition FunctionId.h:167
@ SecFlagIsPreInlined
SecFlagIsPreInlined means this profile contains ShouldBeInlined contexts thus this is CS preinliner c...
Definition SampleProf.h:236
@ SecFlagHasVTableTypeProf
SecFlagHasVTableTypeProf means this profile contains vtable type profiles.
Definition SampleProf.h:239
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
Definition SampleProf.h:227
@ SecFlagFSDiscriminator
SecFlagFSDiscriminator means this profile uses flow-sensitive discriminators.
Definition SampleProf.h:233
@ SecFlagFullContext
SecFlagContext means this is context-sensitive flat profile for CSSPGO.
Definition SampleProf.h:230
SmallVector< SampleContextFrame, 1 > SampleContextFrameVector
Definition SampleProf.h:576
std::map< FunctionId, uint64_t > TypeCountMap
Key represents type of a C++ polymorphic class type by its vtable and value represents its counter.
Definition SampleProf.h:370
static std::string getSecName(SecType Type)
Definition SampleProf.h:155
constexpr InMemoryModeT InMemoryMode
constexpr char kVTableProfPrefix[]
Definition SampleProf.h:96
SmallVector< FunctionSamples *, 10 > InlineCallStack
std::map< LineLocation, SampleRecord > BodySampleMap
Definition SampleProf.h:803
uint64_t read64le(const void *P)
Definition Endian.h:435
void write64le(void *P, uint64_t V)
Definition Endian.h:478
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition Endian.h:60
value_type readNext(const CharT *&memory, endianness endian)
Read a value of a particular endianness from a buffer, and increment the buffer past that value.
Definition Endian.h:81
detail::packed_endian_specific_integral< uint64_t, llvm::endianness::little, unaligned > ulittle64_t
Definition Endian.h:293
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
static Expected< std::unique_ptr< MemoryBuffer > > setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS)
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:1013
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:130
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
sampleprof_error mergeSampleProfErrors(sampleprof_error &Accumulator, sampleprof_error Result)
Definition SampleProf.h:74
sampleprof_error
Definition SampleProf.h:51
bool isDigit(char C)
Checks if character C is one of the 10 decimal digits.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
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:2012
ArrayRef(const T &OneElt) -> ArrayRef< T >
Represents the relative location of an instruction.
Definition SampleProf.h:319