[llvm] r356146 - [SampleFDO] add suffix elision control for fcn names
Than McIntosh via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 14 06:56:49 PDT 2019
Author: thanm
Date: Thu Mar 14 06:56:49 2019
New Revision: 356146
URL: http://llvm.org/viewvc/llvm-project?rev=356146&view=rev
Log:
[SampleFDO] add suffix elision control for fcn names
Summary:
Add hooks for determining the policy used to decide whether/how
to chop off symbol 'suffixes' when locating a given function
in a sample profile.
Prior to this change, any function symbols of the form "X.Y" were
elided/truncated into just "X" when looking up things in a sample
profile data file.
With this change, the policy on suffixes can be changed by adding a
new attribute "sample-profile-suffix-elision-policy" to the function:
this attribute can have the value "all" (the default), "selected", or
"none". A value of "all" preserves the previous behavior (chop off
everything after the first "." character, then treat that as the
symbol name). A value of "selected" chops off only the rightmost
".llvm.XXXX" suffix (where "XXX" is any string not containing a "."
char). A value of "none" indicates that names should be left as is.
Subscribers: jdoerfert, wmi, mtrofin, danielcdh, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D58832
Modified:
llvm/trunk/include/llvm/ProfileData/SampleProf.h
llvm/trunk/include/llvm/ProfileData/SampleProfReader.h
llvm/trunk/lib/ProfileData/SampleProfReader.cpp
llvm/trunk/unittests/ProfileData/SampleProfTest.cpp
Modified: llvm/trunk/include/llvm/ProfileData/SampleProf.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProf.h?rev=356146&r1=356145&r2=356146&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProf.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProf.h Thu Mar 14 06:56:49 2019
@@ -410,6 +410,34 @@ public:
return getNameInModule(Name, M);
}
+ /// Return the canonical name for a function, taking into account
+ /// suffix elision policy attributes.
+ static StringRef getCanonicalFnName(const Function &F) {
+ static const char *knownSuffixes[] = { ".llvm.", ".part." };
+ auto AttrName = "sample-profile-suffix-elision-policy";
+ auto Attr = F.getFnAttribute(AttrName).getValueAsString();
+ if (Attr == "" || Attr == "all") {
+ return F.getName().split('.').first;
+ } else if (Attr == "selected") {
+ StringRef Cand(F.getName());
+ for (const auto &Suf : knownSuffixes) {
+ StringRef Suffix(Suf);
+ auto It = Cand.rfind(Suffix);
+ if (It == StringRef::npos)
+ return Cand;
+ auto Dit = Cand.rfind('.');
+ if (Dit == It + Suffix.size() - 1)
+ Cand = Cand.substr(0, It);
+ }
+ return Cand;
+ } else if (Attr == "none") {
+ return F.getName();
+ } else {
+ assert(false && "internal error: unknown suffix elision policy");
+ }
+ return F.getName();
+ }
+
/// Translate \p Name into its original name in Module.
/// When the Format is not SPF_Compact_Binary, \p Name needs no translation.
/// When the Format is SPF_Compact_Binary, \p Name in current FunctionSamples
@@ -465,11 +493,9 @@ public:
/// built in post-thin-link phase and var promotion has been done,
/// we need to add the substring of function name without the suffix
/// into the GUIDToFuncNameMap.
- auto pos = OrigName.find('.');
- if (pos != StringRef::npos) {
- StringRef NewName = OrigName.substr(0, pos);
- GUIDToFuncNameMap.insert({Function::getGUID(NewName), NewName});
- }
+ StringRef CanonName = getCanonicalFnName(F);
+ if (CanonName != OrigName)
+ GUIDToFuncNameMap.insert({Function::getGUID(CanonName), CanonName});
}
CurrentModule = &M;
}
Modified: llvm/trunk/include/llvm/ProfileData/SampleProfReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProfReader.h?rev=356146&r1=356145&r2=356146&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProfReader.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProfReader.h Thu Mar 14 06:56:49 2019
@@ -286,10 +286,11 @@ public:
/// Return the samples collected for function \p F.
FunctionSamples *getSamplesFor(const Function &F) {
- // The function name may have been updated by adding suffix. In sample
- // profile, the function names are all stripped, so we need to strip
- // the function name suffix before matching with profile.
- return getSamplesFor(F.getName().split('.').first);
+ // The function name may have been updated by adding suffix. Call
+ // a helper to (optionally) strip off suffixes so that we can
+ // match against the original function name in the profile.
+ StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
+ return getSamplesFor(CanonName);
}
/// Return the samples collected for function \p F.
Modified: llvm/trunk/lib/ProfileData/SampleProfReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProfReader.cpp?rev=356146&r1=356145&r2=356146&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/SampleProfReader.cpp (original)
+++ llvm/trunk/lib/ProfileData/SampleProfReader.cpp Thu Mar 14 06:56:49 2019
@@ -593,8 +593,8 @@ std::error_code SampleProfileReaderCompa
void SampleProfileReaderCompactBinary::collectFuncsToUse(const Module &M) {
FuncsToUse.clear();
for (auto &F : M) {
- StringRef Fname = F.getName().split('.').first;
- FuncsToUse.insert(Fname);
+ StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
+ FuncsToUse.insert(CanonName);
}
}
Modified: llvm/trunk/unittests/ProfileData/SampleProfTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ProfileData/SampleProfTest.cpp?rev=356146&r1=356145&r2=356146&view=diff
==============================================================================
--- llvm/trunk/unittests/ProfileData/SampleProfTest.cpp (original)
+++ llvm/trunk/unittests/ProfileData/SampleProfTest.cpp Thu Mar 14 06:56:49 2019
@@ -199,6 +199,78 @@ struct SampleProfTest : ::testing::Test
VerifySummary(*PS);
delete PS;
}
+
+ void addFunctionSamples(StringMap<FunctionSamples> *Smap, const char *Fname,
+ uint64_t TotalSamples, uint64_t HeadSamples) {
+ StringRef Name(Fname);
+ FunctionSamples FcnSamples;
+ FcnSamples.setName(Name);
+ FcnSamples.addTotalSamples(TotalSamples);
+ FcnSamples.addHeadSamples(HeadSamples);
+ FcnSamples.addBodySamples(1, 0, HeadSamples);
+ (*Smap)[Name] = FcnSamples;
+ }
+
+ StringMap<FunctionSamples> setupFcnSamplesForElisionTest(StringRef Policy) {
+ StringMap<FunctionSamples> Smap;
+ addFunctionSamples(&Smap, "foo", uint64_t(20301), uint64_t(1437));
+ if (Policy == "" || Policy == "all")
+ return Smap;
+ addFunctionSamples(&Smap, "foo.bar", uint64_t(20303), uint64_t(1439));
+ if (Policy == "selected")
+ return Smap;
+ addFunctionSamples(&Smap, "foo.llvm.2465", uint64_t(20305), uint64_t(1441));
+ return Smap;
+ }
+
+ void createFunctionWithSampleProfileElisionPolicy(Module *M,
+ const char *Fname,
+ StringRef Policy) {
+ FunctionType *FnType =
+ FunctionType::get(Type::getVoidTy(Context), {}, false);
+ auto Inserted = M->getOrInsertFunction(Fname, FnType);
+ auto Fcn = cast<Function>(Inserted.getCallee());
+ if (Policy != "")
+ Fcn->addFnAttr("sample-profile-suffix-elision-policy", Policy);
+ }
+
+ void setupModuleForElisionTest(Module *M, StringRef Policy) {
+ createFunctionWithSampleProfileElisionPolicy(M, "foo", Policy);
+ createFunctionWithSampleProfileElisionPolicy(M, "foo.bar", Policy);
+ createFunctionWithSampleProfileElisionPolicy(M, "foo.llvm.2465", Policy);
+ }
+
+ void testSuffixElisionPolicy(SampleProfileFormat Format, StringRef Policy,
+ const StringMap<uint64_t> &Expected) {
+ SmallVector<char, 128> ProfilePath;
+ std::error_code EC;
+ EC = llvm::sys::fs::createTemporaryFile("profile", "", ProfilePath);
+ ASSERT_TRUE(NoError(EC));
+ StringRef ProfileFile(ProfilePath.data(), ProfilePath.size());
+
+ Module M("my_module", Context);
+ setupModuleForElisionTest(&M, Policy);
+ StringMap<FunctionSamples> ProfMap = setupFcnSamplesForElisionTest(Policy);
+
+ // write profile
+ createWriter(Format, ProfileFile);
+ EC = Writer->write(ProfMap);
+ ASSERT_TRUE(NoError(EC));
+ Writer->getOutputStream().flush();
+
+ // read profile
+ readProfile(M, ProfileFile);
+ EC = Reader->read();
+ ASSERT_TRUE(NoError(EC));
+
+ for (auto I = Expected.begin(); I != Expected.end(); ++I) {
+ uint64_t Esamples = uint64_t(-1);
+ FunctionSamples *Samples = Reader->getSamplesFor(I->getKey());
+ if (Samples != nullptr)
+ Esamples = Samples->getTotalSamples();
+ ASSERT_EQ(I->getValue(), Esamples);
+ }
+ }
};
TEST_F(SampleProfTest, roundtrip_text_profile) {
@@ -251,4 +323,77 @@ TEST_F(SampleProfTest, sample_overflow_s
ASSERT_EQ(BodySamples.get(), Max);
}
+TEST_F(SampleProfTest, default_suffix_elision_text) {
+ // Default suffix elision policy: strip everything after first dot.
+ // This implies that all suffix variants will map to "foo", so
+ // we don't expect to see any entries for them in the sample
+ // profile.
+ StringMap<uint64_t> Expected;
+ Expected["foo"] = uint64_t(20301);
+ Expected["foo.bar"] = uint64_t(-1);
+ Expected["foo.llvm.2465"] = uint64_t(-1);
+ testSuffixElisionPolicy(SampleProfileFormat::SPF_Text, "", Expected);
+}
+
+TEST_F(SampleProfTest, default_suffix_elision_compact_binary) {
+ // Default suffix elision policy: strip everything after first dot.
+ // This implies that all suffix variants will map to "foo", so
+ // we don't expect to see any entries for them in the sample
+ // profile.
+ StringMap<uint64_t> Expected;
+ Expected["foo"] = uint64_t(20301);
+ Expected["foo.bar"] = uint64_t(-1);
+ Expected["foo.llvm.2465"] = uint64_t(-1);
+ testSuffixElisionPolicy(SampleProfileFormat::SPF_Compact_Binary, "",
+ Expected);
+}
+
+TEST_F(SampleProfTest, selected_suffix_elision_text) {
+ // Profile is created and searched using the "selected"
+ // suffix elision policy: we only strip a .XXX suffix if
+ // it matches a pattern known to be generated by the compiler
+ // (e.g. ".llvm.<digits>").
+ StringMap<uint64_t> Expected;
+ Expected["foo"] = uint64_t(20301);
+ Expected["foo.bar"] = uint64_t(20303);
+ Expected["foo.llvm.2465"] = uint64_t(-1);
+ testSuffixElisionPolicy(SampleProfileFormat::SPF_Text, "selected", Expected);
+}
+
+TEST_F(SampleProfTest, selected_suffix_elision_compact_binary) {
+ // Profile is created and searched using the "selected"
+ // suffix elision policy: we only strip a .XXX suffix if
+ // it matches a pattern known to be generated by the compiler
+ // (e.g. ".llvm.<digits>").
+ StringMap<uint64_t> Expected;
+ Expected["foo"] = uint64_t(20301);
+ Expected["foo.bar"] = uint64_t(20303);
+ Expected["foo.llvm.2465"] = uint64_t(-1);
+ testSuffixElisionPolicy(SampleProfileFormat::SPF_Compact_Binary, "selected",
+ Expected);
+}
+
+TEST_F(SampleProfTest, none_suffix_elision_text) {
+ // Profile is created and searched using the "none"
+ // suffix elision policy: no stripping of suffixes at all.
+ // Here we expect to see all variants in the profile.
+ StringMap<uint64_t> Expected;
+ Expected["foo"] = uint64_t(20301);
+ Expected["foo.bar"] = uint64_t(20303);
+ Expected["foo.llvm.2465"] = uint64_t(20305);
+ testSuffixElisionPolicy(SampleProfileFormat::SPF_Text, "none", Expected);
+}
+
+TEST_F(SampleProfTest, none_suffix_elision_compact_binary) {
+ // Profile is created and searched using the "none"
+ // suffix elision policy: no stripping of suffixes at all.
+ // Here we expect to see all variants in the profile.
+ StringMap<uint64_t> Expected;
+ Expected["foo"] = uint64_t(20301);
+ Expected["foo.bar"] = uint64_t(20303);
+ Expected["foo.llvm.2465"] = uint64_t(20305);
+ testSuffixElisionPolicy(SampleProfileFormat::SPF_Compact_Binary, "none",
+ Expected);
+}
+
} // end anonymous namespace
More information about the llvm-commits
mailing list