26#define DEBUG_TYPE "sample-profile-matcher"
29 "Number of functions matched by demangled basename");
36void SampleProfileMatcher::findIRAnchors(
const Function &
F,
41 auto FindTopLevelInlinedCallsite = [](
const DILocation *DIL) {
42 assert((DIL && DIL->getInlinedAt()) &&
"No inlined callsite");
43 const DILocation *PrevDIL =
nullptr;
46 DIL = DIL->getInlinedAt();
47 }
while (DIL->getInlinedAt());
51 StringRef CalleeName = PrevDIL->getSubprogramLinkageName();
52 return std::make_pair(Callsite, FunctionId(CalleeName));
55 auto GetCanonicalCalleeName = [](
const CallBase *CB) {
56 StringRef CalleeName = UnknownIndirectCallee;
57 if (
Function *Callee = CB->getCalledFunction())
65 DILocation *DIL =
I.getDebugLoc();
72 if (DIL->getInlinedAt()) {
73 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
80 CalleeName = GetCanonicalCalleeName(CB);
82 LineLocation Loc = LineLocation(Probe->Id, 0);
83 IRAnchors.emplace(Loc, FunctionId(CalleeName));
93 if (DIL->getInlinedAt()) {
94 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
99 IRAnchors.emplace(Callsite, FunctionId(CalleeName));
106void SampleProfileMatcher::findProfileAnchors(
const FunctionSamples &FS,
108 auto isInvalidLineOffset = [](uint32_t LineOffset) {
109 return LineOffset & 0x8000;
112 auto InsertAnchor = [](
const LineLocation &Loc,
const FunctionId &CalleeName,
114 auto Ret = ProfileAnchors.try_emplace(Loc, CalleeName);
118 Ret.first->second = FunctionId(UnknownIndirectCallee);
122 for (
const auto &
I :
FS.getBodySamples()) {
123 const LineLocation &Loc =
I.first;
127 const auto &CallTargets =
I.second.getCallTargets();
128 const bool HasSampledTarget =
129 llvm::any_of(CallTargets, [](
const auto &
C) {
return C.second != 0; });
130 for (
const auto &
C : CallTargets) {
134 if (HasSampledTarget &&
C.second == 0)
136 InsertAnchor(Loc,
C.first, ProfileAnchors);
140 for (
const auto &
I :
FS.getCallsiteSamples()) {
141 const LineLocation &Loc =
I.first;
145 const auto &Callees =
I.second;
147 Callees, [](
const auto &
C) {
return C.second.getTotalSamples() != 0; });
148 for (
const auto &
C : Callees) {
151 if (HasSampledCallee &&
C.second.getTotalSamples() == 0)
153 InsertAnchor(Loc,
C.first, ProfileAnchors);
158bool SampleProfileMatcher::anchorsMatch(
const FunctionId &IRAnchor,
166 return IRAnchor == ProfileAnchor ||
167 IRAnchor == FunctionId(UnknownIndirectCallee);
170bool SampleProfileMatcher::functionHasProfile(
const FunctionId &IRFuncName,
172 FuncWithoutProfile =
nullptr;
173 auto R = FunctionsWithoutProfile.find(IRFuncName);
174 if (R != FunctionsWithoutProfile.end())
175 FuncWithoutProfile =
R->second;
176 return !FuncWithoutProfile;
179bool SampleProfileMatcher::isProfileUnused(
const FunctionId &ProfileFuncName) {
182 return (SymbolMap->find(ProfileFuncName) == SymbolMap->end()) &&
186 (ProbeManager->getDesc(ProfileFuncName.
stringRef()) ==
nullptr));
189bool SampleProfileMatcher::functionMatchesProfile(
191 bool FindMatchedProfileOnly) {
192 if (IRFuncName == ProfileFuncName)
194 if (!SalvageUnusedProfile)
200 if (functionHasProfile(IRFuncName, IRFunc) ||
201 !isProfileUnused(ProfileFuncName))
205 "IR function should be different from profile function to match");
206 return functionMatchesProfile(*IRFunc, ProfileFuncName,
207 FindMatchedProfileOnly);
211SampleProfileMatcher::longestCommonSequence(
const AnchorList &AnchorList1,
213 bool MatchUnusedFunction) {
216 AnchorList1, AnchorList2,
217 [&](
const FunctionId &
A,
const FunctionId &
B) {
218 return functionMatchesProfile(
223 [&](LineLocation
A, LineLocation
B) {
226 return MatchedAnchors;
229void SampleProfileMatcher::matchNonCallsiteLocs(
232 auto UpdateMatching = [&](
const LineLocation &From,
const LineLocation &To) {
237 IRToProfileLocationMap.
erase(From);
241 int32_t LocationDelta = 0;
243 for (
const auto &
IR : IRAnchors) {
244 const auto &Loc =
IR.first;
245 bool IsMatchedAnchor =
false;
247 auto R = MatchedAnchors.
find(Loc);
248 if (R != MatchedAnchors.
end()) {
249 const auto &Candidate =
R->second;
250 UpdateMatching(Loc, Candidate);
252 <<
" is matched from " << Loc <<
" to " << Candidate
254 LocationDelta = Candidate.LineOffset - Loc.
LineOffset;
260 for (
size_t I = (LastMatchedNonAnchors.
size() + 1) / 2;
261 I < LastMatchedNonAnchors.
size();
I++) {
262 const auto &
L = LastMatchedNonAnchors[
I];
263 uint32_t CandidateLineOffset =
L.LineOffset + LocationDelta;
264 LineLocation Candidate(CandidateLineOffset,
L.Discriminator);
265 UpdateMatching(L, Candidate);
267 <<
" to " << Candidate <<
"\n");
270 IsMatchedAnchor =
true;
271 LastMatchedNonAnchors.
clear();
275 if (!IsMatchedAnchor) {
276 uint32_t CandidateLineOffset = Loc.
LineOffset + LocationDelta;
277 LineLocation Candidate(CandidateLineOffset, Loc.
Discriminator);
278 UpdateMatching(Loc, Candidate);
280 << Candidate <<
"\n");
288void SampleProfileMatcher::getFilteredAnchorList(
291 for (
const auto &
I : IRAnchors) {
292 if (
I.second.stringRef().empty())
294 FilteredIRAnchorsList.emplace_back(
I);
297 for (
const auto &
I : ProfileAnchors)
298 FilteredProfileAnchorList.emplace_back(
I);
318void SampleProfileMatcher::runStaleProfileMatching(
321 bool RunCFGMatching,
bool RunCGMatching) {
322 if (!RunCFGMatching && !RunCGMatching)
327 "Run stale profile matching only once per function");
331 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
332 FilteredProfileAnchorList);
334 if (FilteredIRAnchorsList.empty() || FilteredProfileAnchorList.empty())
337 if (FilteredIRAnchorsList.size() > Opts.salvage_stale_profile_max_callsites ||
338 FilteredProfileAnchorList.size() >
339 Opts.salvage_stale_profile_max_callsites) {
341 <<
" because the number of callsites in the IR is "
342 << FilteredIRAnchorsList.size()
343 <<
" and in the profile is "
344 << FilteredProfileAnchorList.size() <<
"\n");
359 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
366 for (
const auto &
IR : IRAnchors) {
367 bool ProfileConflicted =
false;
368 const auto &Loc =
IR.first;
372 FunctionId ProfAnchor;
373 auto AnchorLoc = MatchedAnchors.
find(Loc);
374 if (AnchorLoc == MatchedAnchors.
end()) {
377 auto PreMatched = FuncToProfileNameMap.find(Callee);
378 if (PreMatched == FuncToProfileNameMap.end())
380 ProfAnchor = PreMatched->second;
382 const auto &Prof = ProfileAnchors.find(AnchorLoc->second);
383 if (Prof == ProfileAnchors.end())
385 ProfAnchor = Prof->second;
389 auto Cached = MatchedAnchorCache.find(ProfAnchor);
390 if (Cached == MatchedAnchorCache.end())
391 MatchedAnchorCache[ProfAnchor] =
Callee;
392 else if (Cached->second != Callee)
393 ProfileConflicted =
true;
395 if (ProfileConflicted) {
398 const auto *FSForMatching = getFlattenedSamplesFor(ProfAnchor);
400 FSForMatching = Reader.getSamplesFor(ProfAnchor.
stringRef());
404 FunctionId NewAnchor(
406 auto R = FuncProfileMatchCache.find({
Callee, NewAnchor});
407 if (R != FuncProfileMatchCache.end() &&
R->second)
409 FunctionSamples &NewFS = FlattenedProfiles.create(NewAnchor);
410 NewFS.
merge(*FSForMatching);
411 FuncToProfileNameMap[
Callee] = NewAnchor;
412 FuncProfileMatchCache[{
Callee, NewAnchor}] =
true;
415 SampleProfileMap &Profiles = Reader.getProfiles();
416 SampleContext FContext(NewAnchor);
417 auto Res = Profiles.
try_emplace(FContext.getHashCode(), FContext, NewFS);
418 FunctionSamples &FProfile = Res.first->second;
428 matchNonCallsiteLocs(MatchedAnchors, IRAnchors, IRToProfileLocationMap);
431void SampleProfileMatcher::runOnFunction(
Function &
F) {
438 const auto *FSForMatching = getFlattenedSamplesFor(
F);
439 if (SalvageUnusedProfile && !FSForMatching) {
441 auto R = FuncToProfileNameMap.find(&
F);
442 if (R != FuncToProfileNameMap.end()) {
443 FSForMatching = getFlattenedSamplesFor(
R->second);
447 if (!FSForMatching && Opts.load_func_profile_for_cg_matching)
448 FSForMatching = Reader.getSamplesFor(
R->second.stringRef());
458 findIRAnchors(
F, IRAnchors);
462 findProfileAnchors(*FSForMatching, ProfileAnchors);
465 if (Opts.report_profile_staleness || Opts.persist_profile_staleness)
466 recordCallsiteMatchStates(
F, IRAnchors, ProfileAnchors,
nullptr);
468 if (!SalvageStaleProfile)
473 !ProbeManager->profileIsValid(
F, *FSForMatching);
474 bool RunCFGMatching =
476 bool RunCGMatching = SalvageUnusedProfile;
482 F.addFnAttr(
"profile-checksum-mismatch");
486 auto &IRToProfileLocationMap = getIRToProfileLocationMap(*FSForMatching);
487 runStaleProfileMatching(
F, IRAnchors, ProfileAnchors, IRToProfileLocationMap,
488 RunCFGMatching, RunCGMatching);
490 if (RunCFGMatching &&
491 (Opts.report_profile_staleness || Opts.persist_profile_staleness))
492 recordCallsiteMatchStates(
F, IRAnchors, ProfileAnchors,
493 &IRToProfileLocationMap);
496void SampleProfileMatcher::recordCallsiteMatchStates(
500 bool IsPostMatch = IRToProfileLocationMap !=
nullptr;
501 auto &CallsiteMatchStates =
504 auto MapIRLocToProfileLoc = [&](
const LineLocation &IRLoc) {
506 if (!IRToProfileLocationMap)
508 const auto &ProfileLoc = IRToProfileLocationMap->
find(IRLoc);
509 if (ProfileLoc != IRToProfileLocationMap->
end())
510 return ProfileLoc->second;
515 for (
const auto &
I : IRAnchors) {
518 const auto &ProfileLoc = MapIRLocToProfileLoc(
I.first);
519 const auto &IRCalleeId =
I.second;
520 const auto &It = ProfileAnchors.find(ProfileLoc);
521 if (It == ProfileAnchors.end())
523 const auto &ProfCalleeId = It->second;
524 if (anchorsMatch(IRCalleeId, ProfCalleeId)) {
525 auto It = CallsiteMatchStates.find(ProfileLoc);
526 if (It == CallsiteMatchStates.end())
527 CallsiteMatchStates.try_emplace(ProfileLoc, MatchState::InitialMatch);
528 else if (IsPostMatch) {
529 if (It->second == MatchState::InitialMatch)
530 It->second = MatchState::UnchangedMatch;
531 else if (It->second == MatchState::InitialMismatch)
532 It->second = MatchState::RecoveredMismatch;
539 for (
const auto &
I : ProfileAnchors) {
540 const auto &Loc =
I.first;
541 assert(!
I.second.stringRef().empty() &&
"Callees should not be empty");
542 auto It = CallsiteMatchStates.find(Loc);
543 if (It == CallsiteMatchStates.end())
544 CallsiteMatchStates.try_emplace(Loc, MatchState::InitialMismatch);
545 else if (IsPostMatch) {
548 if (It->second == MatchState::InitialMismatch)
549 It->second = MatchState::UnchangedMismatch;
550 else if (It->second == MatchState::InitialMatch)
551 It->second = MatchState::RemovedMatch;
556void SampleProfileMatcher::countMismatchedFuncSamples(
const FunctionSamples &FS,
558 const auto *FuncDesc = ProbeManager->getDesc(
FS.getGUID());
563 if (ProbeManager->profileIsHashMismatched(*FuncDesc, FS)) {
565 NumStaleProfileFunc++;
570 MismatchedFunctionSamples +=
FS.getTotalSamples();
579 for (
const auto &
I :
FS.getCallsiteSamples())
580 for (
const auto &CS :
I.second)
581 countMismatchedFuncSamples(CS.second,
false);
584void SampleProfileMatcher::countMismatchedCallsiteSamples(
586 auto It = FuncCallsiteMatchStates.find(
FS.getFuncName());
588 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
590 const auto &CallsiteMatchStates = It->second;
592 auto findMatchState = [&](
const LineLocation &Loc) {
593 auto It = CallsiteMatchStates.find(Loc);
594 if (It == CallsiteMatchStates.end())
595 return MatchState::Unknown;
599 auto AttributeMismatchedSamples = [&](
const enum MatchState &State,
601 if (isMismatchState(State))
602 MismatchedCallsiteSamples += Samples;
603 else if (State == MatchState::RecoveredMismatch)
604 RecoveredCallsiteSamples += Samples;
609 for (
const auto &
I :
FS.getBodySamples())
610 AttributeMismatchedSamples(findMatchState(
I.first),
I.second.getSamples());
613 for (
const auto &
I :
FS.getCallsiteSamples()) {
614 auto State = findMatchState(
I.first);
616 for (
const auto &CS :
I.second)
617 CallsiteSamples += CS.second.getTotalSamples();
618 AttributeMismatchedSamples(State, CallsiteSamples);
620 if (isMismatchState(State))
626 for (
const auto &CS :
I.second)
627 countMismatchedCallsiteSamples(CS.second);
631void SampleProfileMatcher::countMismatchCallsites(
const FunctionSamples &FS) {
632 auto It = FuncCallsiteMatchStates.find(
FS.getFuncName());
634 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
636 const auto &MatchStates = It->second;
637 [[maybe_unused]]
bool OnInitialState =
638 isInitialState(MatchStates.begin()->second);
639 for (
const auto &
I : MatchStates) {
640 TotalProfiledCallsites++;
642 (OnInitialState ? isInitialState(
I.second) : isFinalState(
I.second)) &&
643 "Profile matching state is inconsistent");
645 if (isMismatchState(
I.second))
646 NumMismatchedCallsites++;
647 else if (
I.second == MatchState::RecoveredMismatch)
648 NumRecoveredCallsites++;
652void SampleProfileMatcher::countCallGraphRecoveredSamples(
655 if (CallGraphRecoveredProfiles.
count(
FS.getFunction())) {
656 NumCallGraphRecoveredFuncSamples +=
FS.getTotalSamples();
660 for (
const auto &CM :
FS.getCallsiteSamples()) {
661 for (
const auto &CS : CM.second) {
662 countCallGraphRecoveredSamples(CS.second, CallGraphRecoveredProfiles);
667void SampleProfileMatcher::computeAndReportProfileStaleness() {
668 if (!Opts.report_profile_staleness && !Opts.persist_profile_staleness)
671 DenseSet<FunctionId> CallGraphRecoveredProfiles;
672 if (SalvageUnusedProfile) {
673 for (
const auto &
I : FuncToProfileNameMap) {
674 CallGraphRecoveredProfiles.
insert(
I.second);
677 NumCallGraphRecoveredProfiledFunc++;
682 for (
const auto &
F : M) {
689 const auto *
FS = Reader.getSamplesFor(
F);
693 TotalFunctionSamples +=
FS->getTotalSamples();
695 if (SalvageUnusedProfile && !CallGraphRecoveredProfiles.
empty())
696 countCallGraphRecoveredSamples(*FS, CallGraphRecoveredProfiles);
700 countMismatchedFuncSamples(*FS,
true);
703 countMismatchCallsites(*FS);
704 countMismatchedCallsiteSamples(*FS);
707 if (Opts.report_profile_staleness) {
709 errs() <<
"(" << NumStaleProfileFunc <<
"/" << TotalProfiledFunc
710 <<
") of functions' profile are invalid and ("
711 << MismatchedFunctionSamples <<
"/" << TotalFunctionSamples
712 <<
") of samples are discarded due to function hash mismatch.\n";
714 if (SalvageUnusedProfile) {
715 errs() <<
"(" << NumCallGraphRecoveredProfiledFunc <<
"/"
716 << TotalProfiledFunc <<
") of functions' profile are matched and ("
717 << NumCallGraphRecoveredFuncSamples <<
"/" << TotalFunctionSamples
718 <<
") of samples are reused by call graph matching.\n";
721 errs() <<
"(" << (NumMismatchedCallsites + NumRecoveredCallsites) <<
"/"
722 << TotalProfiledCallsites
723 <<
") of callsites' profile are invalid and ("
724 << (MismatchedCallsiteSamples + RecoveredCallsiteSamples) <<
"/"
725 << TotalFunctionSamples
726 <<
") of samples are discarded due to callsite location mismatch.\n";
727 errs() <<
"(" << NumRecoveredCallsites <<
"/"
728 << (NumRecoveredCallsites + NumMismatchedCallsites)
729 <<
") of callsites and (" << RecoveredCallsiteSamples <<
"/"
730 << (RecoveredCallsiteSamples + MismatchedCallsiteSamples)
731 <<
") of samples are recovered by stale profile matching.\n";
734 if (Opts.persist_profile_staleness) {
735 LLVMContext &Ctx = M.getContext();
740 ProfStatsVec.
emplace_back(
"NumStaleProfileFunc", NumStaleProfileFunc);
741 ProfStatsVec.
emplace_back(
"TotalProfiledFunc", TotalProfiledFunc);
743 MismatchedFunctionSamples);
744 ProfStatsVec.
emplace_back(
"TotalFunctionSamples", TotalFunctionSamples);
747 if (SalvageUnusedProfile) {
748 ProfStatsVec.
emplace_back(
"NumCallGraphRecoveredProfiledFunc",
749 NumCallGraphRecoveredProfiledFunc);
750 ProfStatsVec.
emplace_back(
"NumCallGraphRecoveredFuncSamples",
751 NumCallGraphRecoveredFuncSamples);
754 ProfStatsVec.
emplace_back(
"NumMismatchedCallsites", NumMismatchedCallsites);
755 ProfStatsVec.
emplace_back(
"NumRecoveredCallsites", NumRecoveredCallsites);
756 ProfStatsVec.
emplace_back(
"TotalProfiledCallsites", TotalProfiledCallsites);
758 MismatchedCallsiteSamples);
760 RecoveredCallsiteSamples);
762 auto *MD = MDB.createLLVMStats(ProfStatsVec);
763 auto *NMD = M.getOrInsertNamedMetadata(
"llvm.stats");
768void SampleProfileMatcher::findFunctionsWithoutProfile() {
776 if (
F.isDeclaration())
780 const auto *
FS = getFlattenedSamplesFor(
F);
787 if (Reader.contains(CanonFName))
792 if (PSL && PSL->contains(CanonFName))
796 <<
" is not in profile or profile symbol list.\n");
797 FunctionsWithoutProfile[FunctionId(CanonFName)] = &
F;
805 auto FunctionName = FName.
str();
806 if (Demangler.partialDemangle(FunctionName.c_str()))
807 return std::string();
808 size_t BaseNameSize = 0;
812 char *BaseNamePtr = Demangler.getFunctionBaseName(
nullptr, &BaseNameSize);
813 std::string Result = (BaseNamePtr && BaseNameSize)
814 ? std::string(BaseNamePtr, BaseNameSize)
819 while (!Result.empty() && (Result.back() ==
' ' || Result.back() ==
'\0'))
824void SampleProfileMatcher::matchFunctionsWithoutProfileByBasename() {
825 if (FunctionsWithoutProfile.empty() ||
826 !Opts.load_func_profile_for_cg_matching)
828 auto NameTable = Reader.getNameTable();
829 if (NameTable.empty())
837 StringMap<Function *> OrphansByBaseName;
838 StringSet<> AmbiguousBaseNames;
839 for (
auto &[FuncId, Func] : FunctionsWithoutProfile) {
841 if (BaseName.empty() || AmbiguousBaseNames.
count(BaseName))
846 OrphansByBaseName.
erase(It);
847 AmbiguousBaseNames.
insert(BaseName);
850 if (OrphansByBaseName.
empty())
855 StringMap<FunctionId> CandidateByBaseName;
856 for (FunctionId ProfileFuncId : NameTable) {
857 StringRef ProfName = ProfileFuncId.stringRef();
858 if (ProfName.
empty())
862 if (ProfBaseName.empty())
865 if (OrphansByBaseName.
count(ProfBaseName)) {
866 if (AmbiguousBaseNames.
count(ProfBaseName))
870 CandidateByBaseName.
try_emplace(ProfBaseName, ProfileFuncId);
873 CandidateByBaseName.
erase(It);
874 AmbiguousBaseNames.
insert(ProfBaseName);
879 if (CandidateByBaseName.
empty())
883 DenseSet<StringRef> ToLoad;
884 for (
auto &[BaseName, ProfId] : CandidateByBaseName)
885 ToLoad.
insert(ProfId.stringRef());
888 unsigned MatchCount = 0;
889 SampleProfileMap NewlyLoadedProfiles;
890 for (
auto &[BaseName, ProfId] : CandidateByBaseName) {
891 if (!isProfileUnused(ProfId))
897 FuncToProfileNameMap[OrphanFunc] = ProfId;
898 MatchedAnchorCache[ProfId] = OrphanFunc;
899 if (
const auto *FS = Reader.getSamplesFor(ProfId.stringRef()))
903 <<
" (IR) -> " << ProfId <<
" (Profile)"
904 <<
" [basename: " << BaseName <<
"]\n");
909 if (!NewlyLoadedProfiles.empty())
913 NumDirectProfileMatch += MatchCount;
914 LLVM_DEBUG(
dbgs() <<
"Direct basename matching found " << MatchCount
918bool SampleProfileMatcher::functionMatchesProfileHelper(
922 float Similarity = 0.0;
929 if (!IRBaseName.empty() && IRBaseName == ProfBaseName) {
931 << ProfFunc <<
"(Profile) share the same base name: "
932 << IRBaseName <<
".\n");
936 const auto *FSForMatching = getFlattenedSamplesFor(ProfFunc);
942 if (!FSForMatching && Opts.load_func_profile_for_cg_matching) {
943 DenseSet<StringRef> TopLevelFunc({ProfFunc.
stringRef()});
944 if (std::error_code EC = Reader.read(TopLevelFunc))
946 FSForMatching = Reader.getSamplesFor(ProfFunc.
stringRef());
951 SampleProfileMap TempProfiles;
952 TempProfiles.
create(FSForMatching->getFunction()).
merge(*FSForMatching);
955 FSForMatching = getFlattenedSamplesFor(ProfFunc);
959 dbgs() <<
"Read top-level function " << ProfFunc
960 <<
" for call-graph matching\n";
968 if (IRFunc.
size() < Opts.min_func_count_for_cg_matching ||
969 FSForMatching->getBodySamples().size() <
970 Opts.min_func_count_for_cg_matching)
976 const auto *FuncDesc = ProbeManager->getDesc(IRFunc);
978 !ProbeManager->profileIsHashMismatched(*FuncDesc, *FSForMatching)) {
980 <<
"(IR) and " << ProfFunc <<
"(Profile) match.\n");
987 findIRAnchors(IRFunc, IRAnchors);
989 findProfileAnchors(*FSForMatching, ProfileAnchors);
993 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
994 FilteredProfileAnchorList);
997 if (FilteredIRAnchorsList.size() < Opts.min_call_count_for_cg_matching ||
998 FilteredProfileAnchorList.size() < Opts.min_call_count_for_cg_matching)
1007 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
1010 Similarity =
static_cast<float>(MatchedAnchors.
size()) /
1011 FilteredProfileAnchorList.size();
1014 <<
"(IR) and " << ProfFunc <<
"(profile) is "
1015 <<
format(
"%.2f", Similarity) <<
"\n");
1016 assert((Similarity >= 0 && Similarity <= 1.0) &&
1017 "Similarity value should be in [0, 1]");
1018 return Similarity * 100 > Opts.func_profile_similarity_threshold;
1023bool SampleProfileMatcher::functionMatchesProfile(
Function &IRFunc,
1025 bool FindMatchedProfileOnly) {
1026 auto R = FuncProfileMatchCache.find({&IRFunc, ProfFunc});
1027 if (R != FuncProfileMatchCache.end())
1030 if (FindMatchedProfileOnly)
1033 bool Matched = functionMatchesProfileHelper(IRFunc, ProfFunc);
1034 FuncProfileMatchCache[{&IRFunc, ProfFunc}] = Matched;
1036 FuncToProfileNameMap[&IRFunc] = ProfFunc;
1038 <<
" matches profile:" << ProfFunc <<
"\n");
1044void SampleProfileMatcher::UpdateWithSalvagedProfiles() {
1045 DenseSet<StringRef> ProfileSalvagedFuncs;
1047 for (
auto &
I : FuncToProfileNameMap) {
1048 assert(
I.first &&
"New function is null");
1049 FunctionId FuncName(
I.first->getName());
1050 ProfileSalvagedFuncs.
insert(
I.second.stringRef());
1051 FuncNameToProfNameMap->emplace(FuncName,
I.second);
1055 SymbolMap->erase(FuncName);
1056 [[maybe_unused]]
auto Ret = SymbolMap->emplace(
I.second,
I.first);
1059 dbgs() <<
"Profile Function " <<
I.second
1060 <<
" has already been matched to another IR function.\n";
1068 Reader.read(ProfileSalvagedFuncs);
1069 Reader.setFuncNameToProfNameMap(*FuncNameToProfNameMap);
1077 SalvageUnusedProfile = SalvageUnusedProfile &&
1078 M.size() < Opts.salvage_unused_profile_max_functions;
1080 if (SalvageUnusedProfile) {
1081 findFunctionsWithoutProfile();
1082 matchFunctionsWithoutProfileByBasename();
1087 std::vector<Function *> TopDownFunctionList;
1088 TopDownFunctionList.reserve(M.size());
1090 for (
auto *
F : TopDownFunctionList) {
1096 if (SalvageUnusedProfile)
1097 UpdateWithSalvagedProfiles();
1099 if (SalvageStaleProfile)
1100 distributeIRToProfileLocationMap();
1102 computeAndReportProfileStaleness();
1105void SampleProfileMatcher::distributeIRToProfileLocationMap(
1107 const auto ProfileMappings = FuncMappings.find(FS.getFuncName());
1108 if (ProfileMappings != FuncMappings.end()) {
1109 FS.setIRToProfileLocationMap(&(ProfileMappings->second));
1112 for (
auto &Callees :
1114 for (
auto &FS : Callees.second) {
1115 distributeIRToProfileLocationMap(FS.second);
1122void SampleProfileMatcher::distributeIRToProfileLocationMap() {
1123 for (
auto &
I : Reader.getProfiles()) {
1124 distributeIRToProfileLocationMap(
I.second);
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< 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 > insert_or_assign(const KeyT &Key, V &&Val)
bool erase(const KeyT &Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
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 std::atomic< bool > ProfileIsFS
If this profile uses flow sensitive discriminators.
static LLVM_ABI std::atomic< bool > UseMD5
Whether the profile uses MD5 to represent string.
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
static LLVM_ABI std::atomic< bool > ProfileIsProbeBased
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 std::atomic< bool > ProfileIsCS
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.
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)
NodeAddr< FuncNode * > Func
std::map< LineLocation, FunctionSamplesMap > CallsiteSampleMap
DenseMap< LineLocation, LineLocation > LocToLocMap
This is an optimization pass for GlobalISel generic memory operations.
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 void buildTopDownFuncOrder(LazyCallGraph &CG, std::vector< Function * > &FunctionOrderList)
@ ThinLTOPreLink
ThinLTO prelink (summary) phase.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
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.
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.
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)