-
Notifications
You must be signed in to change notification settings - Fork 11.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SampleFDO] Stale profile call-graph matching #95135
Changes from 13 commits
622d78f
c7ada8b
183f6ae
6beddf2
7f38b7e
ae436dd
7cb0cd7
beaa601
c61ee03
81811c3
4bdda81
df77394
d001406
8fc8f54
ecc4000
da8b752
93d70fa
8c36fcc
dc4d4f9
c7ae1a9
7b458b4
15e8d0c
47c1816
82cf2a6
845ebe3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,6 +58,33 @@ class SampleProfileMatcher { | |
StringMap<std::unordered_map<LineLocation, MatchState, LineLocationHash>> | ||
FuncCallsiteMatchStates; | ||
|
||
struct FuncToProfileNameMapHash { | ||
uint64_t | ||
operator()(const std::pair<const Function *, FunctionId> &P) const { | ||
return hash_combine(P.first, P.second); | ||
} | ||
}; | ||
// A map from a pair of function and profile name to a boolean value | ||
// indicating whether they are matched. This is used as a cache for the | ||
// matching result. | ||
std::unordered_map<std::pair<const Function *, FunctionId>, bool, | ||
FuncToProfileNameMapHash> | ||
FuncToProfileNameMap; | ||
// The new functions found by the call graph matching. The map's key is the | ||
// old profile name and value is the new(renamed) function. | ||
HashKeyMap<std::unordered_map, FunctionId, Function *> ProfileNameToFuncMap; | ||
|
||
// A map pointer to the SymbolMap in the SampleProfileLoader, which stores all | ||
// the original matched symbols before the matching. this is to determine if | ||
// the profile is unused(to be matched) or not. | ||
HashKeyMap<std::unordered_map, FunctionId, Function *> *SymbolMap; | ||
|
||
// The new functions from IR. | ||
HashKeyMap<std::unordered_map, FunctionId, Function *> NewIRFunctions; | ||
|
||
// Pointer to the Profile Symbol List in the reader. | ||
std::shared_ptr<ProfileSymbolList> PSL; | ||
|
||
// Profile mismatch statstics: | ||
uint64_t TotalProfiledFunc = 0; | ||
// Num of checksum-mismatched function. | ||
|
@@ -72,34 +99,54 @@ class SampleProfileMatcher { | |
uint64_t MismatchedCallsiteSamples = 0; | ||
uint64_t RecoveredCallsiteSamples = 0; | ||
|
||
// Profile call-graph matching statstics: | ||
uint64_t NumRecoveredUnusedSamples = 0; | ||
uint64_t NumRecoveredUnusedFunc = 0; | ||
|
||
// A dummy name for unknown indirect callee, used to differentiate from a | ||
// non-call instruction that also has an empty callee name. | ||
static constexpr const char *UnknownIndirectCallee = | ||
"unknown.indirect.callee"; | ||
|
||
public: | ||
SampleProfileMatcher(Module &M, SampleProfileReader &Reader, | ||
const PseudoProbeManager *ProbeManager, | ||
ThinOrFullLTOPhase LTOPhase) | ||
: M(M), Reader(Reader), ProbeManager(ProbeManager), LTOPhase(LTOPhase){}; | ||
void runOnModule(); | ||
SampleProfileMatcher( | ||
Module &M, SampleProfileReader &Reader, | ||
const PseudoProbeManager *ProbeManager, ThinOrFullLTOPhase LTOPhase, | ||
HashKeyMap<std::unordered_map, FunctionId, Function *> &SymMap, | ||
std::shared_ptr<ProfileSymbolList> PSL) | ||
: M(M), Reader(Reader), ProbeManager(ProbeManager), LTOPhase(LTOPhase), | ||
SymbolMap(&SymMap), PSL(PSL) {}; | ||
void runOnModule(std::vector<Function *> &OrderedFuncList); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably better not to have We can have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, done.(that needs some refactoring to reuse the code from SampleLoader) |
||
void clearMatchingData() { | ||
// Do not clear FuncMappings, it stores IRLoc to ProfLoc remappings which | ||
// will be used for sample loader. | ||
FuncCallsiteMatchStates.clear(); | ||
FlattenedProfiles.clear(); | ||
|
||
NewIRFunctions.clear(); | ||
FuncToProfileNameMap.clear(); | ||
ProfileNameToFuncMap.clear(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clear doesn't free memory held by the container itself: https://en.cppreference.com/w/cpp/container/vector/clear To free memory, a common trick is to swap with empty container. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, changing to use |
||
} | ||
|
||
private: | ||
FunctionSamples *getFlattenedSamplesFor(const Function &F) { | ||
StringRef CanonFName = FunctionSamples::getCanonicalFnName(F); | ||
auto It = FlattenedProfiles.find(FunctionId(CanonFName)); | ||
FunctionSamples *getFlattenedSamplesFor(const FunctionId &Fname) { | ||
auto It = FlattenedProfiles.find(Fname); | ||
if (It != FlattenedProfiles.end()) | ||
return &It->second; | ||
return nullptr; | ||
} | ||
FunctionSamples *getFlattenedSamplesFor(const Function &F) { | ||
StringRef CanonFName = FunctionSamples::getCanonicalFnName(F); | ||
return getFlattenedSamplesFor(FunctionId(CanonFName)); | ||
} | ||
void getFilteredAnchorList(const AnchorMap &IRAnchors, | ||
const AnchorMap &ProfileAnchors, | ||
AnchorList &FilteredIRAnchorsList, | ||
AnchorList &FilteredProfileAnchorList); | ||
void runOnFunction(Function &F); | ||
void findIRAnchors(const Function &F, AnchorMap &IRAnchors); | ||
void findProfileAnchors(const FunctionSamples &FS, AnchorMap &ProfileAnchors); | ||
void findIRAnchors(const Function &F, AnchorMap &IRAnchors) const; | ||
void findProfileAnchors(const FunctionSamples &FS, | ||
AnchorMap &ProfileAnchors) const; | ||
// Record the callsite match states for profile staleness report, the result | ||
// is saved in FuncCallsiteMatchStates. | ||
void recordCallsiteMatchStates(const Function &F, const AnchorMap &IRAnchors, | ||
|
@@ -141,6 +188,12 @@ class SampleProfileMatcher { | |
} | ||
void distributeIRToProfileLocationMap(); | ||
void distributeIRToProfileLocationMap(FunctionSamples &FS); | ||
// Check if the two functions are equal. If FindMatchedProfileOnly is set, | ||
// only search the existing matched function. Otherwise, if the two functions | ||
// are both new, try to match the two functions. | ||
bool isFunctionEqual(const FunctionId &IRFuncName, | ||
const FunctionId &ProfileFuncName, | ||
bool FindMatchedProfileOnly); | ||
// This function implements the Myers diff algorithm used for stale profile | ||
// matching. The algorithm provides a simple and efficient way to find the | ||
// Longest Common Subsequence(LCS) or the Shortest Edit Script(SES) of two | ||
|
@@ -151,15 +204,32 @@ class SampleProfileMatcher { | |
// parts from the resulting SES are used to remap the IR locations to the | ||
// profile locations. As the number of function callsite is usually not big, | ||
// we currently just implements the basic greedy version(page 6 of the paper). | ||
LocToLocMap | ||
longestCommonSequence(const AnchorList &IRCallsiteAnchors, | ||
const AnchorList &ProfileCallsiteAnchors) const; | ||
LocToLocMap longestCommonSequence(const AnchorList &IRCallsiteAnchors, | ||
const AnchorList &ProfileCallsiteAnchors, | ||
bool MatchUnusedFunction); | ||
void matchNonCallsiteLocs(const LocToLocMap &AnchorMatchings, | ||
const AnchorMap &IRAnchors, | ||
LocToLocMap &IRToProfileLocationMap); | ||
void runStaleProfileMatching(const Function &F, const AnchorMap &IRAnchors, | ||
const AnchorMap &ProfileAnchors, | ||
LocToLocMap &IRToProfileLocationMap); | ||
LocToLocMap &IRToProfileLocationMap, | ||
bool RunCFGMatching, bool RunCGMatching); | ||
bool functionMatchesProfileHelper(const Function &IRFunc, | ||
const FunctionId &ProfFunc); | ||
// Determine if the function matches profile by computing a similarity ratio | ||
// between two callsite anchors extracted from function and profile. If it's | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: |
||
// above the threshold, the function matches the profile. | ||
bool functionMatchesProfile(Function &IRFunc, const FunctionId &ProfFunc, | ||
bool FindMatchedProfileOnly); | ||
void matchProfileForNewFunctions(const StringMap<Function *> &NewIRFunctions, | ||
FunctionSamples &FS); | ||
// Find functions that don't show in the profile or profile symbol list, | ||
// which are supposed to be new functions. We use them as the targets for | ||
// renaming matching. | ||
void findNewIRFunctions(); | ||
void updateProfillesAndSymbolMap(); | ||
wlei-llvm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
void updateProfileWithNewName(FunctionSamples &FuncProfile); | ||
void runCallGraphMatching(); | ||
void reportOrPersistProfileStats(); | ||
}; | ||
} // end namespace llvm | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the names above, how about:
NumCallGraphRecoveredProfiledFunc
NumCallGraphRecoveredFuncSamples