Skip to content

Commit f25b13f

Browse files
committed
Error out if the checksum mismatch is high
1 parent 6fe180e commit f25b13f

File tree

1 file changed

+83
-1
lines changed

1 file changed

+83
-1
lines changed

llvm/lib/Transforms/IPO/SampleProfile.cpp

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,25 @@ 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+
"that the num of its 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(100),
245+
cl::desc(
246+
"For checksum-mismatch error check, skip the check if the number of "
247+
"total selected function is smaller than the given number."));
248+
249+
static cl::opt<unsigned> ChecksumMismatchErrorThreshold(
250+
"checksum-mismatch-error-threshold", cl::Hidden, cl::init(90),
251+
cl::desc(
252+
"For checksum-mismatch error check, error out if the percentage of "
253+
"function mismatched-checksum is higher than the given percentage "
254+
"threshold"));
255+
237256
static cl::opt<bool> CallsitePrioritizedInline(
238257
"sample-profile-prioritized-inline", cl::Hidden,
239258

@@ -630,6 +649,8 @@ class SampleProfileLoader final : public SampleProfileLoaderBaseImpl<Function> {
630649
std::vector<Function *> buildFunctionOrder(Module &M, LazyCallGraph &CG);
631650
std::unique_ptr<ProfiledCallGraph> buildProfiledCallGraph(Module &M);
632651
void generateMDProfMetadata(Function &F);
652+
bool errorIfHighChecksumMismatch(Module &M, ProfileSummaryInfo *PSI,
653+
const SampleProfileMap &Profiles);
633654

634655
/// Map from function name to Function *. Used to find the function from
635656
/// the function name. If the function name contains suffix, additional
@@ -1190,7 +1211,7 @@ void SampleProfileLoader::findExternalInlineCandidate(
11901211
CalleeSample->getContext().hasAttribute(ContextShouldBeInlined);
11911212
if (!PreInline && CalleeSample->getHeadSamplesEstimate() < Threshold)
11921213
continue;
1193-
1214+
11941215
Function *Func = SymbolMap.lookup(CalleeSample->getFunction());
11951216
// Add to the import list only when it's defined out of module.
11961217
if (!Func || Func->isDeclaration())
@@ -2184,6 +2205,61 @@ bool SampleProfileLoader::doInitialization(Module &M,
21842205
return true;
21852206
}
21862207

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

0 commit comments

Comments
 (0)