Skip to content

[CSSPGO] Reject high checksum mismatched profile #84097

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

Merged
merged 7 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions llvm/lib/Transforms/IPO/SampleProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,21 @@ static cl::opt<unsigned> ProfileICPRelativeHotnessSkip(
cl::desc(
"Skip relative hotness check for ICP up to given number of targets."));

static cl::opt<unsigned> HotFuncCutoffForStalenessError(
"hot-func-cutoff-for-staleness-error", cl::Hidden, cl::init(800000),
cl::desc("A function is considered hot for staleness error check if its "
"total sample count is above the specified percentile"));

static cl::opt<unsigned> MinfuncsForStalenessError(
"min-functions-for-staleness-error", cl::Hidden, cl::init(50),
cl::desc("Skip the check if the number of hot functions is smaller than "
"the specified number."));

static cl::opt<unsigned> PrecentMismatchForStalenessError(
"precent-mismatch-for-staleness-error", cl::Hidden, cl::init(80),
cl::desc("Reject the profile if the mismatch percent is higher than the "
"given number."));

static cl::opt<bool> CallsitePrioritizedInline(
"sample-profile-prioritized-inline", cl::Hidden,

Expand Down Expand Up @@ -630,6 +645,8 @@ class SampleProfileLoader final : public SampleProfileLoaderBaseImpl<Function> {
std::vector<Function *> buildFunctionOrder(Module &M, LazyCallGraph &CG);
std::unique_ptr<ProfiledCallGraph> buildProfiledCallGraph(Module &M);
void generateMDProfMetadata(Function &F);
bool rejectHighStalenessProfile(Module &M, ProfileSummaryInfo *PSI,
const SampleProfileMap &Profiles);

/// Map from function name to Function *. Used to find the function from
/// the function name. If the function name contains suffix, additional
Expand Down Expand Up @@ -2187,6 +2204,55 @@ bool SampleProfileLoader::doInitialization(Module &M,
return true;
}

// Note that this is a module-level check. Even if one module is errored out,
// the entire build will be errored out. However, the user could make big
// changes to functions in single module but those changes might not be
// performance significant to the whole binary. Therefore, to avoid those false
// positives, we select a reasonable big set of hot functions that are supposed
// to be globally performance significant, only compute and check the mismatch
// within those functions. The function selection is based on two criteria:
// 1) The function is hot enough, which is tuned by a hotness-based
// flag(HotFuncCutoffForStalenessError). 2) The num of function is large enough
// which is tuned by the MinfuncsForStalenessError flag.
bool SampleProfileLoader::rejectHighStalenessProfile(
Module &M, ProfileSummaryInfo *PSI, const SampleProfileMap &Profiles) {
assert(FunctionSamples::ProfileIsProbeBased &&
"Only support for probe-based profile");
uint64_t TotalHotFunc = 0;
uint64_t NumMismatchedFunc = 0;
for (const auto &I : Profiles) {
const auto &FS = I.second;
const auto *FuncDesc = ProbeManager->getDesc(FS.getGUID());
if (!FuncDesc)
continue;

// Use a hotness-based threshold to control the function selection.
if (!PSI->isHotCountNthPercentile(HotFuncCutoffForStalenessError,
FS.getTotalSamples()))
continue;

TotalHotFunc++;
if (ProbeManager->profileIsHashMismatched(*FuncDesc, FS))
NumMismatchedFunc++;
}
// Make sure that the num of selected function is not too small to distinguish
// from the user's benign changes.
if (TotalHotFunc < MinfuncsForStalenessError)
return false;

// Finally check the mismatch percentage against the threshold.
if (NumMismatchedFunc * 100 >=
TotalHotFunc * PrecentMismatchForStalenessError) {
auto &Ctx = M.getContext();
const char *Msg =
"The input profile significantly mismatches current source code. "
"Please recollect profile to avoid performance regression.";
Ctx.diagnose(DiagnosticInfoSampleProfile(M.getModuleIdentifier(), Msg));
return true;
}
return false;
}

void SampleProfileMatcher::findIRAnchors(
const Function &F, std::map<LineLocation, StringRef> &IRAnchors) {
// For inlined code, recover the original callsite and callee by finding the
Expand Down Expand Up @@ -2718,6 +2784,11 @@ bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM,
ProfileSummary::PSK_Sample);
PSI->refresh();
}

if (FunctionSamples::ProfileIsProbeBased &&
rejectHighStalenessProfile(M, PSI, Reader->getProfiles()))
return false;

// Compute the total number of samples collected in this profile.
for (const auto &I : Reader->getProfiles())
TotalCollectedSamples += I.second.getTotalSamples();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; REQUIRES: x86_64-linux
; RUN: not opt < %S/pseudo-probe-profile-mismatch.ll -passes=sample-profile -sample-profile-file=%S/Inputs/pseudo-probe-profile-mismatch.prof -min-functions-for-staleness-error=1 -precent-mismatch-for-staleness-error=1 -S 2>&1 | FileCheck %s
; RUN: opt < %S/pseudo-probe-profile-mismatch.ll -passes=sample-profile -sample-profile-file=%S/Inputs/pseudo-probe-profile-mismatch.prof -min-functions-for-staleness-error=3 -precent-mismatch-for-staleness-error=70 -S 2>&1
; RUN: opt < %S/pseudo-probe-profile-mismatch.ll -passes=sample-profile -sample-profile-file=%S/Inputs/pseudo-probe-profile-mismatch.prof -min-functions-for-staleness-error=4 -precent-mismatch-for-staleness-error=1 -S 2>&1


; CHECK: error: {{.*}}: The input profile significantly mismatches current source code. Please recollect profile to avoid performance regression.