25#define DEBUG_TYPE "sample-profile-matcher"
28 "Number of functions matched by demangled basename");
34 cl::desc(
"Consider a profile matches a function if the similarity of their "
35 "callee sequences is above the specified percentile."));
39 cl::desc(
"The minimum number of basic blocks required for a function to "
40 "run stale profile call graph matching."));
44 cl::desc(
"The minimum number of call anchors required for a function to "
45 "run stale profile call graph matching."));
50 "Load top-level profiles that the sample reader initially skipped for "
51 "the call-graph matching (only meaningful for extended binary "
61 cl::desc(
"The maximum number of functions in a module, above which salvage "
62 "unused profile will be skipped."));
66 cl::desc(
"The maximum number of callsites in a function, above which stale "
67 "profile matching will be skipped."));
71void SampleProfileMatcher::findIRAnchors(
const Function &
F,
76 auto FindTopLevelInlinedCallsite = [](
const DILocation *DIL) {
77 assert((DIL && DIL->getInlinedAt()) &&
"No inlined callsite");
81 DIL = DIL->getInlinedAt();
82 }
while (DIL->getInlinedAt());
86 StringRef CalleeName = PrevDIL->getSubprogramLinkageName();
87 return std::make_pair(Callsite, FunctionId(CalleeName));
90 auto GetCanonicalCalleeName = [](
const CallBase *CB) {
91 StringRef CalleeName = UnknownIndirectCallee;
92 if (Function *Callee = CB->getCalledFunction())
100 DILocation *DIL =
I.getDebugLoc();
107 if (DIL->getInlinedAt()) {
108 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
111 StringRef CalleeName;
115 CalleeName = GetCanonicalCalleeName(CB);
117 LineLocation Loc = LineLocation(Probe->Id, 0);
118 IRAnchors.emplace(Loc, FunctionId(CalleeName));
128 if (DIL->getInlinedAt()) {
129 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
134 IRAnchors.emplace(Callsite, FunctionId(CalleeName));
141void SampleProfileMatcher::findProfileAnchors(
const FunctionSamples &FS,
143 auto isInvalidLineOffset = [](uint32_t LineOffset) {
144 return LineOffset & 0x8000;
147 auto InsertAnchor = [](
const LineLocation &Loc,
const FunctionId &CalleeName,
149 auto Ret = ProfileAnchors.try_emplace(Loc, CalleeName);
153 Ret.first->second = FunctionId(UnknownIndirectCallee);
157 for (
const auto &
I :
FS.getBodySamples()) {
158 const LineLocation &Loc =
I.first;
161 for (
const auto &
C :
I.second.getCallTargets())
162 InsertAnchor(Loc,
C.first, ProfileAnchors);
165 for (
const auto &
I :
FS.getCallsiteSamples()) {
166 const LineLocation &Loc =
I.first;
169 for (
const auto &
C :
I.second)
170 InsertAnchor(Loc,
C.first, ProfileAnchors);
174bool SampleProfileMatcher::functionHasProfile(
const FunctionId &IRFuncName,
176 FuncWithoutProfile =
nullptr;
177 auto R = FunctionsWithoutProfile.find(IRFuncName);
178 if (R != FunctionsWithoutProfile.end())
179 FuncWithoutProfile =
R->second;
180 return !FuncWithoutProfile;
183bool SampleProfileMatcher::isProfileUnused(
const FunctionId &ProfileFuncName) {
186 return (SymbolMap->find(ProfileFuncName) == SymbolMap->end()) &&
190 (ProbeManager->getDesc(ProfileFuncName.
stringRef()) ==
nullptr));
193bool SampleProfileMatcher::functionMatchesProfile(
195 bool FindMatchedProfileOnly) {
196 if (IRFuncName == ProfileFuncName)
204 if (functionHasProfile(IRFuncName, IRFunc) ||
205 !isProfileUnused(ProfileFuncName))
209 "IR function should be different from profile function to match");
210 return functionMatchesProfile(*IRFunc, ProfileFuncName,
211 FindMatchedProfileOnly);
215SampleProfileMatcher::longestCommonSequence(
const AnchorList &AnchorList1,
217 bool MatchUnusedFunction) {
220 AnchorList1, AnchorList2,
221 [&](
const FunctionId &
A,
const FunctionId &
B) {
222 return functionMatchesProfile(
227 [&](LineLocation
A, LineLocation
B) {
230 return MatchedAnchors;
233void SampleProfileMatcher::matchNonCallsiteLocs(
236 auto UpdateMatching = [&](
const LineLocation &From,
const LineLocation &To) {
241 IRToProfileLocationMap.
erase(From);
245 int32_t LocationDelta = 0;
247 for (
const auto &
IR : IRAnchors) {
248 const auto &Loc =
IR.first;
249 bool IsMatchedAnchor =
false;
251 auto R = MatchedAnchors.
find(Loc);
252 if (R != MatchedAnchors.
end()) {
253 const auto &Candidate =
R->second;
254 UpdateMatching(Loc, Candidate);
256 <<
" is matched from " << Loc <<
" to " << Candidate
258 LocationDelta = Candidate.LineOffset - Loc.
LineOffset;
264 for (
size_t I = (LastMatchedNonAnchors.
size() + 1) / 2;
265 I < LastMatchedNonAnchors.
size();
I++) {
266 const auto &
L = LastMatchedNonAnchors[
I];
267 uint32_t CandidateLineOffset =
L.LineOffset + LocationDelta;
268 LineLocation Candidate(CandidateLineOffset,
L.Discriminator);
269 UpdateMatching(L, Candidate);
271 <<
" to " << Candidate <<
"\n");
274 IsMatchedAnchor =
true;
275 LastMatchedNonAnchors.
clear();
279 if (!IsMatchedAnchor) {
280 uint32_t CandidateLineOffset = Loc.
LineOffset + LocationDelta;
281 LineLocation Candidate(CandidateLineOffset, Loc.
Discriminator);
282 UpdateMatching(Loc, Candidate);
284 << Candidate <<
"\n");
292void SampleProfileMatcher::getFilteredAnchorList(
295 for (
const auto &
I : IRAnchors) {
296 if (
I.second.stringRef().empty())
298 FilteredIRAnchorsList.emplace_back(
I);
301 for (
const auto &
I : ProfileAnchors)
302 FilteredProfileAnchorList.emplace_back(
I);
322void SampleProfileMatcher::runStaleProfileMatching(
325 bool RunCFGMatching,
bool RunCGMatching) {
326 if (!RunCFGMatching && !RunCGMatching)
331 "Run stale profile matching only once per function");
335 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
336 FilteredProfileAnchorList);
338 if (FilteredIRAnchorsList.empty() || FilteredProfileAnchorList.empty())
344 <<
" because the number of callsites in the IR is "
345 << FilteredIRAnchorsList.size()
346 <<
" and in the profile is "
347 << FilteredProfileAnchorList.size() <<
"\n");
362 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
369 for (
const auto &
IR : IRAnchors) {
370 bool ProfileConflicted =
false;
371 const auto &Loc =
IR.first;
375 FunctionId ProfAnchor;
376 auto AnchorLoc = MatchedAnchors.
find(Loc);
377 if (AnchorLoc == MatchedAnchors.
end()) {
380 auto PreMatched = FuncToProfileNameMap.find(Callee);
381 if (PreMatched == FuncToProfileNameMap.end())
383 ProfAnchor = PreMatched->second;
385 const auto &Prof = ProfileAnchors.find(AnchorLoc->second);
386 if (Prof == ProfileAnchors.end())
388 ProfAnchor = Prof->second;
392 auto Cached = MatchedAnchorCache.find(ProfAnchor);
393 if (Cached == MatchedAnchorCache.end())
394 MatchedAnchorCache[ProfAnchor] =
Callee;
395 else if (Cached->second != Callee)
396 ProfileConflicted =
true;
398 if (ProfileConflicted) {
401 const auto *FSForMatching = getFlattenedSamplesFor(ProfAnchor);
403 FSForMatching = Reader.getSamplesFor(ProfAnchor.
stringRef());
407 FunctionId NewAnchor(
409 auto R = FuncProfileMatchCache.find({
Callee, NewAnchor});
410 if (R != FuncProfileMatchCache.end() &&
R->second)
412 FunctionSamples &NewFS = FlattenedProfiles.create(NewAnchor);
413 NewFS.
merge(*FSForMatching);
414 FuncToProfileNameMap[
Callee] = NewAnchor;
415 FuncProfileMatchCache[{
Callee, NewAnchor}] =
true;
418 SampleProfileMap &Profiles = Reader.getProfiles();
419 SampleContext FContext(NewAnchor);
420 auto Res = Profiles.
try_emplace(FContext.getHashCode(), FContext, NewFS);
421 FunctionSamples &FProfile = Res.first->second;
431 matchNonCallsiteLocs(MatchedAnchors, IRAnchors, IRToProfileLocationMap);
434void SampleProfileMatcher::runOnFunction(
Function &
F) {
441 const auto *FSForMatching = getFlattenedSamplesFor(
F);
444 auto R = FuncToProfileNameMap.find(&
F);
445 if (R != FuncToProfileNameMap.end()) {
446 FSForMatching = getFlattenedSamplesFor(
R->second);
451 FSForMatching = Reader.getSamplesFor(
R->second.stringRef());
461 findIRAnchors(
F, IRAnchors);
465 findProfileAnchors(*FSForMatching, ProfileAnchors);
469 recordCallsiteMatchStates(
F, IRAnchors, ProfileAnchors,
nullptr);
476 !ProbeManager->profileIsValid(
F, *FSForMatching);
477 bool RunCFGMatching =
485 F.addFnAttr(
"profile-checksum-mismatch");
489 auto &IRToProfileLocationMap = getIRToProfileLocationMap(*FSForMatching);
490 runStaleProfileMatching(
F, IRAnchors, ProfileAnchors, IRToProfileLocationMap,
491 RunCFGMatching, RunCGMatching);
494 recordCallsiteMatchStates(
F, IRAnchors, ProfileAnchors,
495 &IRToProfileLocationMap);
498void SampleProfileMatcher::recordCallsiteMatchStates(
502 bool IsPostMatch = IRToProfileLocationMap !=
nullptr;
503 auto &CallsiteMatchStates =
506 auto MapIRLocToProfileLoc = [&](
const LineLocation &IRLoc) {
508 if (!IRToProfileLocationMap)
510 const auto &ProfileLoc = IRToProfileLocationMap->
find(IRLoc);
511 if (ProfileLoc != IRToProfileLocationMap->
end())
512 return ProfileLoc->second;
517 for (
const auto &
I : IRAnchors) {
520 const auto &ProfileLoc = MapIRLocToProfileLoc(
I.first);
521 const auto &IRCalleeId =
I.second;
522 const auto &It = ProfileAnchors.find(ProfileLoc);
523 if (It == ProfileAnchors.end())
525 const auto &ProfCalleeId = It->second;
526 if (IRCalleeId == ProfCalleeId) {
527 auto It = CallsiteMatchStates.find(ProfileLoc);
528 if (It == CallsiteMatchStates.end())
529 CallsiteMatchStates.try_emplace(ProfileLoc, MatchState::InitialMatch);
530 else if (IsPostMatch) {
531 if (It->second == MatchState::InitialMatch)
532 It->second = MatchState::UnchangedMatch;
533 else if (It->second == MatchState::InitialMismatch)
534 It->second = MatchState::RecoveredMismatch;
541 for (
const auto &
I : ProfileAnchors) {
542 const auto &Loc =
I.first;
543 assert(!
I.second.stringRef().empty() &&
"Callees should not be empty");
544 auto It = CallsiteMatchStates.find(Loc);
545 if (It == CallsiteMatchStates.end())
546 CallsiteMatchStates.try_emplace(Loc, MatchState::InitialMismatch);
547 else if (IsPostMatch) {
550 if (It->second == MatchState::InitialMismatch)
551 It->second = MatchState::UnchangedMismatch;
552 else if (It->second == MatchState::InitialMatch)
553 It->second = MatchState::RemovedMatch;
558void SampleProfileMatcher::countMismatchedFuncSamples(
const FunctionSamples &FS,
560 const auto *FuncDesc = ProbeManager->getDesc(
FS.getGUID());
565 if (ProbeManager->profileIsHashMismatched(*FuncDesc, FS)) {
567 NumStaleProfileFunc++;
572 MismatchedFunctionSamples +=
FS.getTotalSamples();
581 for (
const auto &
I :
FS.getCallsiteSamples())
582 for (
const auto &CS :
I.second)
583 countMismatchedFuncSamples(CS.second,
false);
586void SampleProfileMatcher::countMismatchedCallsiteSamples(
588 auto It = FuncCallsiteMatchStates.find(
FS.getFuncName());
590 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
592 const auto &CallsiteMatchStates = It->second;
594 auto findMatchState = [&](
const LineLocation &Loc) {
595 auto It = CallsiteMatchStates.find(Loc);
596 if (It == CallsiteMatchStates.end())
597 return MatchState::Unknown;
601 auto AttributeMismatchedSamples = [&](
const enum MatchState &State,
603 if (isMismatchState(State))
604 MismatchedCallsiteSamples += Samples;
605 else if (State == MatchState::RecoveredMismatch)
606 RecoveredCallsiteSamples += Samples;
611 for (
const auto &
I :
FS.getBodySamples())
612 AttributeMismatchedSamples(findMatchState(
I.first),
I.second.getSamples());
615 for (
const auto &
I :
FS.getCallsiteSamples()) {
616 auto State = findMatchState(
I.first);
617 uint64_t CallsiteSamples = 0;
618 for (
const auto &CS :
I.second)
619 CallsiteSamples += CS.second.getTotalSamples();
620 AttributeMismatchedSamples(State, CallsiteSamples);
622 if (isMismatchState(State))
628 for (
const auto &CS :
I.second)
629 countMismatchedCallsiteSamples(CS.second);
633void SampleProfileMatcher::countMismatchCallsites(
const FunctionSamples &FS) {
634 auto It = FuncCallsiteMatchStates.find(
FS.getFuncName());
636 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
638 const auto &MatchStates = It->second;
639 [[maybe_unused]]
bool OnInitialState =
640 isInitialState(MatchStates.begin()->second);
641 for (
const auto &
I : MatchStates) {
642 TotalProfiledCallsites++;
644 (OnInitialState ? isInitialState(
I.second) : isFinalState(
I.second)) &&
645 "Profile matching state is inconsistent");
647 if (isMismatchState(
I.second))
648 NumMismatchedCallsites++;
649 else if (
I.second == MatchState::RecoveredMismatch)
650 NumRecoveredCallsites++;
654void SampleProfileMatcher::countCallGraphRecoveredSamples(
657 if (CallGraphRecoveredProfiles.
count(
FS.getFunction())) {
658 NumCallGraphRecoveredFuncSamples +=
FS.getTotalSamples();
662 for (
const auto &CM :
FS.getCallsiteSamples()) {
663 for (
const auto &CS : CM.second) {
664 countCallGraphRecoveredSamples(CS.second, CallGraphRecoveredProfiles);
669void SampleProfileMatcher::computeAndReportProfileStaleness() {
673 DenseSet<FunctionId> CallGraphRecoveredProfiles;
675 for (
const auto &
I : FuncToProfileNameMap) {
676 CallGraphRecoveredProfiles.
insert(
I.second);
679 NumCallGraphRecoveredProfiledFunc++;
684 for (
const auto &
F : M) {
691 const auto *
FS = Reader.getSamplesFor(
F);
695 TotalFunctionSamples +=
FS->getTotalSamples();
698 countCallGraphRecoveredSamples(*FS, CallGraphRecoveredProfiles);
702 countMismatchedFuncSamples(*FS,
true);
705 countMismatchCallsites(*FS);
706 countMismatchedCallsiteSamples(*FS);
711 errs() <<
"(" << NumStaleProfileFunc <<
"/" << TotalProfiledFunc
712 <<
") of functions' profile are invalid and ("
713 << MismatchedFunctionSamples <<
"/" << TotalFunctionSamples
714 <<
") of samples are discarded due to function hash mismatch.\n";
717 errs() <<
"(" << NumCallGraphRecoveredProfiledFunc <<
"/"
718 << TotalProfiledFunc <<
") of functions' profile are matched and ("
719 << NumCallGraphRecoveredFuncSamples <<
"/" << TotalFunctionSamples
720 <<
") of samples are reused by call graph matching.\n";
723 errs() <<
"(" << (NumMismatchedCallsites + NumRecoveredCallsites) <<
"/"
724 << TotalProfiledCallsites
725 <<
") of callsites' profile are invalid and ("
726 << (MismatchedCallsiteSamples + RecoveredCallsiteSamples) <<
"/"
727 << TotalFunctionSamples
728 <<
") of samples are discarded due to callsite location mismatch.\n";
729 errs() <<
"(" << NumRecoveredCallsites <<
"/"
730 << (NumRecoveredCallsites + NumMismatchedCallsites)
731 <<
") of callsites and (" << RecoveredCallsiteSamples <<
"/"
732 << (RecoveredCallsiteSamples + MismatchedCallsiteSamples)
733 <<
") of samples are recovered by stale profile matching.\n";
737 LLVMContext &Ctx = M.getContext();
742 ProfStatsVec.
emplace_back(
"NumStaleProfileFunc", NumStaleProfileFunc);
743 ProfStatsVec.
emplace_back(
"TotalProfiledFunc", TotalProfiledFunc);
745 MismatchedFunctionSamples);
746 ProfStatsVec.
emplace_back(
"TotalFunctionSamples", TotalFunctionSamples);
750 ProfStatsVec.
emplace_back(
"NumCallGraphRecoveredProfiledFunc",
751 NumCallGraphRecoveredProfiledFunc);
752 ProfStatsVec.
emplace_back(
"NumCallGraphRecoveredFuncSamples",
753 NumCallGraphRecoveredFuncSamples);
756 ProfStatsVec.
emplace_back(
"NumMismatchedCallsites", NumMismatchedCallsites);
757 ProfStatsVec.
emplace_back(
"NumRecoveredCallsites", NumRecoveredCallsites);
758 ProfStatsVec.
emplace_back(
"TotalProfiledCallsites", TotalProfiledCallsites);
760 MismatchedCallsiteSamples);
762 RecoveredCallsiteSamples);
764 auto *MD = MDB.createLLVMStats(ProfStatsVec);
765 auto *NMD = M.getOrInsertNamedMetadata(
"llvm.stats");
770void SampleProfileMatcher::findFunctionsWithoutProfile() {
774 StringSet<> NamesInProfile;
775 for (FunctionId Name : Reader.getNameTable())
781 if (
F.isDeclaration())
785 const auto *
FS = getFlattenedSamplesFor(
F);
792 if (NamesInProfile.
count(CanonFName))
797 if (PSL && PSL->contains(CanonFName))
801 <<
" is not in profile or profile symbol list.\n");
802 FunctionsWithoutProfile[FunctionId(CanonFName)] = &
F;
810 auto FunctionName = FName.
str();
811 if (Demangler.partialDemangle(FunctionName.c_str()))
812 return std::string();
813 size_t BaseNameSize = 0;
817 char *BaseNamePtr = Demangler.getFunctionBaseName(
nullptr, &BaseNameSize);
818 std::string Result = (BaseNamePtr && BaseNameSize)
819 ? std::string(BaseNamePtr, BaseNameSize)
824 while (!Result.empty() && (Result.back() ==
' ' || Result.back() ==
'\0'))
829void SampleProfileMatcher::matchFunctionsWithoutProfileByBasename() {
832 auto NameTable = Reader.getNameTable();
833 if (NameTable.empty())
841 StringMap<Function *> OrphansByBaseName;
842 StringSet<> AmbiguousBaseNames;
843 for (
auto &[FuncId, Func] : FunctionsWithoutProfile) {
845 if (BaseName.empty() || AmbiguousBaseNames.
count(BaseName))
850 OrphansByBaseName.
erase(It);
851 AmbiguousBaseNames.
insert(BaseName);
854 if (OrphansByBaseName.
empty())
859 StringMap<FunctionId> CandidateByBaseName;
860 for (FunctionId ProfileFuncId : NameTable) {
861 StringRef ProfName = ProfileFuncId.stringRef();
862 if (ProfName.
empty())
866 if (ProfBaseName.empty())
869 if (OrphansByBaseName.
count(ProfBaseName)) {
870 if (AmbiguousBaseNames.
count(ProfBaseName))
874 CandidateByBaseName.
try_emplace(ProfBaseName, ProfileFuncId);
877 CandidateByBaseName.
erase(It);
878 AmbiguousBaseNames.
insert(ProfBaseName);
883 if (CandidateByBaseName.
empty())
887 DenseSet<StringRef> ToLoad;
888 for (
auto &[BaseName, ProfId] : CandidateByBaseName)
889 ToLoad.
insert(ProfId.stringRef());
892 unsigned MatchCount = 0;
893 SampleProfileMap NewlyLoadedProfiles;
894 for (
auto &[BaseName, ProfId] : CandidateByBaseName) {
895 if (!isProfileUnused(ProfId))
901 FuncToProfileNameMap[OrphanFunc] = ProfId;
902 MatchedAnchorCache[ProfId] = OrphanFunc;
903 if (
const auto *FS = Reader.getSamplesFor(ProfId.stringRef()))
907 <<
" (IR) -> " << ProfId <<
" (Profile)"
908 <<
" [basename: " << BaseName <<
"]\n");
913 if (!NewlyLoadedProfiles.empty())
917 NumDirectProfileMatch += MatchCount;
918 LLVM_DEBUG(
dbgs() <<
"Direct basename matching found " << MatchCount
922bool SampleProfileMatcher::functionMatchesProfileHelper(
926 float Similarity = 0.0;
933 if (!IRBaseName.empty() && IRBaseName == ProfBaseName) {
935 << ProfFunc <<
"(Profile) share the same base name: "
936 << IRBaseName <<
".\n");
940 const auto *FSForMatching = getFlattenedSamplesFor(ProfFunc);
947 DenseSet<StringRef> TopLevelFunc({ProfFunc.
stringRef()});
948 if (std::error_code EC = Reader.read(TopLevelFunc))
950 FSForMatching = Reader.getSamplesFor(ProfFunc.
stringRef());
955 SampleProfileMap TempProfiles;
956 TempProfiles.
create(FSForMatching->getFunction()).
merge(*FSForMatching);
959 FSForMatching = getFlattenedSamplesFor(ProfFunc);
963 dbgs() <<
"Read top-level function " << ProfFunc
964 <<
" for call-graph matching\n";
979 const auto *FuncDesc = ProbeManager->getDesc(IRFunc);
981 !ProbeManager->profileIsHashMismatched(*FuncDesc, *FSForMatching)) {
983 <<
"(IR) and " << ProfFunc <<
"(Profile) match.\n");
990 findIRAnchors(IRFunc, IRAnchors);
992 findProfileAnchors(*FSForMatching, ProfileAnchors);
996 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
997 FilteredProfileAnchorList);
1010 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
1013 Similarity =
static_cast<float>(MatchedAnchors.
size()) /
1014 FilteredProfileAnchorList.size();
1017 <<
"(IR) and " << ProfFunc <<
"(profile) is "
1018 <<
format(
"%.2f", Similarity) <<
"\n");
1019 assert((Similarity >= 0 && Similarity <= 1.0) &&
1020 "Similarity value should be in [0, 1]");
1026bool SampleProfileMatcher::functionMatchesProfile(
Function &IRFunc,
1028 bool FindMatchedProfileOnly) {
1029 auto R = FuncProfileMatchCache.find({&IRFunc, ProfFunc});
1030 if (R != FuncProfileMatchCache.end())
1033 if (FindMatchedProfileOnly)
1036 bool Matched = functionMatchesProfileHelper(IRFunc, ProfFunc);
1037 FuncProfileMatchCache[{&IRFunc, ProfFunc}] = Matched;
1039 FuncToProfileNameMap[&IRFunc] = ProfFunc;
1041 <<
" matches profile:" << ProfFunc <<
"\n");
1047void SampleProfileMatcher::UpdateWithSalvagedProfiles() {
1048 DenseSet<StringRef> ProfileSalvagedFuncs;
1050 for (
auto &
I : FuncToProfileNameMap) {
1051 assert(
I.first &&
"New function is null");
1052 FunctionId FuncName(
I.first->getName());
1053 ProfileSalvagedFuncs.
insert(
I.second.stringRef());
1054 FuncNameToProfNameMap->emplace(FuncName,
I.second);
1058 SymbolMap->erase(FuncName);
1059 [[maybe_unused]]
auto Ret = SymbolMap->emplace(
I.second,
I.first);
1062 dbgs() <<
"Profile Function " <<
I.second
1063 <<
" has already been matched to another IR function.\n";
1071 Reader.read(ProfileSalvagedFuncs);
1072 Reader.setFuncNameToProfNameMap(*FuncNameToProfNameMap);
1084 findFunctionsWithoutProfile();
1085 matchFunctionsWithoutProfileByBasename();
1090 std::vector<Function *> TopDownFunctionList;
1091 TopDownFunctionList.reserve(M.size());
1093 for (
auto *
F : TopDownFunctionList) {
1100 UpdateWithSalvagedProfiles();
1103 distributeIRToProfileLocationMap();
1105 computeAndReportProfileStaleness();
1108void SampleProfileMatcher::distributeIRToProfileLocationMap(
1110 const auto ProfileMappings = FuncMappings.find(FS.getFuncName());
1111 if (ProfileMappings != FuncMappings.end()) {
1112 FS.setIRToProfileLocationMap(&(ProfileMappings->second));
1115 for (
auto &Callees :
1117 for (
auto &FS : Callees.second) {
1118 distributeIRToProfileLocationMap(FS.second);
1125void SampleProfileMatcher::distributeIRToProfileLocationMap() {
1126 for (
auto &
I : Reader.getProfiles()) {
1127 distributeIRToProfileLocationMap(
I.second);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
itanium_demangle::ManglingParser< DefaultAllocator > Demangler
Legalize the Machine IR a function s Machine IR
static std::string getDemangledBaseName(ItaniumPartialDemangler &Demangler, StringRef FName)
This file provides the interface for SampleProfileMatcher.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
bool erase(const KeyT &Val)
std::pair< iterator, bool > insert_or_assign(const KeyT &Key, V &&Val)
Implements a dense probed hash-table based set.
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
LLVM_ABI void runOnModule()
reference emplace_back(ArgTypes &&... Args)
size_type count(StringRef Key) const
count - Return 1 if the element is in the map, 0 otherwise.
ValueTy lookup(StringRef Key) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
std::pair< iterator, bool > try_emplace(StringRef Key, ArgsTy &&...Args)
Emplace a new element for the specified key into the map if the key isn't already in the map.
Represent a constant reference to a string, i.e.
std::string str() const
Get the contents as an std::string.
constexpr bool empty() const
Check if the string is empty.
std::pair< typename Base::iterator, bool > insert(StringRef key)
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
This class represents a function that is read from a sample profile.
StringRef stringRef() const
Convert to StringRef.
bool isStringRef() const
Check if this object represents a StringRef, or a hash code.
Representation of the samples collected for a function.
static LLVM_ABI bool ProfileIsCS
static LLVM_ABI bool ProfileIsProbeBased
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
static LLVM_ABI bool ProfileIsFS
If this profile uses flow sensitive discriminators.
sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight=1)
Merge the samples in Other into this one.
void setContext(const SampleContext &FContext)
static LLVM_ABI LineLocation getCallSiteIdentifier(const DILocation *DIL, bool ProfileIsFS=false)
Returns a unique call site identifier for a given debug location of a call instruction.
static LLVM_ABI bool UseMD5
Whether the profile uses MD5 to represent string.
std::pair< iterator, bool > try_emplace(const key_type &Hash, const original_key_type &Key, Ts &&...Args)
static void flattenProfile(SampleProfileMap &ProfileMap, bool ProfileIsCS=false)
mapped_type & create(const SampleContext &Ctx)
@ C
The default llvm calling convention, compatible with C.
initializer< Ty > init(const Ty &Val)
NodeAddr< FuncNode * > Func
std::map< LineLocation, FunctionSamplesMap > CallsiteSampleMap
DenseMap< LineLocation, LineLocation > LocToLocMap
This is an optimization pass for GlobalISel generic memory operations.
cl::opt< bool > ReportProfileStaleness("report-profile-staleness", cl::Hidden, cl::init(false), cl::desc("Compute and report stale profile statistical metrics."))
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)."))
std::map< LineLocation, FunctionId > AnchorMap
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
static cl::opt< bool > LoadFuncProfileforCGMatching("load-func-profile-for-cg-matching", cl::Hidden, cl::init(true), cl::desc("Load top-level profiles that the sample reader initially skipped for " "the call-graph matching (only meaningful for extended binary " "format)"))
static cl::opt< unsigned > SalvageUnusedProfileMaxFunctions("salvage-unused-profile-max-functions", cl::Hidden, cl::init(UINT_MAX), cl::desc("The maximum number of functions in a module, above which salvage " "unused profile will be skipped."))
static void buildTopDownFuncOrder(LazyCallGraph &CG, std::vector< Function * > &FunctionOrderList)
@ ThinLTOPreLink
ThinLTO prelink (summary) phase.
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."))
LLVM_ABI std::optional< PseudoProbe > extractProbe(const Instruction &Inst)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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."))
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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."))
void longestCommonSequence(AnchorList AnchorList1, AnchorList AnchorList2, llvm::function_ref< bool(const Function &, const Function &)> FunctionMatchesProfile, llvm::function_ref< void(Loc, Loc)> InsertMatching)
std::vector< std::pair< LineLocation, FunctionId > > AnchorList
static bool skipProfileForFunction(const Function &F)
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."))
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 > 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."))