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 {
898 bool IsEytzinger =
900 bool IsFlat = hasSecFlag(Entry, SecCommonFlags::SecFlagFlat);
901 // An unflagged function offset table inherently indexes the primary
902 // context-sensitive symbol span.
903 bool IsCS = !IsFlat;
906 IsEytzinger) &&
907 "func offset table should always be sorted or in Eytzinger BFS "
908 "order in CS profile");
909 if (std::error_code EC = readFuncOffsetTable(IsEytzinger, IsCS))
910 return EC;
911 }
912 break;
913 case SecFuncMetadata: {
919 if (std::error_code EC = readFuncMetadata())
920 return EC;
921 break;
922 }
924 if (std::error_code EC = readProfileSymbolList(
926 return EC;
927 break;
928 default:
929 if (std::error_code EC = readCustomSection(Entry))
930 return EC;
931 break;
932 }
934}
935
937 // If profile is CS, the function offset section is expected to consist of
938 // sequences of contexts in pre-order layout
939 // (e.g. [A, A:1 @ B, A:1 @ B:2.3 @ C] [D, D:1 @ E]), so that when a matched
940 // context in the module is found, the profiles of all its callees are
941 // recursively loaded. A list is needed since the order of profiles matters.
942 if (ProfileIsCS)
943 return true;
944
945 // If the profile is MD5, use the map container to lookup functions in
946 // the module. A remapper has no use on MD5 names.
947 if (useMD5())
948 return false;
949
950 // Profile is not MD5 and if a remapper is present, the remapped name of
951 // every function needed to be matched against the module, so use the list
952 // container since each entry is accessed.
953 if (Remapper)
954 return true;
955
956 // Otherwise use the map container for faster lookup.
957 // TODO: If the cardinality of the function offset section is much smaller
958 // than the number of functions in the module, using the list container can
959 // be always faster, but we need to figure out the constant factor to
960 // determine the cutoff.
961 return false;
962}
963
964std::error_code
966 SampleProfileMap &Profiles) {
967 if (FuncsToUse.empty())
969
970 Data = ProfileSecRange.first;
971 End = ProfileSecRange.second;
972 if (std::error_code EC = readFuncProfiles(FuncsToUse, Profiles))
973 return EC;
974 End = Data;
975 DenseSet<FunctionSamples *> ProfilesToReadMetadata;
976 for (auto FName : FuncsToUse) {
977 auto I = Profiles.find(FName);
978 if (I != Profiles.end())
979 ProfilesToReadMetadata.insert(&I->second);
980 }
981
982 if (std::error_code EC = readFuncMetadata(ProfilesToReadMetadata))
983 return EC;
985}
986
988 if (!M)
989 return false;
990 FuncsToUse.clear();
991 for (auto &F : *M)
993 return true;
994}
995
996std::error_code
998 bool IsCS) {
999 if (IsEytzinger)
1000 return readEytzingerFuncOffsetTable(IsCS);
1002}
1003
1004std::error_code
1006 // If there are more than one function offset section, the profile associated
1007 // with the previous section has to be done reading before next one is read.
1008 FuncOffsetTable.reset();
1009
1010 size_t Size = End - Data;
1011 size_t SpanSize = NameTable->getEytzingerSpan(IsCS).size();
1012 if (Size != SpanSize * sizeof(uint32_t))
1014
1015 auto *Array = reinterpret_cast<const support::ulittle32_t *>(Data);
1016 ArrayRef<support::ulittle32_t> Offsets(Array, SpanSize);
1017
1018 FuncOffsetTable.emplace(EytzingerMode, NameTable->getEytzingerSpan(IsCS),
1019 Offsets);
1020
1021 Data = End;
1023}
1024
1026 // If there are more than one function offset section, the profile associated
1027 // with the previous section has to be done reading before next one is read.
1028 FuncOffsetTable.reset();
1029 FuncOffsetList.clear();
1030
1031 auto Size = readNumber<uint64_t>();
1032 if (std::error_code EC = Size.getError())
1033 return EC;
1034
1035 bool UseFuncOffsetList = useFuncOffsetList();
1036 if (UseFuncOffsetList)
1037 FuncOffsetList.reserve(*Size);
1038 else
1040
1041 for (uint64_t I = 0; I < *Size; ++I) {
1042 auto FContextHash(readSampleContextFromTable());
1043 if (std::error_code EC = FContextHash.getError())
1044 return EC;
1045
1046 auto &[FContext, Hash] = *FContextHash;
1048 if (std::error_code EC = Offset.getError())
1049 return EC;
1050
1051 if (UseFuncOffsetList)
1052 FuncOffsetList.emplace_back(FContext, *Offset);
1053 else
1054 // Because Porfiles replace existing value with new value if collision
1055 // happens, we also use the latest offset so that they are consistent.
1056 FuncOffsetTable->insert(Hash, *Offset);
1057 }
1058
1060}
1061
1064 const uint8_t *Start = Data;
1065
1066 if (Remapper) {
1067 for (auto Name : FuncsToUse) {
1068 Remapper->insert(Name);
1069 }
1070 }
1071
1072 if (FuncOffsetTable && FuncOffsetTable->isEytzinger() &&
1074 ArrayRef<support::ulittle32_t> Offsets = FuncOffsetTable->getFuncOffsets();
1075 if (Offsets.size() != FuncOffsetTable->getExpectedSize())
1077 for (const auto &[LocalIdx, RelOffset] : llvm::enumerate(Offsets)) {
1078 if (RelOffset == UINT32_MAX)
1079 continue;
1080 const uint8_t *FuncProfileAddr = Start + RelOffset;
1081 if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
1082 return EC;
1083 }
1085 }
1086
1087 if (ProfileIsCS) {
1089 DenseSet<uint64_t> FuncGuidsToUse;
1090 if (useMD5()) {
1091 for (auto Name : FuncsToUse)
1093 }
1094
1095 // For each function in current module, load all context profiles for
1096 // the function as well as their callee contexts which can help profile
1097 // guided importing for ThinLTO. This can be achieved by walking
1098 // through an ordered context container, where contexts are laid out
1099 // as if they were walked in preorder of a context trie. While
1100 // traversing the trie, a link to the highest common ancestor node is
1101 // kept so that all of its decendants will be loaded.
1102 const SampleContext *CommonContext = nullptr;
1103 for (const auto &NameOffset : FuncOffsetList) {
1104 const auto &FContext = NameOffset.first;
1105 FunctionId FName = FContext.getFunction();
1106 StringRef FNameString;
1107 if (!useMD5())
1108 FNameString = FName.stringRef();
1109
1110 // For function in the current module, keep its farthest ancestor
1111 // context. This can be used to load itself and its child and
1112 // sibling contexts.
1113 if ((useMD5() && FuncGuidsToUse.count(FName.getHashCode())) ||
1114 (!useMD5() && (FuncsToUse.count(FNameString) ||
1115 (Remapper && Remapper->exist(FNameString))))) {
1116 if (!CommonContext || !CommonContext->isPrefixOf(FContext))
1117 CommonContext = &FContext;
1118 }
1119
1120 if (CommonContext == &FContext ||
1121 (CommonContext && CommonContext->isPrefixOf(FContext))) {
1122 // Load profile for the current context which originated from
1123 // the common ancestor.
1124 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
1125 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
1126 return EC;
1127 }
1128 }
1129 } else if (useMD5()) {
1131 for (auto Name : FuncsToUse) {
1132 auto GUID = MD5Hash(Name);
1133 if (auto Offset = FuncOffsetTable->lookup(GUID)) {
1134 const uint8_t *FuncProfileAddr = Start + *Offset;
1135 if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
1136 return EC;
1137 }
1138 }
1139 } else if (Remapper) {
1141 for (auto NameOffset : FuncOffsetList) {
1142 SampleContext FContext(NameOffset.first);
1143 auto FuncName = FContext.getFunction();
1144 StringRef FuncNameStr = FuncName.stringRef();
1145 if (!FuncsToUse.count(FuncNameStr) && !Remapper->exist(FuncNameStr))
1146 continue;
1147 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
1148 if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
1149 return EC;
1150 }
1151 } else {
1153 for (auto Name : FuncsToUse) {
1154 if (auto Offset = FuncOffsetTable->lookup(MD5Hash(Name))) {
1155 const uint8_t *FuncProfileAddr = Start + *Offset;
1156 if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
1157 return EC;
1158 }
1159 }
1160 }
1161
1163}
1164
1166 // Collect functions used by current module if the Reader has been
1167 // given a module.
1168 // collectFuncsFromModule uses FunctionSamples::getCanonicalFnName
1169 // which will query FunctionSamples::HasUniqSuffix, so it has to be
1170 // called after FunctionSamples::HasUniqSuffix is set, i.e. after
1171 // NameTable section is read.
1172 bool LoadFuncsToBeUsed = collectFuncsFromModule();
1173
1174 // When LoadFuncsToBeUsed is false, we are using LLVM tool, need to read all
1175 // profiles.
1176 if (!LoadFuncsToBeUsed) {
1177 while (Data < End) {
1178 if (std::error_code EC = readFuncProfile(Data))
1179 return EC;
1180 }
1181 assert(Data == End && "More data is read than expected");
1182 } else {
1183 // Load function profiles on demand.
1184 if (std::error_code EC = readFuncProfiles(FuncsToUse, Profiles))
1185 return EC;
1186 Data = End;
1187 }
1188 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
1189 "Cannot have both context-sensitive and regular profile");
1191 "Section flag should be consistent with actual profile");
1193}
1194
1195std::error_code
1201
1203 size_t Size = End - Data;
1204 if (Size % sizeof(uint64_t) != 0)
1206 const auto *Table = reinterpret_cast<const support::ulittle64_t *>(Data);
1207 size_t NumEntries = Size / sizeof(uint64_t);
1208 if (!ProfSymList)
1209 ProfSymList = std::make_unique<ProfileSymbolList>();
1210 ProfSymList->setColdGUIDTable(
1212 Data = End;
1214}
1215
1216std::error_code
1218 if (!ProfSymList)
1219 ProfSymList = std::make_unique<ProfileSymbolList>();
1220
1221 if (std::error_code EC = ProfSymList->read(Data, End - Data))
1222 return EC;
1223
1224 Data = End;
1226}
1227
1228std::error_code SampleProfileReaderExtBinaryBase::decompressSection(
1229 const uint8_t *SecStart, const uint64_t SecSize,
1230 const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) {
1231 Data = SecStart;
1232 End = SecStart + SecSize;
1233 auto DecompressSize = readNumber<uint64_t>();
1234 if (std::error_code EC = DecompressSize.getError())
1235 return EC;
1236 DecompressBufSize = *DecompressSize;
1237
1238 auto CompressSize = readNumber<uint64_t>();
1239 if (std::error_code EC = CompressSize.getError())
1240 return EC;
1241
1244
1245 uint8_t *Buffer = Allocator.Allocate<uint8_t>(DecompressBufSize);
1246 size_t UCSize = DecompressBufSize;
1248 Buffer, UCSize);
1249 if (E)
1251 DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer);
1253}
1254
1256 const uint8_t *BufStart =
1257 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1258
1259 for (auto &Entry : SecHdrTable) {
1260 // Skip empty section.
1261 if (!Entry.Size)
1262 continue;
1263
1264 // Skip sections without inlined functions when SkipFlatProf is true.
1266 continue;
1267
1268 const uint8_t *SecStart = BufStart + Entry.Offset;
1269 uint64_t SecSize = Entry.Size;
1270
1271 // If the section is compressed, decompress it into a buffer
1272 // DecompressBuf before reading the actual data. The pointee of
1273 // 'Data' will be changed to buffer hold by DecompressBuf
1274 // temporarily when reading the actual data.
1275 bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress);
1276 if (isCompressed) {
1277 const uint8_t *DecompressBuf;
1278 uint64_t DecompressBufSize;
1279 if (std::error_code EC = decompressSection(
1280 SecStart, SecSize, DecompressBuf, DecompressBufSize))
1281 return EC;
1282 SecStart = DecompressBuf;
1283 SecSize = DecompressBufSize;
1284 }
1285
1286 if (std::error_code EC = readOneSection(SecStart, SecSize, Entry))
1287 return EC;
1288 if (Data != SecStart + SecSize)
1290
1291 // Change the pointee of 'Data' from DecompressBuf to original Buffer.
1292 if (isCompressed) {
1293 Data = BufStart + Entry.Offset;
1294 End = BufStart + Buffer->getBufferSize();
1295 }
1296 }
1297
1299}
1300
1301std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
1302 if (Magic == SPMagic())
1305}
1306
1307std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
1308 if (Magic == SPMagic(SPF_Ext_Binary))
1311}
1312
1314 auto Size = readNumber<size_t>();
1315 if (std::error_code EC = Size.getError())
1316 return EC;
1317
1318 // Normally if useMD5 is true, the name table should have MD5 values, not
1319 // strings, however in the case that ExtBinary profile has multiple name
1320 // tables mixing string and MD5, all of them have to be normalized to use MD5,
1321 // because optimization passes can only handle either type.
1322 bool UseMD5 = useMD5();
1323
1324 std::vector<FunctionId> TableVec;
1325 TableVec.reserve(*Size);
1326 if (!ProfileIsCS) {
1327 MD5SampleContextTable.clear();
1328 if (UseMD5)
1329 MD5SampleContextTable.reserve(*Size);
1330 else
1331 // If we are using strings, delay MD5 computation since only a portion of
1332 // names are used by top level functions. Use 0 to indicate MD5 value is
1333 // to be calculated as no known string has a MD5 value of 0.
1334 MD5SampleContextTable.resize(*Size);
1335 }
1336 for (size_t I = 0; I < *Size; ++I) {
1337 auto Name(readString());
1338 if (std::error_code EC = Name.getError())
1339 return EC;
1340 if (UseMD5) {
1341 FunctionId FID(*Name);
1342 if (!ProfileIsCS)
1343 MD5SampleContextTable.emplace_back(FID.getHashCode());
1344 TableVec.emplace_back(FID);
1345 } else
1346 TableVec.push_back(FunctionId(*Name));
1347 }
1348 if (!ProfileIsCS)
1350 if (UseMD5)
1351 NameTable =
1352 std::make_unique<MD5SampleProfileNameTable>(std::move(TableVec));
1353 else
1354 NameTable =
1355 std::make_unique<StringSampleProfileNameTable>(std::move(TableVec));
1357}
1358
1360 bool IsMD5, bool FixedLengthMD5, bool IsEytzinger) {
1361 if (IsEytzinger)
1362 return readNameTableSecEytzinger(IsMD5, FixedLengthMD5);
1363 return readNameTableSecLegacy(IsMD5, FixedLengthMD5);
1364}
1365
1366// Read the Eytzinger layout for SecNameTable from an ExtBinary MD5 profile.
1367//
1368// The section consists of three sequential ULEB128 symbol counts (CS, Flat, and
1369// Inlinees) followed by their corresponding arrays of 64-bit MD5 hash keys laid
1370// out in Eytzinger order.
1372 bool IsMD5, bool FixedLengthMD5) {
1373 assert(IsMD5 && "Eytzinger name tables require MD5 representation");
1374 if (!IsMD5)
1376
1377 // Read the table sizes for CS, flat, and inlinee symbols.
1378 std::array<uint64_t, static_cast<size_t>(EytzingerSpan::NumSpans)> Counts;
1379 for (uint64_t &Count : Counts) {
1380 auto ValOrErr = readNumber<uint64_t>();
1381 if (std::error_code EC = ValOrErr.getError())
1382 return EC;
1383 Count = *ValOrErr;
1384 }
1385 auto [NumCS, NumFlat, NumInlinees] = Counts;
1386
1387 // Guard against unsigned overflow in total entry computation.
1388 if (NumCS > std::numeric_limits<uint32_t>::max() ||
1389 NumFlat > std::numeric_limits<uint32_t>::max() ||
1390 NumInlinees > std::numeric_limits<uint32_t>::max())
1392
1393 uint64_t TotalEntries = NumCS + NumFlat + NumInlinees;
1394 if (static_cast<size_t>(End - Data) < TotalEntries * sizeof(uint64_t))
1396
1397 NameTable = std::make_unique<EytzingerSampleProfileNameTable>(
1398 reinterpret_cast<const support::ulittle64_t *>(Data), NumCS, NumFlat,
1399 NumInlinees);
1400
1401 if (!ProfileIsCS)
1402 MD5SampleContextStart = reinterpret_cast<const uint64_t *>(Data);
1403 Data = Data + TotalEntries * sizeof(uint64_t);
1405}
1406
1407std::error_code
1409 bool FixedLengthMD5) {
1410 if (FixedLengthMD5) {
1411 if (!IsMD5)
1412 errs() << "If FixedLengthMD5 is true, UseMD5 has to be true";
1413 auto Size = readNumber<size_t>();
1414 if (std::error_code EC = Size.getError())
1415 return EC;
1416
1417 assert(Data + (*Size) * sizeof(uint64_t) == End &&
1418 "Fixed length MD5 name table does not contain specified number of "
1419 "entries");
1420 if (Data + (*Size) * sizeof(uint64_t) > End)
1422
1423 if (LazyLoadNameTable) {
1424 NameTable = std::make_unique<LazySampleProfileNameTable>(Data, *Size);
1425 } else {
1426 std::vector<FunctionId> TableVec;
1427 TableVec.reserve(*Size);
1428 for (size_t I = 0; I < *Size; ++I) {
1429 using namespace support;
1431 Data + I * sizeof(uint64_t), endianness::little);
1432 TableVec.emplace_back(FunctionId(FID));
1433 }
1434 NameTable =
1435 std::make_unique<MD5SampleProfileNameTable>(std::move(TableVec));
1436 }
1437 if (!ProfileIsCS)
1438 MD5SampleContextStart = reinterpret_cast<const uint64_t *>(Data);
1439 Data = Data + (*Size) * sizeof(uint64_t);
1441 }
1442
1443 if (IsMD5) {
1444 assert(!FixedLengthMD5 && "FixedLengthMD5 should be unreachable here");
1445 auto Size = readNumber<size_t>();
1446 if (std::error_code EC = Size.getError())
1447 return EC;
1448
1449 std::vector<FunctionId> TableVec;
1450 TableVec.reserve(*Size);
1451 if (!ProfileIsCS)
1452 MD5SampleContextTable.resize(*Size);
1453 for (size_t I = 0; I < *Size; ++I) {
1454 auto FID = readNumber<uint64_t>();
1455 if (std::error_code EC = FID.getError())
1456 return EC;
1457 if (!ProfileIsCS)
1459 TableVec.emplace_back(FunctionId(*FID));
1460 }
1461 if (!ProfileIsCS)
1463 NameTable =
1464 std::make_unique<MD5SampleProfileNameTable>(std::move(TableVec));
1466 }
1467
1469}
1470
1471// Read in the CS name table section, which basically contains a list of context
1472// vectors. Each element of a context vector, aka a frame, refers to the
1473// underlying raw function names that are stored in the name table, as well as
1474// a callsite identifier that only makes sense for non-leaf frames.
1476 auto Size = readNumber<size_t>();
1477 if (std::error_code EC = Size.getError())
1478 return EC;
1479
1480 CSNameTable.clear();
1481 CSNameTable.reserve(*Size);
1482 if (ProfileIsCS) {
1483 // Delay MD5 computation of CS context until they are needed. Use 0 to
1484 // indicate MD5 value is to be calculated as no known string has a MD5
1485 // value of 0.
1486 MD5SampleContextTable.clear();
1487 MD5SampleContextTable.resize(*Size);
1489 }
1490 for (size_t I = 0; I < *Size; ++I) {
1491 CSNameTable.emplace_back(SampleContextFrameVector());
1492 auto ContextSize = readNumber<uint32_t>();
1493 if (std::error_code EC = ContextSize.getError())
1494 return EC;
1495 for (uint32_t J = 0; J < *ContextSize; ++J) {
1496 auto FName(readStringFromTable());
1497 if (std::error_code EC = FName.getError())
1498 return EC;
1499 auto LineOffset = readNumber<uint64_t>();
1500 if (std::error_code EC = LineOffset.getError())
1501 return EC;
1502
1503 if (!isOffsetLegal(*LineOffset))
1505
1506 auto Discriminator = readNumber<uint64_t>();
1507 if (std::error_code EC = Discriminator.getError())
1508 return EC;
1509
1510 CSNameTable.back().emplace_back(
1511 FName.get(), LineLocation(LineOffset.get(), Discriminator.get()));
1512 }
1513 }
1514
1516}
1517
1518std::error_code
1520 if (Data < End) {
1521 if (ProfileIsProbeBased) {
1522 auto Checksum = readNumber<uint64_t>();
1523 if (std::error_code EC = Checksum.getError())
1524 return EC;
1525 if (FProfile)
1526 FProfile->setFunctionHash(*Checksum);
1527 }
1528
1529 if (ProfileHasAttribute) {
1530 auto Attributes = readNumber<uint32_t>();
1531 if (std::error_code EC = Attributes.getError())
1532 return EC;
1533 if (FProfile)
1534 FProfile->getContext().setAllAttributes(*Attributes);
1535 }
1536
1537 if (!ProfileIsCS) {
1538 // Read all the attributes for inlined function calls.
1539 auto NumCallsites = readNumber<uint32_t>();
1540 if (std::error_code EC = NumCallsites.getError())
1541 return EC;
1542
1543 for (uint32_t J = 0; J < *NumCallsites; ++J) {
1544 auto LineOffset = readNumber<uint64_t>();
1545 if (std::error_code EC = LineOffset.getError())
1546 return EC;
1547
1548 auto Discriminator = readNumber<uint64_t>();
1549 if (std::error_code EC = Discriminator.getError())
1550 return EC;
1551
1552 auto FContextHash(readSampleContextFromTable());
1553 if (std::error_code EC = FContextHash.getError())
1554 return EC;
1555
1556 auto &[FContext, Hash] = *FContextHash;
1557 FunctionSamples *CalleeProfile = nullptr;
1558 if (FProfile) {
1559 CalleeProfile = const_cast<FunctionSamples *>(
1561 *LineOffset, *Discriminator))[FContext.getFunction()]);
1562 }
1563 if (std::error_code EC = readFuncMetadata(CalleeProfile))
1564 return EC;
1565 }
1566 }
1567 }
1568
1570}
1571
1574 if (FuncMetadataIndex.empty())
1576
1577 for (auto *FProfile : Profiles) {
1578 auto R = FuncMetadataIndex.find(FProfile->getContext().getHashCode());
1579 if (R == FuncMetadataIndex.end())
1580 continue;
1581
1582 Data = R->second.first;
1583 End = R->second.second;
1584 if (std::error_code EC = readFuncMetadata(FProfile))
1585 return EC;
1586 assert(Data == End && "More data is read than expected");
1587 }
1589}
1590
1592 while (Data < End) {
1593 auto FContextHash(readSampleContextFromTable());
1594 if (std::error_code EC = FContextHash.getError())
1595 return EC;
1596 auto &[FContext, Hash] = *FContextHash;
1597 FunctionSamples *FProfile = nullptr;
1598 auto It = Profiles.find(FContext);
1599 if (It != Profiles.end())
1600 FProfile = &It->second;
1601
1602 const uint8_t *Start = Data;
1603 if (std::error_code EC = readFuncMetadata(FProfile))
1604 return EC;
1605
1606 FuncMetadataIndex[FContext.getHashCode()] = {Start, Data};
1607 }
1608
1609 assert(Data == End && "More data is read than expected");
1611}
1612
1613std::error_code
1615 SecHdrTableEntry Entry;
1617 if (std::error_code EC = Type.getError())
1618 return EC;
1619 Entry.Type = static_cast<SecType>(*Type);
1620
1621 auto Flags = readUnencodedNumber<uint64_t>();
1622 if (std::error_code EC = Flags.getError())
1623 return EC;
1624 Entry.Flags = *Flags;
1625
1627 if (std::error_code EC = Offset.getError())
1628 return EC;
1629 Entry.Offset = *Offset;
1630
1632 if (std::error_code EC = Size.getError())
1633 return EC;
1634 Entry.Size = *Size;
1635
1636 Entry.LayoutIndex = Idx;
1637 SecHdrTable.push_back(std::move(Entry));
1639}
1640
1642 auto EntryNum = readUnencodedNumber<uint64_t>();
1643 if (std::error_code EC = EntryNum.getError())
1644 return EC;
1645
1646 for (uint64_t i = 0; i < (*EntryNum); i++)
1647 if (std::error_code EC = readSecHdrTableEntry(i))
1648 return EC;
1649
1651}
1652
1654 const uint8_t *BufStart =
1655 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1656 Data = BufStart;
1657 End = BufStart + Buffer->getBufferSize();
1658
1659 if (std::error_code EC = readMagicIdent())
1660 return EC;
1661
1662 if (std::error_code EC = readSecHdrTable())
1663 return EC;
1664
1666}
1667
1669 uint64_t Size = 0;
1670 for (auto &Entry : SecHdrTable) {
1671 if (Entry.Type == Type)
1672 Size += Entry.Size;
1673 }
1674 return Size;
1675}
1676
1678 // Sections in SecHdrTable is not necessarily in the same order as
1679 // sections in the profile because section like FuncOffsetTable needs
1680 // to be written after section LBRProfile but needs to be read before
1681 // section LBRProfile, so we cannot simply use the last entry in
1682 // SecHdrTable to calculate the file size.
1683 uint64_t FileSize = 0;
1684 for (auto &Entry : SecHdrTable) {
1685 FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
1686 }
1687 return FileSize;
1688}
1689
1690static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
1691 std::string Flags;
1693 Flags.append("{compressed,");
1694 else
1695 Flags.append("{");
1696
1698 Flags.append("flat,");
1699
1700 switch (Entry.Type) {
1701 case SecNameTable:
1703 Flags.append("eytzinger,");
1705 Flags.append("fixlenmd5,");
1707 Flags.append("md5,");
1709 Flags.append("uniq,");
1710 break;
1711 case SecProfSummary:
1713 Flags.append("partial,");
1715 Flags.append("context,");
1717 Flags.append("preInlined,");
1719 Flags.append("fs-discriminator,");
1720 break;
1721 case SecFuncOffsetTable:
1723 Flags.append("ordered,");
1725 Flags.append("eytzinger,");
1726 break;
1727 case SecFuncMetadata:
1729 Flags.append("probe,");
1731 Flags.append("attr,");
1732 break;
1735 Flags.append("md5,");
1736 break;
1737 default:
1738 break;
1739 }
1740 char &last = Flags.back();
1741 if (last == ',')
1742 last = '}';
1743 else
1744 Flags.append("}");
1745 return Flags;
1746}
1747
1749 uint64_t TotalSecsSize = 0;
1750 for (auto &Entry : SecHdrTable) {
1751 OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset
1752 << ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
1753 << "\n";
1754 ;
1755 TotalSecsSize += Entry.Size;
1756 }
1757 uint64_t HeaderSize = SecHdrTable.front().Offset;
1758 assert(HeaderSize + TotalSecsSize == getFileSize() &&
1759 "Size of 'header + sections' doesn't match the total size of profile");
1760
1761 OS << "Header Size: " << HeaderSize << "\n";
1762 OS << "Total Sections Size: " << TotalSecsSize << "\n";
1763 OS << "File Size: " << getFileSize() << "\n";
1764 return true;
1765}
1766
1768 // Read and check the magic identifier.
1769 auto Magic = readNumber<uint64_t>();
1770 if (std::error_code EC = Magic.getError())
1771 return EC;
1772 else if (std::error_code EC = verifySPMagic(*Magic))
1773 return EC;
1774
1775 // Read the version number.
1777 if (std::error_code EC = Version.getError())
1778 return EC;
1782
1784}
1785
1787 Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1788 End = Data + Buffer->getBufferSize();
1789
1790 if (std::error_code EC = readMagicIdent())
1791 return EC;
1792
1793 if (std::error_code EC = readSummary())
1794 return EC;
1795
1796 if (std::error_code EC = readNameTable())
1797 return EC;
1799}
1800
1801std::error_code SampleProfileReaderBinary::readSummaryEntry(
1802 std::vector<ProfileSummaryEntry> &Entries) {
1803 auto Cutoff = readNumber<uint64_t>();
1804 if (std::error_code EC = Cutoff.getError())
1805 return EC;
1806
1807 auto MinBlockCount = readNumber<uint64_t>();
1808 if (std::error_code EC = MinBlockCount.getError())
1809 return EC;
1810
1811 auto NumBlocks = readNumber<uint64_t>();
1812 if (std::error_code EC = NumBlocks.getError())
1813 return EC;
1814
1815 Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks);
1817}
1818
1820 auto TotalCount = readNumber<uint64_t>();
1821 if (std::error_code EC = TotalCount.getError())
1822 return EC;
1823
1824 auto MaxBlockCount = readNumber<uint64_t>();
1825 if (std::error_code EC = MaxBlockCount.getError())
1826 return EC;
1827
1828 auto MaxFunctionCount = readNumber<uint64_t>();
1829 if (std::error_code EC = MaxFunctionCount.getError())
1830 return EC;
1831
1832 auto NumBlocks = readNumber<uint64_t>();
1833 if (std::error_code EC = NumBlocks.getError())
1834 return EC;
1835
1836 auto NumFunctions = readNumber<uint64_t>();
1837 if (std::error_code EC = NumFunctions.getError())
1838 return EC;
1839
1840 auto NumSummaryEntries = readNumber<uint64_t>();
1841 if (std::error_code EC = NumSummaryEntries.getError())
1842 return EC;
1843
1844 std::vector<ProfileSummaryEntry> Entries;
1845 for (unsigned i = 0; i < *NumSummaryEntries; i++) {
1846 std::error_code EC = readSummaryEntry(Entries);
1847 if (EC != sampleprof_error::success)
1848 return EC;
1849 }
1850 Summary = std::make_unique<ProfileSummary>(
1851 ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0,
1852 *MaxFunctionCount, *NumBlocks, *NumFunctions);
1853
1855}
1856
1858 const uint8_t *Data =
1859 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1860 uint64_t Magic = decodeULEB128(Data);
1861 return Magic == SPMagic();
1862}
1863
1865 const uint8_t *Data =
1866 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1867 uint64_t Magic = decodeULEB128(Data);
1868 return Magic == SPMagic(SPF_Ext_Binary);
1869}
1870
1872 uint32_t dummy;
1873 if (!GcovBuffer.readInt(dummy))
1876}
1877
1879 if (sizeof(T) <= sizeof(uint32_t)) {
1880 uint32_t Val;
1881 if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
1882 return static_cast<T>(Val);
1883 } else if (sizeof(T) <= sizeof(uint64_t)) {
1884 uint64_t Val;
1885 if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
1886 return static_cast<T>(Val);
1887 }
1888
1889 std::error_code EC = sampleprof_error::malformed;
1890 reportError(0, EC.message());
1891 return EC;
1892}
1893
1895 StringRef Str;
1896 if (!GcovBuffer.readString(Str))
1898 return Str;
1899}
1900
1902 // Read the magic identifier.
1903 if (!GcovBuffer.readGCDAFormat())
1905
1906 // Read the version number. Note - the GCC reader does not validate this
1907 // version, but the profile creator generates v704.
1908 GCOV::GCOVVersion version;
1909 if (!GcovBuffer.readGCOVVersion(version))
1911
1912 if (version != GCOV::V407)
1914
1915 // Skip the empty integer.
1916 if (std::error_code EC = skipNextWord())
1917 return EC;
1918
1920}
1921
1923 uint32_t Tag;
1924 if (!GcovBuffer.readInt(Tag))
1926
1927 if (Tag != Expected)
1929
1930 if (std::error_code EC = skipNextWord())
1931 return EC;
1932
1934}
1935
1937 if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
1938 return EC;
1939
1940 uint32_t Size;
1941 if (!GcovBuffer.readInt(Size))
1943
1944 for (uint32_t I = 0; I < Size; ++I) {
1945 StringRef Str;
1946 if (!GcovBuffer.readString(Str))
1948 Names.push_back(std::string(Str));
1949 }
1950
1952}
1953
1955 if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
1956 return EC;
1957
1958 uint32_t NumFunctions;
1959 if (!GcovBuffer.readInt(NumFunctions))
1961
1962 InlineCallStack Stack;
1963 for (uint32_t I = 0; I < NumFunctions; ++I)
1964 if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
1965 return EC;
1966
1969}
1970
1972 const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
1973 uint64_t HeadCount = 0;
1974 if (InlineStack.size() == 0)
1975 if (!GcovBuffer.readInt64(HeadCount))
1977
1978 uint32_t NameIdx;
1979 if (!GcovBuffer.readInt(NameIdx))
1981
1982 StringRef Name(Names[NameIdx]);
1983
1984 uint32_t NumPosCounts;
1985 if (!GcovBuffer.readInt(NumPosCounts))
1987
1988 uint32_t NumCallsites;
1989 if (!GcovBuffer.readInt(NumCallsites))
1991
1992 FunctionSamples *FProfile = nullptr;
1993 if (InlineStack.size() == 0) {
1994 // If this is a top function that we have already processed, do not
1995 // update its profile again. This happens in the presence of
1996 // function aliases. Since these aliases share the same function
1997 // body, there will be identical replicated profiles for the
1998 // original function. In this case, we simply not bother updating
1999 // the profile of the original function.
2000 FProfile = &Profiles[FunctionId(Name)];
2001 FProfile->addHeadSamples(HeadCount);
2002 if (FProfile->getTotalSamples() > 0)
2003 Update = false;
2004 } else {
2005 // Otherwise, we are reading an inlined instance. The top of the
2006 // inline stack contains the profile of the caller. Insert this
2007 // callee in the caller's CallsiteMap.
2008 FunctionSamples *CallerProfile = InlineStack.front();
2009 uint32_t LineOffset = Offset >> 16;
2010 uint32_t Discriminator = Offset & 0xffff;
2011 FProfile = &CallerProfile->functionSamplesAt(
2012 LineLocation(LineOffset, Discriminator))[FunctionId(Name)];
2013 }
2014 FProfile->setFunction(FunctionId(Name));
2015
2016 for (uint32_t I = 0; I < NumPosCounts; ++I) {
2018 if (!GcovBuffer.readInt(Offset))
2020
2021 uint32_t NumTargets;
2022 if (!GcovBuffer.readInt(NumTargets))
2024
2026 if (!GcovBuffer.readInt64(Count))
2028
2029 // The line location is encoded in the offset as:
2030 // high 16 bits: line offset to the start of the function.
2031 // low 16 bits: discriminator.
2032 uint32_t LineOffset = Offset >> 16;
2033 uint32_t Discriminator = Offset & 0xffff;
2034
2035 InlineCallStack NewStack;
2036 NewStack.push_back(FProfile);
2037 llvm::append_range(NewStack, InlineStack);
2038 if (Update) {
2039 // Walk up the inline stack, adding the samples on this line to
2040 // the total sample count of the callers in the chain.
2041 for (auto *CallerProfile : NewStack)
2042 CallerProfile->addTotalSamples(Count);
2043
2044 // Update the body samples for the current profile.
2045 FProfile->addBodySamples(LineOffset, Discriminator, Count);
2046 }
2047
2048 // Process the list of functions called at an indirect call site.
2049 // These are all the targets that a function pointer (or virtual
2050 // function) resolved at runtime.
2051 for (uint32_t J = 0; J < NumTargets; J++) {
2052 uint32_t HistVal;
2053 if (!GcovBuffer.readInt(HistVal))
2055
2056 if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
2058
2059 uint64_t TargetIdx;
2060 if (!GcovBuffer.readInt64(TargetIdx))
2062 StringRef TargetName(Names[TargetIdx]);
2063
2064 uint64_t TargetCount;
2065 if (!GcovBuffer.readInt64(TargetCount))
2067
2068 if (Update)
2069 FProfile->addCalledTargetSamples(LineOffset, Discriminator,
2070 FunctionId(TargetName), TargetCount);
2071 }
2072 }
2073
2074 // Process all the inlined callers into the current function. These
2075 // are all the callsites that were inlined into this function.
2076 for (uint32_t I = 0; I < NumCallsites; I++) {
2077 // The offset is encoded as:
2078 // high 16 bits: line offset to the start of the function.
2079 // low 16 bits: discriminator.
2081 if (!GcovBuffer.readInt(Offset))
2083 InlineCallStack NewStack;
2084 NewStack.push_back(FProfile);
2085 llvm::append_range(NewStack, InlineStack);
2086 if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
2087 return EC;
2088 }
2089
2091}
2092
2093/// Read a GCC AutoFDO profile.
2094///
2095/// This format is generated by the Linux Perf conversion tool at
2096/// https://github.com/google/autofdo.
2098 assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator");
2099 // Read the string table.
2100 if (std::error_code EC = readNameTable())
2101 return EC;
2102
2103 // Read the source profile.
2104 if (std::error_code EC = readFunctionProfiles())
2105 return EC;
2106
2108}
2109
2111 StringRef Magic(Buffer.getBufferStart());
2112 return Magic == "adcg*704";
2113}
2114
2116 // If the reader uses MD5 to represent string, we can't remap it because
2117 // we don't know what the original function names were.
2118 if (Reader.useMD5()) {
2119 Ctx.diagnose(DiagnosticInfoSampleProfile(
2120 Reader.getBuffer()->getBufferIdentifier(),
2121 "Profile data remapping cannot be applied to profile data "
2122 "using MD5 names (original mangled names are not available).",
2123 DS_Warning));
2124 return;
2125 }
2126
2127 // CSSPGO-TODO: Remapper is not yet supported.
2128 // We will need to remap the entire context string.
2129 assert(Remappings && "should be initialized while creating remapper");
2130 for (auto &Sample : Reader.getProfiles()) {
2131 DenseSet<FunctionId> NamesInSample;
2132 Sample.second.findAllNames(NamesInSample);
2133 for (auto &Name : NamesInSample) {
2134 StringRef NameStr = Name.stringRef();
2135 if (auto Key = Remappings->insert(NameStr))
2136 NameMap.insert({Key, NameStr});
2137 }
2138 }
2139
2140 RemappingApplied = true;
2141}
2142
2143std::optional<StringRef>
2145 if (auto Key = Remappings->lookup(Fname)) {
2146 StringRef Result = NameMap.lookup(Key);
2147 if (!Result.empty())
2148 return Result;
2149 }
2150 return std::nullopt;
2151}
2152
2153/// Prepare a memory buffer for the contents of \p Filename.
2154///
2155/// \returns an error code indicating the status of the buffer.
2158 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
2159 : FS.getBufferForFile(Filename);
2160 if (std::error_code EC = BufferOrErr.getError())
2161 return EC;
2162 auto Buffer = std::move(BufferOrErr.get());
2163
2164 return std::move(Buffer);
2165}
2166
2167/// Create a sample profile reader based on the format of the input file.
2168///
2169/// \param Filename The file to open.
2170///
2171/// \param C The LLVM context to use to emit diagnostics.
2172///
2173/// \param P The FSDiscriminatorPass.
2174///
2175/// \param RemapFilename The file used for profile remapping.
2176///
2177/// \returns an error code indicating the status of the created reader.
2178ErrorOr<std::unique_ptr<SampleProfileReader>>
2181 StringRef RemapFilename) {
2182 auto BufferOrError = setupMemoryBuffer(Filename, FS);
2183 if (std::error_code EC = BufferOrError.getError())
2184 return EC;
2185 return create(BufferOrError.get(), C, FS, P, RemapFilename);
2186}
2187
2188/// Create a sample profile remapper from the given input, to remap the
2189/// function names in the given profile data.
2190///
2191/// \param Filename The file to open.
2192///
2193/// \param Reader The profile reader the remapper is going to be applied to.
2194///
2195/// \param C The LLVM context to use to emit diagnostics.
2196///
2197/// \returns an error code indicating the status of the created reader.
2200 vfs::FileSystem &FS,
2201 SampleProfileReader &Reader,
2202 LLVMContext &C) {
2203 auto BufferOrError = setupMemoryBuffer(Filename, FS);
2204 if (std::error_code EC = BufferOrError.getError())
2205 return EC;
2206 return create(BufferOrError.get(), Reader, C);
2207}
2208
2209/// Create a sample profile remapper from the given input, to remap the
2210/// function names in the given profile data.
2211///
2212/// \param B The memory buffer to create the reader from (assumes ownership).
2213///
2214/// \param C The LLVM context to use to emit diagnostics.
2215///
2216/// \param Reader The profile reader the remapper is going to be applied to.
2217///
2218/// \returns an error code indicating the status of the created reader.
2220SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B,
2221 SampleProfileReader &Reader,
2222 LLVMContext &C) {
2223 auto Remappings = std::make_unique<SymbolRemappingReader>();
2224 if (Error E = Remappings->read(*B)) {
2226 std::move(E), [&](const SymbolRemappingParseError &ParseError) {
2227 C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(),
2228 ParseError.getLineNum(),
2229 ParseError.getMessage()));
2230 });
2232 }
2233
2234 return std::make_unique<SampleProfileReaderItaniumRemapper>(
2235 std::move(B), std::move(Remappings), Reader);
2236}
2237
2238/// Create a sample profile reader based on the format of the input data.
2239///
2240/// \param B The memory buffer to create the reader from (assumes ownership).
2241///
2242/// \param C The LLVM context to use to emit diagnostics.
2243///
2244/// \param P The FSDiscriminatorPass.
2245///
2246/// \param RemapFilename The file used for profile remapping.
2247///
2248/// \returns an error code indicating the status of the created reader.
2250SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
2252 StringRef RemapFilename) {
2253 std::unique_ptr<SampleProfileReader> Reader;
2255 Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
2257 Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
2259 Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
2261 Reader.reset(new SampleProfileReaderText(std::move(B), C));
2262 else
2264
2265 if (!RemapFilename.empty()) {
2267 RemapFilename, FS, *Reader, C);
2268 if (std::error_code EC = ReaderOrErr.getError()) {
2269 std::string Msg = "Could not create remapper: " + EC.message();
2270 C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg));
2271 return EC;
2272 }
2273 Reader->Remapper = std::move(ReaderOrErr.get());
2274 }
2275
2276 if (std::error_code EC = Reader->readHeader()) {
2277 return EC;
2278 }
2279
2280 Reader->setDiscriminatorMaskedBitFrom(P);
2281
2282 return std::move(Reader);
2283}
2284
2285// For text and GCC file formats, we compute the summary after reading the
2286// 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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
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:819
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:826
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:845
sampleprof_error addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator, FunctionId Func, uint64_t Num, uint64_t Weight=1)
Definition SampleProf.h:859
FunctionSamplesMap & functionSamplesAt(const LineLocation &Loc)
Return the function samples at the given callsite location.
Definition SampleProf.h:988
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:853
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:685
FunctionId getFunction() const
Definition SampleProf.h:691
bool isPrefixOf(const SampleContext &That) const
Definition SampleProf.h:770
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 readFuncOffsetTable(bool IsEytzinger, bool IsCS)
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:393
SortedCallTargetSet getSortedCallTargets() const
Definition SampleProf.h:462
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:810
static bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:306
uint64_t MD5Hash(const FunctionId &Obj)
Definition FunctionId.h:167
constexpr EytzingerModeT EytzingerMode
@ 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:579
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:373
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:806
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
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, unaligned > ulittle32_t
Definition Endian.h:290
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)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
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:322