[llvm] [SamplePGO] Ignore Remapper when salvaging unused profile (PR #176905)
Krzysztof Pszeniczny via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 20 03:57:20 PST 2026
https://github.com/amharc updated https://github.com/llvm/llvm-project/pull/176905
>From e4e320ea66c38cab9303a7ddf8dc3eb4031fc51b Mon Sep 17 00:00:00 2001
From: Krzysztof Pszeniczny <kpszeniczny at google.com>
Date: Tue, 20 Jan 2026 12:48:24 +0100
Subject: [PATCH] [SamplePGO] Ignore Remapper when salvaging unused profile
Currently `SampleProfileMatcher::functionMatchesProfileHelper` calls
`Reader.read(TopLevelFunc))` for the function for which it was called.
If a Remapper is configured, `Reader::read` will ultimately iterate
over *all* functions in the profile (iteration over `FuncOffsetList`
in `SampleProfileReaderExtBinaryBase::readFuncProfiles`). This means
that `-fsalvage-unused-profile` has a quadratic time complexity.
We don't need the remapper at all when salvaging unused profile. The
whole idea of salvaging unused profiles is to be resilient to function
renames, so we don't need to support hand-crafted symbol renames there.
---
.../llvm/ProfileData/SampleProfReader.h | 18 ++++++++++-------
llvm/lib/ProfileData/SampleProfReader.cpp | 20 ++++++++++++-------
.../Transforms/IPO/SampleProfileMatcher.cpp | 4 ++--
3 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 67834f72c2400..464ff18930bd8 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -371,22 +371,23 @@ class SampleProfileReader {
}
/// The interface to read sample profiles from the associated file.
- std::error_code read() {
+ std::error_code read(bool IgnoreRemapper = false) {
if (std::error_code EC = readImpl())
return EC;
- if (Remapper)
+ if (Remapper && !IgnoreRemapper)
Remapper->applyRemapping(Ctx);
FunctionSamples::UseMD5 = useMD5();
return sampleprof_error::success;
}
/// Read sample profiles for the given functions.
- std::error_code read(const DenseSet<StringRef> &FuncsToUse) {
+ std::error_code read(const DenseSet<StringRef> &FuncsToUse,
+ bool IgnoreRemapper = false) {
DenseSet<StringRef> S;
for (StringRef F : FuncsToUse)
if (Profiles.find(FunctionId(F)) == Profiles.end())
S.insert(F);
- if (std::error_code EC = read(S, Profiles))
+ if (std::error_code EC = read(S, Profiles, IgnoreRemapper))
return EC;
return sampleprof_error::success;
}
@@ -551,7 +552,8 @@ class SampleProfileReader {
/// profile map. Currently it's only used for extended binary format to load
/// the profiles on-demand.
virtual std::error_code read(const DenseSet<StringRef> &FuncsToUse,
- SampleProfileMap &Profiles) {
+ SampleProfileMap &Profiles,
+ bool IgnoreRemapper = false) {
return sampleprof_error::not_implemented;
}
@@ -798,7 +800,8 @@ class LLVM_ABI SampleProfileReaderExtBinaryBase
std::error_code readFuncOffsetTable();
std::error_code readFuncProfiles();
std::error_code readFuncProfiles(const DenseSet<StringRef> &FuncsToUse,
- SampleProfileMap &Profiles);
+ SampleProfileMap &Profiles,
+ bool IgnoreRemapper = false);
std::error_code readNameTableSec(bool IsMD5, bool FixedLengthMD5);
std::error_code readCSNameTableSec();
std::error_code readProfileSymbolList();
@@ -856,7 +859,8 @@ class LLVM_ABI SampleProfileReaderExtBinaryBase
/// at the beginning and we need to loaded the profiles explicitly for
/// potential matching.
std::error_code read(const DenseSet<StringRef> &FuncsToUse,
- SampleProfileMap &Profiles) override;
+ SampleProfileMap &Profiles,
+ bool IgnoreRemapper = false) override;
};
class LLVM_ABI SampleProfileReaderExtBinary
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index 766c0814ca067..cbba9da52d3a8 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -945,13 +945,15 @@ bool SampleProfileReaderExtBinaryBase::useFuncOffsetList() const {
std::error_code
SampleProfileReaderExtBinaryBase::read(const DenseSet<StringRef> &FuncsToUse,
- SampleProfileMap &Profiles) {
+ SampleProfileMap &Profiles,
+ bool IgnoreRemapper) {
if (FuncsToUse.empty())
return sampleprof_error::success;
Data = ProfileSecRange.first;
End = ProfileSecRange.second;
- if (std::error_code EC = readFuncProfiles(FuncsToUse, Profiles))
+ if (std::error_code EC =
+ readFuncProfiles(FuncsToUse, Profiles, IgnoreRemapper))
return EC;
End = Data;
DenseSet<FunctionSamples *> ProfilesToReadMetadata;
@@ -1014,10 +1016,11 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
}
std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles(
- const DenseSet<StringRef> &FuncsToUse, SampleProfileMap &Profiles) {
+ const DenseSet<StringRef> &FuncsToUse, SampleProfileMap &Profiles,
+ bool IgnoreRemapper) {
const uint8_t *Start = Data;
- if (Remapper) {
+ if (Remapper && !IgnoreRemapper) {
for (auto Name : FuncsToUse) {
Remapper->insert(Name);
}
@@ -1050,8 +1053,9 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles(
// context. This can be used to load itself and its child and
// sibling contexts.
if ((useMD5() && FuncGuidsToUse.count(FName.getHashCode())) ||
- (!useMD5() && (FuncsToUse.count(FNameString) ||
- (Remapper && Remapper->exist(FNameString))))) {
+ (!useMD5() &&
+ (FuncsToUse.count(FNameString) ||
+ (Remapper && !IgnoreRemapper && Remapper->exist(FNameString))))) {
if (!CommonContext || !CommonContext->isPrefixOf(FContext))
CommonContext = &FContext;
}
@@ -1082,8 +1086,10 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles(
SampleContext FContext(NameOffset.first);
auto FuncName = FContext.getFunction();
StringRef FuncNameStr = FuncName.stringRef();
- if (!FuncsToUse.count(FuncNameStr) && !Remapper->exist(FuncNameStr))
+ if (!FuncsToUse.count(FuncNameStr) &&
+ (IgnoreRemapper || !Remapper->exist(FuncNameStr)))
continue;
+
const uint8_t *FuncProfileAddr = Start + NameOffset.second;
if (std::error_code EC = readFuncProfile(FuncProfileAddr, Profiles))
return EC;
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index b9fb7a3ae4b5b..ce903f70af3fb 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -771,7 +771,7 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
// this, we load the top-level profile candidate explicitly for the matching.
if (!FSForMatching && LoadFuncProfileforCGMatching) {
DenseSet<StringRef> TopLevelFunc({ProfFunc.stringRef()});
- if (std::error_code EC = Reader.read(TopLevelFunc))
+ if (std::error_code EC = Reader.read(TopLevelFunc, /*IgnoreRemapper=*/true))
return false;
FSForMatching = Reader.getSamplesFor(ProfFunc.stringRef());
LLVM_DEBUG({
@@ -879,7 +879,7 @@ void SampleProfileMatcher::UpdateWithSalvagedProfiles() {
// based on current function names in the module, so we need to load top-level
// profiles for functions with different profile name explicitly after
// function-profile name map is established with stale profile matching.
- Reader.read(ProfileSalvagedFuncs);
+ Reader.read(ProfileSalvagedFuncs, /*IgnoreRemapper=*/true);
Reader.setFuncNameToProfNameMap(*FuncNameToProfNameMap);
}
More information about the llvm-commits
mailing list