Skip to content

Commit 1d99d7a

Browse files
authored
[SampleFDO][NFC] Refactoring SampleProfileMatcher (#86988)
Move all the stale profile matching stuffs into new files so that it can be shared for unit testing.
1 parent 89bae85 commit 1d99d7a

File tree

8 files changed

+718
-671
lines changed

8 files changed

+718
-671
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
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"
18+
#include "llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h"
19+
20+
namespace llvm {
21+
22+
// Sample profile matching - fuzzy match.
23+
class SampleProfileMatcher {
24+
Module &M;
25+
SampleProfileReader &Reader;
26+
const PseudoProbeManager *ProbeManager;
27+
const ThinOrFullLTOPhase LTOPhase;
28+
SampleProfileMap FlattenedProfiles;
29+
// For each function, the matcher generates a map, of which each entry is a
30+
// mapping from the source location of current build to the source location in
31+
// the profile.
32+
StringMap<LocToLocMap> FuncMappings;
33+
34+
// Match state for an anchor/callsite.
35+
enum class MatchState {
36+
Unknown = 0,
37+
// Initial match between input profile and current IR.
38+
InitialMatch = 1,
39+
// Initial mismatch between input profile and current IR.
40+
InitialMismatch = 2,
41+
// InitialMatch stays matched after fuzzy profile matching.
42+
UnchangedMatch = 3,
43+
// InitialMismatch stays mismatched after fuzzy profile matching.
44+
UnchangedMismatch = 4,
45+
// InitialMismatch is recovered after fuzzy profile matching.
46+
RecoveredMismatch = 5,
47+
// InitialMatch is removed and becomes mismatched after fuzzy profile
48+
// matching.
49+
RemovedMatch = 6,
50+
};
51+
52+
// For each function, store every callsite and its matching state into this
53+
// map, of which each entry is a pair of callsite location and MatchState.
54+
// This is used for profile staleness computation and report.
55+
StringMap<std::unordered_map<LineLocation, MatchState, LineLocationHash>>
56+
FuncCallsiteMatchStates;
57+
58+
// Profile mismatch statstics:
59+
uint64_t TotalProfiledFunc = 0;
60+
// Num of checksum-mismatched function.
61+
uint64_t NumStaleProfileFunc = 0;
62+
uint64_t TotalProfiledCallsites = 0;
63+
uint64_t NumMismatchedCallsites = 0;
64+
uint64_t NumRecoveredCallsites = 0;
65+
// Total samples for all profiled functions.
66+
uint64_t TotalFunctionSamples = 0;
67+
// Total samples for all checksum-mismatched functions.
68+
uint64_t MismatchedFunctionSamples = 0;
69+
uint64_t MismatchedCallsiteSamples = 0;
70+
uint64_t RecoveredCallsiteSamples = 0;
71+
72+
// A dummy name for unknown indirect callee, used to differentiate from a
73+
// non-call instruction that also has an empty callee name.
74+
static constexpr const char *UnknownIndirectCallee =
75+
"unknown.indirect.callee";
76+
77+
public:
78+
SampleProfileMatcher(Module &M, SampleProfileReader &Reader,
79+
const PseudoProbeManager *ProbeManager,
80+
ThinOrFullLTOPhase LTOPhase)
81+
: M(M), Reader(Reader), ProbeManager(ProbeManager), LTOPhase(LTOPhase){};
82+
void runOnModule();
83+
void clearMatchingData() {
84+
// Do not clear FuncMappings, it stores IRLoc to ProfLoc remappings which
85+
// will be used for sample loader.
86+
FuncCallsiteMatchStates.clear();
87+
}
88+
89+
private:
90+
FunctionSamples *getFlattenedSamplesFor(const Function &F) {
91+
StringRef CanonFName = FunctionSamples::getCanonicalFnName(F);
92+
auto It = FlattenedProfiles.find(FunctionId(CanonFName));
93+
if (It != FlattenedProfiles.end())
94+
return &It->second;
95+
return nullptr;
96+
}
97+
void runOnFunction(Function &F);
98+
void findIRAnchors(const Function &F,
99+
std::map<LineLocation, StringRef> &IRAnchors);
100+
void findProfileAnchors(
101+
const FunctionSamples &FS,
102+
std::map<LineLocation, std::unordered_set<FunctionId>> &ProfileAnchors);
103+
// Record the callsite match states for profile staleness report, the result
104+
// is saved in FuncCallsiteMatchStates.
105+
void recordCallsiteMatchStates(
106+
const Function &F, const std::map<LineLocation, StringRef> &IRAnchors,
107+
const std::map<LineLocation, std::unordered_set<FunctionId>>
108+
&ProfileAnchors,
109+
const LocToLocMap *IRToProfileLocationMap);
110+
111+
bool isMismatchState(const enum MatchState &State) {
112+
return State == MatchState::InitialMismatch ||
113+
State == MatchState::UnchangedMismatch ||
114+
State == MatchState::RemovedMatch;
115+
};
116+
117+
bool isInitialState(const enum MatchState &State) {
118+
return State == MatchState::InitialMatch ||
119+
State == MatchState::InitialMismatch;
120+
};
121+
122+
bool isFinalState(const enum MatchState &State) {
123+
return State == MatchState::UnchangedMatch ||
124+
State == MatchState::UnchangedMismatch ||
125+
State == MatchState::RecoveredMismatch ||
126+
State == MatchState::RemovedMatch;
127+
};
128+
129+
// Count the samples of checksum mismatched function for the top-level
130+
// function and all inlinees.
131+
void countMismatchedFuncSamples(const FunctionSamples &FS, bool IsTopLevel);
132+
// Count the number of mismatched or recovered callsites.
133+
void countMismatchCallsites(const FunctionSamples &FS);
134+
// Count the samples of mismatched or recovered callsites for top-level
135+
// function and all inlinees.
136+
void countMismatchedCallsiteSamples(const FunctionSamples &FS);
137+
void computeAndReportProfileStaleness();
138+
139+
LocToLocMap &getIRToProfileLocationMap(const Function &F) {
140+
auto Ret = FuncMappings.try_emplace(
141+
FunctionSamples::getCanonicalFnName(F.getName()), LocToLocMap());
142+
return Ret.first->second;
143+
}
144+
void distributeIRToProfileLocationMap();
145+
void distributeIRToProfileLocationMap(FunctionSamples &FS);
146+
void runStaleProfileMatching(
147+
const Function &F, const std::map<LineLocation, StringRef> &IRAnchors,
148+
const std::map<LineLocation, std::unordered_set<FunctionId>>
149+
&ProfileAnchors,
150+
LocToLocMap &IRToProfileLocationMap);
151+
void reportOrPersistProfileStats();
152+
};
153+
} // end namespace llvm
154+
#endif // LLVM_TRANSFORMS_IPO_SAMPLEPROFILEMATCHER_H

llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ class PseudoProbeManager {
146146

147147
extern cl::opt<bool> SampleProfileUseProfi;
148148

149+
static inline bool skipProfileForFunction(const Function &F) {
150+
return F.isDeclaration() || !F.hasFnAttribute("use-sample-profile");
151+
}
152+
149153
template <typename FT> class SampleProfileLoaderBaseImpl {
150154
public:
151155
SampleProfileLoaderBaseImpl(std::string Name, std::string RemapName,

llvm/lib/Transforms/IPO/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ add_llvm_component_library(LLVMipo
3535
PartialInlining.cpp
3636
SampleContextTracker.cpp
3737
SampleProfile.cpp
38+
SampleProfileMatcher.cpp
3839
SampleProfileProbe.cpp
3940
SCCP.cpp
4041
StripDeadPrototypes.cpp

0 commit comments

Comments
 (0)