@@ -36,6 +36,13 @@ static cl::opt<unsigned> MinCallCountForCGMatching(
36
36
cl::desc(" The minimum number of call anchors required for a function to "
37
37
" run stale profile call graph matching." ));
38
38
39
+ static cl::opt<bool > LoadFuncProfileforCGMatching (
40
+ " load-func-profile-for-cg-matching" , cl::Hidden, cl::init(false ),
41
+ cl::desc(
42
+ " Load top-level profiles that the sample reader initially skipped for "
43
+ " the call-graph matching (only meaningful for extended binary "
44
+ " format)" ));
45
+
39
46
extern cl::opt<bool > SalvageStaleProfile;
40
47
extern cl::opt<bool > SalvageUnusedProfile;
41
48
extern cl::opt<bool > PersistProfileStaleness;
@@ -410,18 +417,19 @@ void SampleProfileMatcher::runOnFunction(Function &F) {
410
417
// callsites in one context may differ from those in another context. To get
411
418
// the maximum number of callsites, we merge the function profiles from all
412
419
// contexts, aka, the flattened profile to find profile anchors.
413
- const auto *FSFlattened = getFlattenedSamplesFor (F);
414
- if (SalvageUnusedProfile && !FSFlattened ) {
420
+ const auto *FSForMatching = getFlattenedSamplesFor (F);
421
+ if (SalvageUnusedProfile && !FSForMatching ) {
415
422
// Apply the matching in place to find the new function's matched profile.
416
- // TODO: For extended profile format, if a function profile is unused and
417
- // it's top-level, even if the profile is matched, it's not found in the
418
- // profile. This is because sample reader only read the used profile at the
419
- // beginning, we need to support loading the profile on-demand in future.
420
423
auto R = FuncToProfileNameMap.find (&F);
421
- if (R != FuncToProfileNameMap.end ())
422
- FSFlattened = getFlattenedSamplesFor (R->second );
424
+ if (R != FuncToProfileNameMap.end ()) {
425
+ FSForMatching = getFlattenedSamplesFor (R->second );
426
+ // Try to find the salvaged top-level profiles that are explicitly loaded
427
+ // for the matching, see "functionMatchesProfileHelper" for the details.
428
+ if (!FSForMatching && LoadFuncProfileforCGMatching)
429
+ FSForMatching = Reader.getSamplesFor (R->second .stringRef ());
430
+ }
423
431
}
424
- if (!FSFlattened )
432
+ if (!FSForMatching )
425
433
return ;
426
434
427
435
// Anchors for IR. It's a map from IR location to callee name, callee name is
@@ -432,7 +440,7 @@ void SampleProfileMatcher::runOnFunction(Function &F) {
432
440
// Anchors for profile. It's a map from callsite location to a set of callee
433
441
// name.
434
442
AnchorMap ProfileAnchors;
435
- findProfileAnchors (*FSFlattened , ProfileAnchors);
443
+ findProfileAnchors (*FSForMatching , ProfileAnchors);
436
444
437
445
// Compute the callsite match states for profile staleness report.
438
446
if (ReportProfileStaleness || PersistProfileStaleness)
@@ -443,7 +451,7 @@ void SampleProfileMatcher::runOnFunction(Function &F) {
443
451
// For probe-based profiles, run matching only when profile checksum is
444
452
// mismatched.
445
453
bool ChecksumMismatch = FunctionSamples::ProfileIsProbeBased &&
446
- !ProbeManager->profileIsValid (F, *FSFlattened );
454
+ !ProbeManager->profileIsValid (F, *FSForMatching );
447
455
bool RunCFGMatching =
448
456
!FunctionSamples::ProfileIsProbeBased || ChecksumMismatch;
449
457
bool RunCGMatching = SalvageUnusedProfile;
@@ -781,22 +789,38 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
781
789
// two sequences are.
782
790
float Similarity = 0.0 ;
783
791
784
- const auto *FSFlattened = getFlattenedSamplesFor (ProfFunc);
785
- if (!FSFlattened)
792
+ const auto *FSForMatching = getFlattenedSamplesFor (ProfFunc);
793
+ // With extbinary profile format, initial profile loading only reads profile
794
+ // based on current function names in the module.
795
+ // However, if a function is renamed, sample loader skips to load its original
796
+ // profile(which has a different name), we will miss this case. To address
797
+ // this, we load the top-level profile candidate explicitly for the matching.
798
+ if (!FSForMatching && LoadFuncProfileforCGMatching) {
799
+ DenseSet<StringRef> TopLevelFunc ({ProfFunc.stringRef ()});
800
+ if (std::error_code EC = Reader.read (TopLevelFunc))
801
+ return false ;
802
+ FSForMatching = Reader.getSamplesFor (ProfFunc.stringRef ());
803
+ LLVM_DEBUG ({
804
+ if (FSForMatching)
805
+ dbgs () << " Read top-level function " << ProfFunc
806
+ << " for call-graph matching\n " ;
807
+ });
808
+ }
809
+ if (!FSForMatching)
786
810
return false ;
787
811
// The check for similarity or checksum may not be reliable if the function is
788
812
// tiny, we use the number of basic block as a proxy for the function
789
813
// complexity and skip the matching if it's too small.
790
814
if (IRFunc.size () < MinFuncCountForCGMatching ||
791
- FSFlattened ->getBodySamples ().size () < MinFuncCountForCGMatching)
815
+ FSForMatching ->getBodySamples ().size () < MinFuncCountForCGMatching)
792
816
return false ;
793
817
794
818
// For probe-based function, we first trust the checksum info. If the checksum
795
819
// doesn't match, we continue checking for similarity.
796
820
if (FunctionSamples::ProfileIsProbeBased) {
797
821
const auto *FuncDesc = ProbeManager->getDesc (IRFunc);
798
822
if (FuncDesc &&
799
- !ProbeManager->profileIsHashMismatched (*FuncDesc, *FSFlattened )) {
823
+ !ProbeManager->profileIsHashMismatched (*FuncDesc, *FSForMatching )) {
800
824
LLVM_DEBUG (dbgs () << " The checksums for " << IRFunc.getName ()
801
825
<< " (IR) and " << ProfFunc << " (Profile) match.\n " );
802
826
@@ -807,7 +831,7 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
807
831
AnchorMap IRAnchors;
808
832
findIRAnchors (IRFunc, IRAnchors);
809
833
AnchorMap ProfileAnchors;
810
- findProfileAnchors (*FSFlattened , ProfileAnchors);
834
+ findProfileAnchors (*FSForMatching , ProfileAnchors);
811
835
812
836
AnchorList FilteredIRAnchorsList;
813
837
AnchorList FilteredProfileAnchorList;
@@ -863,6 +887,29 @@ bool SampleProfileMatcher::functionMatchesProfile(Function &IRFunc,
863
887
return Matched;
864
888
}
865
889
890
+ void SampleProfileMatcher::UpdateWithSalvagedProfiles () {
891
+ DenseSet<StringRef> ProfileSalvagedFuncs;
892
+ // Update FuncNameToProfNameMap and SymbolMap.
893
+ for (auto &I : FuncToProfileNameMap) {
894
+ assert (I.first && " New function is null" );
895
+ FunctionId FuncName (I.first ->getName ());
896
+ ProfileSalvagedFuncs.insert (I.second .stringRef ());
897
+ FuncNameToProfNameMap->emplace (FuncName, I.second );
898
+
899
+ // We need to remove the old entry to avoid duplicating the function
900
+ // processing.
901
+ SymbolMap->erase (FuncName);
902
+ SymbolMap->emplace (I.second , I.first );
903
+ }
904
+
905
+ // With extbinary profile format, initial profile loading only reads profile
906
+ // based on current function names in the module, so we need to load top-level
907
+ // profiles for functions with different profile name explicitly after
908
+ // function-profile name map is established with stale profile matching.
909
+ Reader.read (ProfileSalvagedFuncs);
910
+ Reader.setFuncNameToProfNameMap (*FuncNameToProfNameMap);
911
+ }
912
+
866
913
void SampleProfileMatcher::runOnModule () {
867
914
ProfileConverter::flattenProfile (Reader.getProfiles (), FlattenedProfiles,
868
915
FunctionSamples::ProfileIsCS);
@@ -880,17 +927,8 @@ void SampleProfileMatcher::runOnModule() {
880
927
runOnFunction (*F);
881
928
}
882
929
883
- // Update the data in SampleLoader.
884
930
if (SalvageUnusedProfile)
885
- for (auto &I : FuncToProfileNameMap) {
886
- assert (I.first && " New function is null" );
887
- FunctionId FuncName (I.first ->getName ());
888
- FuncNameToProfNameMap->emplace (FuncName, I.second );
889
- // We need to remove the old entry to avoid duplicating the function
890
- // processing.
891
- SymbolMap->erase (FuncName);
892
- SymbolMap->emplace (I.second , I.first );
893
- }
931
+ UpdateWithSalvagedProfiles ();
894
932
895
933
if (SalvageStaleProfile)
896
934
distributeIRToProfileLocationMap ();
0 commit comments