diff options
author | Rong Xu <xur@google.com> | 2022-11-29 22:23:47 -0800 |
---|---|---|
committer | Rong Xu <xur@google.com> | 2022-11-29 22:23:47 -0800 |
commit | 077baefc998dd55ba1b91d9c9e284ce5a8e0216e (patch) | |
tree | 7c4d7afa58a9e1137f795ca6a24e31627e91a6e1 /llvm/tools/llvm-profdata/llvm-profdata.cpp | |
parent | dabd2391765154848d35f172fbbeb68c88ff9dd4 (diff) | |
download | llvm-077baefc998dd55ba1b91d9c9e284ce5a8e0216e.zip llvm-077baefc998dd55ba1b91d9c9e284ce5a8e0216e.tar.gz llvm-077baefc998dd55ba1b91d9c9e284ce5a8e0216e.tar.bz2 |
[llvm-profdata] Use flattening sample profile in profile supplementation
We need to flatten the SampleFDO profile in profile supplementation
because the InstrFDO profile does not have inlined callsite counters.
Without flattening profile, FDO optimizations are not stable:
we will not supplement the second generation profile when the modified
functions are all inlined.
This patch fixes this issue: we will flatten the profile for functions
that appears in FDO profile.
Note that we only need to find the hot/warm functions in SampleFDO
profile, so we will not perform a full flatten. We will use
a DFS traversal to compute the accumulated entry count and max bodycount.
This is much cheaper than full flattening.
Differential Revision: https://reviews.llvm.org/D138893
Diffstat (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp')
-rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 112 |
1 files changed, 105 insertions, 7 deletions
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index c80d969..9b50379 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -632,6 +632,100 @@ adjustInstrProfile(std::unique_ptr<WriterContext> &WC, } }; + // We need to flatten the SampleFDO profile as the InstrFDO + // profile does not have inlined callsite profiles. + // One caveat is the pre-inlined function -- their samples + // should be collapsed into the caller function. + // Here we do a DFS traversal to get the flatten profile + // info: the sum of entrycount and the max of maxcount. + // Here is the algorithm: + // recursive (FS, root_name) { + // name = FS->getName(); + // get samples for FS; + // if (InstrProf.find(name) { + // root_name = name; + // } else { + // if (name is in static_func map) { + // root_name = static_name; + // } + // } + // update the Map entry for root_name; + // for (subfs: FS) { + // recursive(subfs, root_name); + // } + // } + // + // Here is an example. + // + // SampleProfile: + // foo:12345:1000 + // 1: 1000 + // 2.1: 1000 + // 15: 5000 + // 4: bar:1000 + // 1: 1000 + // 2: goo:3000 + // 1: 3000 + // 8: bar:40000 + // 1: 10000 + // 2: goo:30000 + // 1: 30000 + // + // InstrProfile has two entries: + // foo + // bar.cc:bar + // + // After BuildMaxSampleMap, we should have the following in FlattenSampleMap: + // {"foo", {1000, 5000}} + // {"bar.cc:bar", {11000, 30000}} + // + // foo's has an entry count of 1000, and max body count of 5000. + // bar.cc:bar has an entry count of 11000 (sum two callsites of 1000 and + // 10000), and max count of 30000 (from the callsite in line 8). + // + // Note that goo's count will remain in bar.cc:bar() as it does not have an + // entry in InstrProfile. + DenseMap<StringRef, std::pair<uint64_t, uint64_t>> FlattenSampleMap; + auto BuildMaxSampleMap = [&FlattenSampleMap, &StaticFuncMap, + &InstrProfileMap](const FunctionSamples &FS, + const StringRef &RootName) { + auto BuildMaxSampleMapImpl = [&](const FunctionSamples &FS, + const StringRef &RootName, + auto &BuildImpl) -> void { + const StringRef &Name = FS.getName(); + const StringRef *NewRootName = &RootName; + uint64_t EntrySample = FS.getHeadSamplesEstimate(); + uint64_t MaxBodySample = FS.getMaxCountInside(/* SkipCallSite*/ true); + + auto It = InstrProfileMap.find(Name); + if (It != InstrProfileMap.end()) { + NewRootName = &Name; + } else { + auto NewName = StaticFuncMap.find(Name); + if (NewName != StaticFuncMap.end()) { + It = InstrProfileMap.find(NewName->second.str()); + if (NewName->second != DuplicateNameStr) { + NewRootName = &NewName->second; + } + } else { + // Here the EntrySample is of an inlined function, so we should not + // update the EntrySample in the map. + EntrySample = 0; + } + } + EntrySample += FlattenSampleMap[*NewRootName].first; + MaxBodySample = + std::max(FlattenSampleMap[*NewRootName].second, MaxBodySample); + FlattenSampleMap[*NewRootName] = + std::make_pair(EntrySample, MaxBodySample); + + for (const auto &C : FS.getCallsiteSamples()) + for (const auto &F : C.second) + BuildImpl(F.second, *NewRootName, BuildImpl); + }; + BuildMaxSampleMapImpl(FS, RootName, BuildMaxSampleMapImpl); + }; + for (auto &PD : WC->Writer.getProfileData()) { // Populate IPBuilder. for (const auto &PDV : PD.getValue()) { @@ -650,6 +744,11 @@ adjustInstrProfile(std::unique_ptr<WriterContext> &WC, buildStaticFuncMap(FullName); } + for (auto &PD : Reader->getProfiles()) { + sampleprof::FunctionSamples &FS = PD.second; + BuildMaxSampleMap(FS, FS.getName()); + } + ProfileSummary InstrPS = *IPBuilder.getSummary(); ProfileSummary SamplePS = Reader->getSummary(); @@ -679,20 +778,19 @@ adjustInstrProfile(std::unique_ptr<WriterContext> &WC, // Find hot/warm functions in sample profile which is cold in instr profile // and adjust the profiles of those functions in the instr profile. - for (const auto &PD : Reader->getProfiles()) { - const sampleprof::FunctionSamples &FS = PD.second; - uint64_t SampleMaxCount = FS.getMaxCountInside(); + for (const auto &E : FlattenSampleMap) { + uint64_t SampleMaxCount = std::max(E.second.first, E.second.second); if (SampleMaxCount < ColdSampleThreshold) continue; - auto &FContext = PD.first; - auto It = InstrProfileMap.find(FContext.toString()); + const StringRef &Name = E.first; + auto It = InstrProfileMap.find(Name); if (It == InstrProfileMap.end()) { - auto NewName = StaticFuncMap.find(FContext.toString()); + auto NewName = StaticFuncMap.find(Name); if (NewName != StaticFuncMap.end()) { It = InstrProfileMap.find(NewName->second.str()); if (NewName->second == DuplicateNameStr) { WithColor::warning() - << "Static function " << FContext.toString() + << "Static function " << Name << " has multiple promoted names, cannot adjust profile.\n"; } } |