LLVM 20.0.0git
SampleProfileMatcher.h
Go to the documentation of this file.
1//===- Transforms/IPO/SampleProfileMatcher.h ----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This file provides the interface for SampleProfileMatcher.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_TRANSFORMS_IPO_SAMPLEPROFILEMATCHER_H
15#define LLVM_TRANSFORMS_IPO_SAMPLEPROFILEMATCHER_H
16
17#include "llvm/ADT/StringSet.h"
19
20namespace llvm {
21
22using AnchorList = std::vector<std::pair<LineLocation, FunctionId>>;
23using AnchorMap = std::map<LineLocation, FunctionId>;
24
25// Sample profile matching - fuzzy match.
27 Module &M;
28 SampleProfileReader &Reader;
29 LazyCallGraph &CG;
30 const PseudoProbeManager *ProbeManager;
31 const ThinOrFullLTOPhase LTOPhase;
32 SampleProfileMap FlattenedProfiles;
33 // For each function, the matcher generates a map, of which each entry is a
34 // mapping from the source location of current build to the source location
35 // in the profile.
36 StringMap<LocToLocMap> FuncMappings;
37
38 // Match state for an anchor/callsite.
39 enum class MatchState {
40 Unknown = 0,
41 // Initial match between input profile and current IR.
42 InitialMatch = 1,
43 // Initial mismatch between input profile and current IR.
44 InitialMismatch = 2,
45 // InitialMatch stays matched after fuzzy profile matching.
46 UnchangedMatch = 3,
47 // InitialMismatch stays mismatched after fuzzy profile matching.
48 UnchangedMismatch = 4,
49 // InitialMismatch is recovered after fuzzy profile matching.
50 RecoveredMismatch = 5,
51 // InitialMatch is removed and becomes mismatched after fuzzy profile
52 // matching.
53 RemovedMatch = 6,
54 };
55
56 // For each function, store every callsite and its matching state into this
57 // map, of which each entry is a pair of callsite location and MatchState.
58 // This is used for profile staleness computation and report.
60 FuncCallsiteMatchStates;
61
62 struct FuncToProfileNameMapHash {
64 operator()(const std::pair<const Function *, FunctionId> &P) const {
65 return hash_combine(P.first, P.second);
66 }
67 };
68 // A map from a pair of function and profile name to a boolean value
69 // indicating whether they are matched. This is used as a cache for the
70 // matching result.
71 std::unordered_map<std::pair<const Function *, FunctionId>, bool,
72 FuncToProfileNameMapHash>
73 FuncProfileMatchCache;
74 // The new functions found by the call graph matching. The map's key is the
75 // the new(renamed) function pointer and the value is old(unused) profile
76 // name.
77 std::unordered_map<Function *, FunctionId> FuncToProfileNameMap;
78
79 // A map pointer to the FuncNameToProfNameMap in SampleProfileLoader,
80 // which maps the function name to the matched profile name. This is used
81 // for sample loader to look up profile using the new name.
83
84 // A map pointer to the SymbolMap in SampleProfileLoader, which stores all
85 // the original matched symbols before the matching. this is to determine if
86 // the profile is unused(to be matched) or not.
88
89 // The new functions from IR.
91 FunctionsWithoutProfile;
92
93 // Pointer to the Profile Symbol List in the reader.
94 std::shared_ptr<ProfileSymbolList> PSL;
95
96 // Profile mismatch statstics:
97 uint64_t TotalProfiledFunc = 0;
98 // Num of checksum-mismatched function.
99 uint64_t NumStaleProfileFunc = 0;
100 uint64_t TotalProfiledCallsites = 0;
101 uint64_t NumMismatchedCallsites = 0;
102 uint64_t NumRecoveredCallsites = 0;
103 // Total samples for all profiled functions.
104 uint64_t TotalFunctionSamples = 0;
105 // Total samples for all checksum-mismatched functions.
106 uint64_t MismatchedFunctionSamples = 0;
107 uint64_t MismatchedCallsiteSamples = 0;
108 uint64_t RecoveredCallsiteSamples = 0;
109
110 // Profile call-graph matching statstics:
111 uint64_t NumCallGraphRecoveredProfiledFunc = 0;
112 uint64_t NumCallGraphRecoveredFuncSamples = 0;
113
114 // A dummy name for unknown indirect callee, used to differentiate from a
115 // non-call instruction that also has an empty callee name.
116 static constexpr const char *UnknownIndirectCallee =
117 "unknown.indirect.callee";
118
119public:
122 const PseudoProbeManager *ProbeManager, ThinOrFullLTOPhase LTOPhase,
124 std::shared_ptr<ProfileSymbolList> PSL,
126 &FuncNameToProfNameMap)
127 : M(M), Reader(Reader), CG(CG), ProbeManager(ProbeManager),
128 LTOPhase(LTOPhase), FuncNameToProfNameMap(&FuncNameToProfNameMap),
129 SymbolMap(&SymMap), PSL(PSL) {};
130 void runOnModule();
132 // Do not clear FuncMappings, it stores IRLoc to ProfLoc remappings which
133 // will be used for sample loader.
134 // Do not clear FlattenedProfiles as it contains function names referenced
135 // by FuncNameToProfNameMap. Clearing this memory could lead to a
136 // use-after-free error.
137 freeContainer(FuncCallsiteMatchStates);
138 freeContainer(FunctionsWithoutProfile);
139 freeContainer(FuncToProfileNameMap);
140 }
141
142private:
143 FunctionSamples *getFlattenedSamplesFor(const FunctionId &Fname) {
144 auto It = FlattenedProfiles.find(Fname);
145 if (It != FlattenedProfiles.end())
146 return &It->second;
147 return nullptr;
148 }
149 FunctionSamples *getFlattenedSamplesFor(const Function &F) {
150 StringRef CanonFName = FunctionSamples::getCanonicalFnName(F);
151 return getFlattenedSamplesFor(FunctionId(CanonFName));
152 }
153 template <typename T> inline void freeContainer(T &C) {
154 T Empty;
155 std::swap(C, Empty);
156 }
157 void getFilteredAnchorList(const AnchorMap &IRAnchors,
158 const AnchorMap &ProfileAnchors,
159 AnchorList &FilteredIRAnchorsList,
160 AnchorList &FilteredProfileAnchorList);
161 void runOnFunction(Function &F);
162 void findIRAnchors(const Function &F, AnchorMap &IRAnchors) const;
163 void findProfileAnchors(const FunctionSamples &FS,
164 AnchorMap &ProfileAnchors) const;
165 // Record the callsite match states for profile staleness report, the result
166 // is saved in FuncCallsiteMatchStates.
167 void recordCallsiteMatchStates(const Function &F, const AnchorMap &IRAnchors,
168 const AnchorMap &ProfileAnchors,
169 const LocToLocMap *IRToProfileLocationMap);
170
171 bool isMismatchState(const enum MatchState &State) {
172 return State == MatchState::InitialMismatch ||
173 State == MatchState::UnchangedMismatch ||
174 State == MatchState::RemovedMatch;
175 };
176
177 bool isInitialState(const enum MatchState &State) {
178 return State == MatchState::InitialMatch ||
179 State == MatchState::InitialMismatch;
180 };
181
182 bool isFinalState(const enum MatchState &State) {
183 return State == MatchState::UnchangedMatch ||
184 State == MatchState::UnchangedMismatch ||
185 State == MatchState::RecoveredMismatch ||
186 State == MatchState::RemovedMatch;
187 };
188
189 void countCallGraphRecoveredSamples(
190 const FunctionSamples &FS,
191 std::unordered_set<FunctionId> &MatchedUnusedProfile);
192 // Count the samples of checksum mismatched function for the top-level
193 // function and all inlinees.
194 void countMismatchedFuncSamples(const FunctionSamples &FS, bool IsTopLevel);
195 // Count the number of mismatched or recovered callsites.
196 void countMismatchCallsites(const FunctionSamples &FS);
197 // Count the samples of mismatched or recovered callsites for top-level
198 // function and all inlinees.
199 void countMismatchedCallsiteSamples(const FunctionSamples &FS);
200 void computeAndReportProfileStaleness();
201
202 LocToLocMap &getIRToProfileLocationMap(const Function &F) {
203 auto Ret = FuncMappings.try_emplace(
205 return Ret.first->second;
206 }
207 void distributeIRToProfileLocationMap();
208 void distributeIRToProfileLocationMap(FunctionSamples &FS);
209 // This function implements the Myers diff algorithm used for stale profile
210 // matching. The algorithm provides a simple and efficient way to find the
211 // Longest Common Subsequence(LCS) or the Shortest Edit Script(SES) of two
212 // sequences. For more details, refer to the paper 'An O(ND) Difference
213 // Algorithm and Its Variations' by Eugene W. Myers.
214 // In the scenario of profile fuzzy matching, the two sequences are the IR
215 // callsite anchors and profile callsite anchors. The subsequence equivalent
216 // parts from the resulting SES are used to remap the IR locations to the
217 // profile locations. As the number of function callsite is usually not big,
218 // we currently just implements the basic greedy version(page 6 of the paper).
219 LocToLocMap longestCommonSequence(const AnchorList &IRCallsiteAnchors,
220 const AnchorList &ProfileCallsiteAnchors,
221 bool MatchUnusedFunction);
222 void matchNonCallsiteLocs(const LocToLocMap &AnchorMatchings,
223 const AnchorMap &IRAnchors,
224 LocToLocMap &IRToProfileLocationMap);
225 void runStaleProfileMatching(const Function &F, const AnchorMap &IRAnchors,
226 const AnchorMap &ProfileAnchors,
227 LocToLocMap &IRToProfileLocationMap,
228 bool RunCFGMatching, bool RunCGMatching);
229 // If the function doesn't have profile, return the pointer to the function.
230 bool functionHasProfile(const FunctionId &IRFuncName,
231 Function *&FuncWithoutProfile);
232 bool isProfileUnused(const FunctionId &ProfileFuncName);
233 bool functionMatchesProfileHelper(const Function &IRFunc,
234 const FunctionId &ProfFunc);
235 // Determine if the function matches profile. If FindMatchedProfileOnly is
236 // set, only search the existing matched function. Otherwise, try matching the
237 // two functions.
238 bool functionMatchesProfile(const FunctionId &IRFuncName,
239 const FunctionId &ProfileFuncName,
240 bool FindMatchedProfileOnly);
241 // Determine if the function matches profile by computing a similarity ratio
242 // between two sequences of callsite anchors extracted from function and
243 // profile. If it's above the threshold, the function matches the profile.
244 bool functionMatchesProfile(Function &IRFunc, const FunctionId &ProfFunc,
245 bool FindMatchedProfileOnly);
246 // Find functions that don't show in the profile or profile symbol list,
247 // which are supposed to be new functions. We use them as the targets for
248 // call graph matching.
249 void findFunctionsWithoutProfile();
250 void reportOrPersistProfileStats();
251};
252} // end namespace llvm
253#endif // LLVM_TRANSFORMS_IPO_SAMPLEPROFILEMATCHER_H
#define F(x, y, z)
Definition: MD5.cpp:55
#define P(N)
This file provides the interface for the sampled PGO profile loader base implementation.
StringSet - A set-like wrapper for the StringMap.
A lazily constructed view of the call graph of a module.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
SampleProfileMatcher(Module &M, SampleProfileReader &Reader, LazyCallGraph &CG, const PseudoProbeManager *ProbeManager, ThinOrFullLTOPhase LTOPhase, HashKeyMap< std::unordered_map, FunctionId, Function * > &SymMap, std::shared_ptr< ProfileSymbolList > PSL, HashKeyMap< std::unordered_map, FunctionId, FunctionId > &FuncNameToProfNameMap)
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:128
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.
Definition: StringMap.h:368
This class represents a function that is read from a sample profile.
Definition: FunctionId.h:36
Representation of the samples collected for a function.
Definition: SampleProf.h:745
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
Definition: SampleProf.h:1090
This class is a wrapper to associative container MapT<KeyT, ValueT> using the hash value of the origi...
Definition: HashKeyMap.h:53
This class provides operator overloads to the map container using MD5 as the key type,...
Definition: SampleProf.h:1313
iterator find(const SampleContext &Ctx)
Definition: SampleProf.h:1324
Sample-based profile reader.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
std::unordered_map< LineLocation, LineLocation, LineLocationHash > LocToLocMap
Definition: SampleProf.h:738
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::vector< std::pair< LineLocation, FunctionId > > AnchorList
std::map< LineLocation, FunctionId > AnchorMap
ThinOrFullLTOPhase
This enumerates the LLVM full LTO or ThinLTO optimization phases.
Definition: Pass.h:76
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:593
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860