20using namespace sampleprof;
22#define DEBUG_TYPE "sample-profile-matcher"
26 cl::desc(
"Consider a profile matches a function if the similarity of their "
27 "callee sequences is above the specified percentile."));
31 cl::desc(
"The minimum number of basic blocks required for a function to "
32 "run stale profile call graph matching."));
36 cl::desc(
"The minimum number of call anchors required for a function to "
37 "run stale profile call graph matching."));
46 cl::desc(
"The maximum number of callsites in a function, above which stale "
47 "profile matching will be skipped."));
49void SampleProfileMatcher::findIRAnchors(
const Function &
F,
54 auto FindTopLevelInlinedCallsite = [](
const DILocation *DIL) {
55 assert((DIL && DIL->getInlinedAt()) &&
"No inlined callsite");
59 DIL = DIL->getInlinedAt();
60 }
while (DIL->getInlinedAt());
64 StringRef CalleeName = PrevDIL->getSubprogramLinkageName();
65 return std::make_pair(Callsite,
FunctionId(CalleeName));
68 auto GetCanonicalCalleeName = [](
const CallBase *CB) {
69 StringRef CalleeName = UnknownIndirectCallee;
70 if (
Function *Callee = CB->getCalledFunction())
85 if (DIL->getInlinedAt()) {
86 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
90 if (
const auto *CB = dyn_cast<CallBase>(&
I)) {
92 if (!isa<IntrinsicInst>(&
I))
93 CalleeName = GetCanonicalCalleeName(CB);
96 IRAnchors.emplace(Loc,
FunctionId(CalleeName));
103 if (!isa<CallBase>(&
I) || isa<IntrinsicInst>(&
I))
106 if (DIL->getInlinedAt()) {
107 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
111 StringRef CalleeName = GetCanonicalCalleeName(dyn_cast<CallBase>(&
I));
112 IRAnchors.emplace(Callsite,
FunctionId(CalleeName));
119void SampleProfileMatcher::findProfileAnchors(
const FunctionSamples &FS,
121 auto isInvalidLineOffset = [](
uint32_t LineOffset) {
122 return LineOffset & 0x8000;
127 auto Ret = ProfileAnchors.try_emplace(Loc, CalleeName);
135 for (
const auto &
I :
FS.getBodySamples()) {
139 for (
const auto &
C :
I.second.getCallTargets())
140 InsertAnchor(Loc,
C.first, ProfileAnchors);
143 for (
const auto &
I :
FS.getCallsiteSamples()) {
147 for (
const auto &
C :
I.second)
148 InsertAnchor(Loc,
C.first, ProfileAnchors);
152bool SampleProfileMatcher::functionHasProfile(
const FunctionId &IRFuncName,
154 FuncWithoutProfile =
nullptr;
155 auto R = FunctionsWithoutProfile.find(IRFuncName);
156 if (R != FunctionsWithoutProfile.end())
157 FuncWithoutProfile =
R->second;
158 return !FuncWithoutProfile;
161bool SampleProfileMatcher::isProfileUnused(
const FunctionId &ProfileFuncName) {
162 return SymbolMap->find(ProfileFuncName) == SymbolMap->end();
165bool SampleProfileMatcher::functionMatchesProfile(
167 bool FindMatchedProfileOnly) {
168 if (IRFuncName == ProfileFuncName)
176 if (functionHasProfile(IRFuncName, IRFunc) ||
177 !isProfileUnused(ProfileFuncName))
181 "IR function should be different from profile function to match");
182 return functionMatchesProfile(*IRFunc, ProfileFuncName,
183 FindMatchedProfileOnly);
187SampleProfileMatcher::longestCommonSequence(
const AnchorList &AnchorList1,
189 bool MatchUnusedFunction) {
190 int32_t Size1 = AnchorList1.size(), Size2 = AnchorList2.size(),
196 return EqualLocations;
199 auto Backtrack = [&](
const std::vector<std::vector<int32_t>> &
Trace,
203 int32_t
X = Size1,
Y = Size2;
213 int32_t PrevX =
P[
Index(PrevK)];
214 int32_t PrevY = PrevX - PrevK;
215 while (
X > PrevX &&
Y > PrevY) {
218 EqualLocations.insert({AnchorList1[
X].first, AnchorList2[
Y].first});
236 std::vector<int32_t>
V(2 *
MaxDepth + 1, -1);
239 std::vector<std::vector<int32_t>>
Trace;
243 int32_t
X = 0,
Y = 0;
249 while (
X < Size1 &&
Y < Size2 &&
250 functionMatchesProfile(
251 AnchorList1[
X].second, AnchorList2[
Y].second,
252 !MatchUnusedFunction ))
257 if (
X >= Size1 &&
Y >= Size2) {
259 Backtrack(
Trace, AnchorList1, AnchorList2, EqualLocations);
260 return EqualLocations;
265 return EqualLocations;
268void SampleProfileMatcher::matchNonCallsiteLocs(
274 IRToProfileLocationMap.insert({
From, To});
278 int32_t LocationDelta = 0;
280 for (
const auto &
IR : IRAnchors) {
281 const auto &Loc =
IR.first;
282 bool IsMatchedAnchor =
false;
284 auto R = MatchedAnchors.find(Loc);
285 if (R != MatchedAnchors.end()) {
286 const auto &Candidate =
R->second;
287 InsertMatching(Loc, Candidate);
289 <<
" is matched from " << Loc <<
" to " << Candidate
291 LocationDelta = Candidate.LineOffset - Loc.
LineOffset;
297 for (
size_t I = (LastMatchedNonAnchors.
size() + 1) / 2;
298 I < LastMatchedNonAnchors.
size();
I++) {
299 const auto &
L = LastMatchedNonAnchors[
I];
300 uint32_t CandidateLineOffset =
L.LineOffset + LocationDelta;
301 LineLocation Candidate(CandidateLineOffset,
L.Discriminator);
302 InsertMatching(L, Candidate);
304 <<
" to " << Candidate <<
"\n");
307 IsMatchedAnchor =
true;
308 LastMatchedNonAnchors.
clear();
312 if (!IsMatchedAnchor) {
315 InsertMatching(Loc, Candidate);
317 << Candidate <<
"\n");
325void SampleProfileMatcher::getFilteredAnchorList(
328 for (
const auto &
I : IRAnchors) {
329 if (
I.second.stringRef().empty())
331 FilteredIRAnchorsList.emplace_back(
I);
334 for (
const auto &
I : ProfileAnchors)
335 FilteredProfileAnchorList.emplace_back(
I);
355void SampleProfileMatcher::runStaleProfileMatching(
358 bool RunCFGMatching,
bool RunCGMatching) {
359 if (!RunCFGMatching && !RunCGMatching)
363 assert(IRToProfileLocationMap.empty() &&
364 "Run stale profile matching only once per function");
368 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
369 FilteredProfileAnchorList);
371 if (FilteredIRAnchorsList.empty() || FilteredProfileAnchorList.empty())
377 <<
" because the number of callsites in the IR is "
378 << FilteredIRAnchorsList.size()
379 <<
" and in the profile is "
380 << FilteredProfileAnchorList.size() <<
"\n");
395 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
403 matchNonCallsiteLocs(MatchedAnchors, IRAnchors, IRToProfileLocationMap);
406void SampleProfileMatcher::runOnFunction(
Function &
F) {
413 const auto *FSFlattened = getFlattenedSamplesFor(
F);
420 auto R = FuncToProfileNameMap.find(&
F);
421 if (R != FuncToProfileNameMap.end())
422 FSFlattened = getFlattenedSamplesFor(
R->second);
431 findIRAnchors(
F, IRAnchors);
435 findProfileAnchors(*FSFlattened, ProfileAnchors);
439 recordCallsiteMatchStates(
F, IRAnchors, ProfileAnchors,
nullptr);
447 bool RunCFGMatching =
455 F.addFnAttr(
"profile-checksum-mismatch");
459 auto &IRToProfileLocationMap = getIRToProfileLocationMap(
F);
460 runStaleProfileMatching(
F, IRAnchors, ProfileAnchors, IRToProfileLocationMap,
461 RunCFGMatching, RunCGMatching);
464 recordCallsiteMatchStates(
F, IRAnchors, ProfileAnchors,
465 &IRToProfileLocationMap);
468void SampleProfileMatcher::recordCallsiteMatchStates(
472 bool IsPostMatch = IRToProfileLocationMap !=
nullptr;
473 auto &CallsiteMatchStates =
476 auto MapIRLocToProfileLoc = [&](
const LineLocation &IRLoc) {
478 if (!IRToProfileLocationMap)
480 const auto &ProfileLoc = IRToProfileLocationMap->find(IRLoc);
481 if (ProfileLoc != IRToProfileLocationMap->end())
482 return ProfileLoc->second;
487 for (
const auto &
I : IRAnchors) {
490 const auto &ProfileLoc = MapIRLocToProfileLoc(
I.first);
491 const auto &IRCalleeId =
I.second;
492 const auto &It = ProfileAnchors.find(ProfileLoc);
493 if (It == ProfileAnchors.end())
495 const auto &ProfCalleeId = It->second;
496 if (IRCalleeId == ProfCalleeId) {
497 auto It = CallsiteMatchStates.find(ProfileLoc);
498 if (It == CallsiteMatchStates.end())
499 CallsiteMatchStates.emplace(ProfileLoc, MatchState::InitialMatch);
500 else if (IsPostMatch) {
501 if (It->second == MatchState::InitialMatch)
502 It->second = MatchState::UnchangedMatch;
503 else if (It->second == MatchState::InitialMismatch)
504 It->second = MatchState::RecoveredMismatch;
511 for (
const auto &
I : ProfileAnchors) {
512 const auto &Loc =
I.first;
513 assert(!
I.second.stringRef().empty() &&
"Callees should not be empty");
514 auto It = CallsiteMatchStates.find(Loc);
515 if (It == CallsiteMatchStates.end())
516 CallsiteMatchStates.emplace(Loc, MatchState::InitialMismatch);
517 else if (IsPostMatch) {
520 if (It->second == MatchState::InitialMismatch)
521 It->second = MatchState::UnchangedMismatch;
522 else if (It->second == MatchState::InitialMatch)
523 It->second = MatchState::RemovedMatch;
528void SampleProfileMatcher::countMismatchedFuncSamples(
const FunctionSamples &FS,
530 const auto *FuncDesc = ProbeManager->
getDesc(
FS.getGUID());
537 NumStaleProfileFunc++;
542 MismatchedFunctionSamples +=
FS.getTotalSamples();
551 for (
const auto &
I :
FS.getCallsiteSamples())
552 for (
const auto &CS :
I.second)
553 countMismatchedFuncSamples(CS.second,
false);
556void SampleProfileMatcher::countMismatchedCallsiteSamples(
558 auto It = FuncCallsiteMatchStates.find(
FS.getFuncName());
560 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
562 const auto &CallsiteMatchStates = It->second;
565 auto It = CallsiteMatchStates.find(Loc);
566 if (It == CallsiteMatchStates.end())
567 return MatchState::Unknown;
571 auto AttributeMismatchedSamples = [&](
const enum MatchState &State,
573 if (isMismatchState(State))
574 MismatchedCallsiteSamples += Samples;
575 else if (State == MatchState::RecoveredMismatch)
576 RecoveredCallsiteSamples += Samples;
581 for (
const auto &
I :
FS.getBodySamples())
582 AttributeMismatchedSamples(findMatchState(
I.first),
I.second.getSamples());
585 for (
const auto &
I :
FS.getCallsiteSamples()) {
586 auto State = findMatchState(
I.first);
588 for (
const auto &CS :
I.second)
589 CallsiteSamples += CS.second.getTotalSamples();
590 AttributeMismatchedSamples(State, CallsiteSamples);
592 if (isMismatchState(State))
598 for (
const auto &CS :
I.second)
599 countMismatchedCallsiteSamples(CS.second);
603void SampleProfileMatcher::countMismatchCallsites(
const FunctionSamples &FS) {
604 auto It = FuncCallsiteMatchStates.find(
FS.getFuncName());
606 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
608 const auto &MatchStates = It->second;
609 [[maybe_unused]]
bool OnInitialState =
610 isInitialState(MatchStates.begin()->second);
611 for (
const auto &
I : MatchStates) {
612 TotalProfiledCallsites++;
614 (OnInitialState ? isInitialState(
I.second) : isFinalState(
I.second)) &&
615 "Profile matching state is inconsistent");
617 if (isMismatchState(
I.second))
618 NumMismatchedCallsites++;
619 else if (
I.second == MatchState::RecoveredMismatch)
620 NumRecoveredCallsites++;
624void SampleProfileMatcher::countCallGraphRecoveredSamples(
626 std::unordered_set<FunctionId> &CallGraphRecoveredProfiles) {
627 if (CallGraphRecoveredProfiles.count(
FS.getFunction())) {
628 NumCallGraphRecoveredFuncSamples +=
FS.getTotalSamples();
632 for (
const auto &CM :
FS.getCallsiteSamples()) {
633 for (
const auto &CS : CM.second) {
634 countCallGraphRecoveredSamples(CS.second, CallGraphRecoveredProfiles);
639void SampleProfileMatcher::computeAndReportProfileStaleness() {
643 std::unordered_set<FunctionId> CallGraphRecoveredProfiles;
645 for (
const auto &
I : FuncToProfileNameMap) {
646 CallGraphRecoveredProfiles.insert(
I.second);
649 NumCallGraphRecoveredProfiledFunc++;
654 for (
const auto &
F : M) {
665 TotalFunctionSamples +=
FS->getTotalSamples();
668 countCallGraphRecoveredSamples(*FS, CallGraphRecoveredProfiles);
672 countMismatchedFuncSamples(*FS,
true);
675 countMismatchCallsites(*FS);
676 countMismatchedCallsiteSamples(*FS);
681 errs() <<
"(" << NumStaleProfileFunc <<
"/" << TotalProfiledFunc
682 <<
") of functions' profile are invalid and ("
683 << MismatchedFunctionSamples <<
"/" << TotalFunctionSamples
684 <<
") of samples are discarded due to function hash mismatch.\n";
687 errs() <<
"(" << NumCallGraphRecoveredProfiledFunc <<
"/"
688 << TotalProfiledFunc <<
") of functions' profile are matched and ("
689 << NumCallGraphRecoveredFuncSamples <<
"/" << TotalFunctionSamples
690 <<
") of samples are reused by call graph matching.\n";
693 errs() <<
"(" << (NumMismatchedCallsites + NumRecoveredCallsites) <<
"/"
694 << TotalProfiledCallsites
695 <<
") of callsites' profile are invalid and ("
696 << (MismatchedCallsiteSamples + RecoveredCallsiteSamples) <<
"/"
697 << TotalFunctionSamples
698 <<
") of samples are discarded due to callsite location mismatch.\n";
699 errs() <<
"(" << NumRecoveredCallsites <<
"/"
700 << (NumRecoveredCallsites + NumMismatchedCallsites)
701 <<
") of callsites and (" << RecoveredCallsiteSamples <<
"/"
702 << (RecoveredCallsiteSamples + MismatchedCallsiteSamples)
703 <<
") of samples are recovered by stale profile matching.\n";
712 ProfStatsVec.
emplace_back(
"NumStaleProfileFunc", NumStaleProfileFunc);
713 ProfStatsVec.
emplace_back(
"TotalProfiledFunc", TotalProfiledFunc);
715 MismatchedFunctionSamples);
716 ProfStatsVec.
emplace_back(
"TotalFunctionSamples", TotalFunctionSamples);
720 ProfStatsVec.
emplace_back(
"NumCallGraphRecoveredProfiledFunc",
721 NumCallGraphRecoveredProfiledFunc);
722 ProfStatsVec.
emplace_back(
"NumCallGraphRecoveredFuncSamples",
723 NumCallGraphRecoveredFuncSamples);
726 ProfStatsVec.
emplace_back(
"NumMismatchedCallsites", NumMismatchedCallsites);
727 ProfStatsVec.
emplace_back(
"NumRecoveredCallsites", NumRecoveredCallsites);
728 ProfStatsVec.
emplace_back(
"TotalProfiledCallsites", TotalProfiledCallsites);
730 MismatchedCallsiteSamples);
732 RecoveredCallsiteSamples);
734 auto *MD = MDB.createLLVMStats(ProfStatsVec);
735 auto *NMD =
M.getOrInsertNamedMetadata(
"llvm.stats");
740void SampleProfileMatcher::findFunctionsWithoutProfile() {
746 for (
auto Name : *NameTable)
753 if (
F.isDeclaration())
757 const auto *
FS = getFlattenedSamplesFor(
F);
764 if (NamesInProfile.
count(CanonFName))
769 if (PSL && PSL->contains(CanonFName))
773 <<
" is not in profile or profile symbol list.\n");
774 FunctionsWithoutProfile[
FunctionId(CanonFName)] = &
F;
778bool SampleProfileMatcher::functionMatchesProfileHelper(
782 float Similarity = 0.0;
784 const auto *FSFlattened = getFlattenedSamplesFor(ProfFunc);
797 const auto *FuncDesc = ProbeManager->
getDesc(IRFunc);
801 <<
"(IR) and " << ProfFunc <<
"(Profile) match.\n");
808 findIRAnchors(IRFunc, IRAnchors);
810 findProfileAnchors(*FSFlattened, ProfileAnchors);
814 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
815 FilteredProfileAnchorList);
828 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
832 static_cast<float>(MatchedAnchors.size()) * 2 /
833 (FilteredIRAnchorsList.size() + FilteredProfileAnchorList.size());
836 <<
"(IR) and " << ProfFunc <<
"(profile) is "
837 <<
format(
"%.2f", Similarity) <<
"\n");
838 assert((Similarity >= 0 && Similarity <= 1.0) &&
839 "Similarity value should be in [0, 1]");
845bool SampleProfileMatcher::functionMatchesProfile(
Function &IRFunc,
847 bool FindMatchedProfileOnly) {
848 auto R = FuncProfileMatchCache.find({&IRFunc, ProfFunc});
849 if (R != FuncProfileMatchCache.end())
852 if (FindMatchedProfileOnly)
855 bool Matched = functionMatchesProfileHelper(IRFunc, ProfFunc);
856 FuncProfileMatchCache[{&IRFunc, ProfFunc}] = Matched;
858 FuncToProfileNameMap[&IRFunc] = ProfFunc;
860 <<
" matches profile:" << ProfFunc <<
"\n");
870 findFunctionsWithoutProfile();
874 std::vector<Function *> TopDownFunctionList;
875 TopDownFunctionList.reserve(M.size());
877 for (
auto *
F : TopDownFunctionList) {
885 for (
auto &
I : FuncToProfileNameMap) {
886 assert(
I.first &&
"New function is null");
888 FuncNameToProfNameMap->emplace(FuncName,
I.second);
891 SymbolMap->erase(FuncName);
892 SymbolMap->emplace(
I.second,
I.first);
896 distributeIRToProfileLocationMap();
898 computeAndReportProfileStaleness();
901void SampleProfileMatcher::distributeIRToProfileLocationMap(
903 const auto ProfileMappings = FuncMappings.
find(FS.getFuncName());
904 if (ProfileMappings != FuncMappings.
end()) {
905 FS.setIRToProfileLocationMap(&(ProfileMappings->second));
910 for (
auto &FS : Callees.second) {
911 distributeIRToProfileLocationMap(FS.second);
918void SampleProfileMatcher::distributeIRToProfileLocationMap() {
920 distributeIRToProfileLocationMap(
I.second);
BlockVerifier::State From
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
static const unsigned MaxDepth
Legalize the Machine IR a function s Machine IR
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static cl::opt< unsigned > MinCallCountForCGMatching("min-call-count-for-cg-matching", cl::Hidden, cl::init(3), cl::desc("The minimum number of call anchors required for a function to " "run stale profile call graph matching."))
cl::opt< bool > ReportProfileStaleness
static cl::opt< unsigned > FuncProfileSimilarityThreshold("func-profile-similarity-threshold", cl::Hidden, cl::init(80), cl::desc("Consider a profile matches a function if the similarity of their " "callee sequences is above the specified percentile."))
cl::opt< bool > SalvageStaleProfile
static cl::opt< unsigned > SalvageStaleProfileMaxCallsites("salvage-stale-profile-max-callsites", cl::Hidden, cl::init(UINT_MAX), cl::desc("The maximum number of callsites in a function, above which stale " "profile matching will be skipped."))
static cl::opt< unsigned > MinFuncCountForCGMatching("min-func-count-for-cg-matching", cl::Hidden, cl::init(5), cl::desc("The minimum number of basic blocks required for a function to " "run stale profile call graph matching."))
cl::opt< bool > SalvageUnusedProfile
cl::opt< bool > PersistProfileStaleness
This file provides the interface for SampleProfileMatcher.
cl::opt< bool > SalvageUnusedProfile("salvage-unused-profile", cl::Hidden, cl::init(false), cl::desc("Salvage unused profile by matching with new " "functions on call graph."))
cl::opt< bool > PersistProfileStaleness("persist-profile-staleness", cl::Hidden, cl::init(false), cl::desc("Compute stale profile statistical metrics and write it into the " "native object file(.llvm_stats section)."))
cl::opt< bool > ReportProfileStaleness("report-profile-staleness", cl::Hidden, cl::init(false), cl::desc("Compute and report stale profile statistical metrics."))
cl::opt< bool > SalvageStaleProfile("salvage-stale-profile", cl::Hidden, cl::init(false), cl::desc("Salvage stale profile by fuzzy matching and use the remapped " "location for sample profile query."))
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
This is an important class for using LLVM in a threaded context.
bool profileIsHashMismatched(const PseudoProbeDescriptor &FuncDesc, const FunctionSamples &Samples) const
bool profileIsValid(const Function &F, const FunctionSamples &Samples) const
const PseudoProbeDescriptor * getDesc(uint64_t GUID) const
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
iterator find(StringRef Key)
size_type count(StringRef Key) const
count - Return 1 if the element is in the map, 0 otherwise.
StringRef - Represent a constant reference to a string, i.e.
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
StringRef getName() const
Return a constant reference to the value's name.
This class represents a function that is read from a sample profile.
Representation of the samples collected for a function.
static bool ProfileIsProbeBased
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
static bool ProfileIsFS
If this profile uses flow sensitive discriminators.
static LineLocation getCallSiteIdentifier(const DILocation *DIL, bool ProfileIsFS=false)
Returns a unique call site identifier for a given debug location of a call instruction.
static bool UseMD5
Whether the profile uses MD5 to represent string.
static void flattenProfile(SampleProfileMap &ProfileMap, bool ProfileIsCS=false)
SampleProfileMap & getProfiles()
Return all the profiles.
FunctionSamples * getSamplesFor(const Function &F)
Return the samples collected for function F.
virtual std::vector< FunctionId > * getNameTable()
It includes all the names that have samples either in outline instance or inline instance.
@ C
The default llvm calling convention, compatible with C.
initializer< Ty > init(const Ty &Val)
std::unordered_map< LineLocation, LineLocation, LineLocationHash > LocToLocMap
std::map< LineLocation, FunctionSamplesMap > CallsiteSampleMap
This is an optimization pass for GlobalISel generic memory operations.
std::vector< std::pair< LineLocation, FunctionId > > AnchorList
std::map< LineLocation, FunctionId > AnchorMap
static void buildTopDownFuncOrder(LazyCallGraph &CG, std::vector< Function * > &FunctionOrderList)
@ ThinLTOPreLink
ThinLTO prelink (summary) phase.
std::optional< PseudoProbe > extractProbe(const Instruction &Inst)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
static bool skipProfileForFunction(const Function &F)
Represents the relative location of an instruction.