Skip to content

Commit 90dea0e

Browse files
committed
[CSSPGO] Error out if the checksum mismatch is high
1 parent 09155ac commit 90dea0e

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

llvm/lib/Transforms/IPO/SampleProfile.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,24 @@ static cl::opt<unsigned> ProfileICPRelativeHotnessSkip(
234234
cl::desc(
235235
"Skip relative hotness check for ICP up to given number of targets."));
236236

237+
static cl::opt<unsigned> ChecksumMismatchFuncHotBlockSkip(
238+
"checksum-mismatch-func-hot-block-skip", cl::Hidden, cl::init(100),
239+
cl::desc("For checksum-mismatch error check, skip checking the function "
240+
"whose num of hot(on average) blocks is smaller than the "
241+
"given number."));
242+
243+
static cl::opt<unsigned> ChecksumMismatchNumFuncSkip(
244+
"checksum-mismatch-num-func-skip", cl::Hidden, cl::init(50),
245+
cl::desc("For checksum-mismatch error check, skip the check if the total "
246+
"number of selected function is smaller than the given number."));
247+
248+
static cl::opt<unsigned> ChecksumMismatchErrorThreshold(
249+
"checksum-mismatch-error-threshold", cl::Hidden, cl::init(80),
250+
cl::desc(
251+
"For checksum-mismatch error check, error out if the percentage of "
252+
"function mismatched-checksum is higher than the given percentage "
253+
"threshold"));
254+
237255
static cl::opt<bool> CallsitePrioritizedInline(
238256
"sample-profile-prioritized-inline", cl::Hidden,
239257

@@ -630,6 +648,8 @@ class SampleProfileLoader final : public SampleProfileLoaderBaseImpl<Function> {
630648
std::vector<Function *> buildFunctionOrder(Module &M, LazyCallGraph &CG);
631649
std::unique_ptr<ProfiledCallGraph> buildProfiledCallGraph(Module &M);
632650
void generateMDProfMetadata(Function &F);
651+
bool errorIfHighChecksumMismatch(Module &M, ProfileSummaryInfo *PSI,
652+
const SampleProfileMap &Profiles);
633653

634654
/// Map from function name to Function *. Used to find the function from
635655
/// the function name. If the function name contains suffix, additional
@@ -2187,6 +2207,61 @@ bool SampleProfileLoader::doInitialization(Module &M,
21872207
return true;
21882208
}
21892209

2210+
// Note that this is a module-level check. Even if one module is errored out,
2211+
// the entire build will be errored out. However, the user could make big
2212+
// changes to functions in single module but those changes might not be
2213+
// performance significant to the whole binary. Therefore, we use a conservative
2214+
// approach to make sure we only error out if it globally impacts the binary
2215+
// performance. To achieve this, we use heuristics to select a reasonable
2216+
// big set of functions that are supposed to be globally performance
2217+
// significant, only compute and check the mismatch within those functions. The
2218+
// function selection is based on two criteria: 1) The function is "hot" enough,
2219+
// which is tuned by a hotness-based flag(ChecksumMismatchFuncHotBlockSkip). 2)
2220+
// The num of function is large enough which is tuned by the
2221+
// ChecksumMismatchNumFuncSkip flag.
2222+
bool SampleProfileLoader::errorIfHighChecksumMismatch(
2223+
Module &M, ProfileSummaryInfo *PSI, const SampleProfileMap &Profiles) {
2224+
assert(FunctionSamples::ProfileIsProbeBased &&
2225+
"Only support for probe-based profile");
2226+
uint64_t TotalSelectedFunc = 0;
2227+
uint64_t NumMismatchedFunc = 0;
2228+
for (const auto &I : Profiles) {
2229+
const auto &FS = I.second;
2230+
const auto *FuncDesc = ProbeManager->getDesc(FS.getGUID());
2231+
if (!FuncDesc)
2232+
continue;
2233+
2234+
// We want to select a set of functions that are globally performance
2235+
// significant, in other words, if those functions profiles are
2236+
// checksum-mismatched and dropped, the whole binary will likely be
2237+
// impacted, so here we use a hotness-based threshold to control the
2238+
// selection.
2239+
if (FS.getTotalSamples() <
2240+
ChecksumMismatchFuncHotBlockSkip * PSI->getOrCompHotCountThreshold())
2241+
continue;
2242+
2243+
TotalSelectedFunc++;
2244+
if (ProbeManager->profileIsHashMismatched(*FuncDesc, FS))
2245+
NumMismatchedFunc++;
2246+
}
2247+
// Make sure that the num of selected function is not too small to distinguish
2248+
// from the user's benign changes.
2249+
if (TotalSelectedFunc < ChecksumMismatchNumFuncSkip)
2250+
return false;
2251+
2252+
// Finally check the mismatch percentage against the threshold.
2253+
if (NumMismatchedFunc * 100 >=
2254+
TotalSelectedFunc * ChecksumMismatchErrorThreshold) {
2255+
auto &Ctx = M.getContext();
2256+
const char *Msg =
2257+
"The FDO profile is too old and will cause big performance regression, "
2258+
"please drop the profile and collect a new one.";
2259+
Ctx.diagnose(DiagnosticInfoSampleProfile(M.getModuleIdentifier(), Msg));
2260+
return true;
2261+
}
2262+
return false;
2263+
}
2264+
21902265
void SampleProfileMatcher::findIRAnchors(
21912266
const Function &F, std::map<LineLocation, StringRef> &IRAnchors) {
21922267
// For inlined code, recover the original callsite and callee by finding the
@@ -2718,6 +2793,12 @@ bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM,
27182793
ProfileSummary::PSK_Sample);
27192794
PSI->refresh();
27202795
}
2796+
2797+
// Error out if the profile checksum mismatch is too high.
2798+
if (FunctionSamples::ProfileIsProbeBased &&
2799+
errorIfHighChecksumMismatch(M, PSI, Reader->getProfiles()))
2800+
return false;
2801+
27212802
// Compute the total number of samples collected in this profile.
27222803
for (const auto &I : Reader->getProfiles())
27232804
TotalCollectedSamples += I.second.getTotalSamples();

0 commit comments

Comments
 (0)