aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ProfileData/SampleProf.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/ProfileData/SampleProf.cpp
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
downloadsrc-344a3780b2e33f6ca763666c380202b18aab72a3.tar.gz
src-344a3780b2e33f6ca763666c380202b18aab72a3.zip
the upstream release/13.x branch was created.
Diffstat (limited to 'llvm/lib/ProfileData/SampleProf.cpp')
-rw-r--r--llvm/lib/ProfileData/SampleProf.cpp133
1 files changed, 127 insertions, 6 deletions
diff --git a/llvm/lib/ProfileData/SampleProf.cpp b/llvm/lib/ProfileData/SampleProf.cpp
index d6acc00e1a6f..60e707b146d5 100644
--- a/llvm/lib/ProfileData/SampleProf.cpp
+++ b/llvm/lib/ProfileData/SampleProf.cpp
@@ -16,6 +16,7 @@
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/PseudoProbe.h"
#include "llvm/ProfileData/SampleProfReader.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
@@ -29,12 +30,19 @@
using namespace llvm;
using namespace sampleprof;
+static cl::opt<uint64_t> ProfileSymbolListCutOff(
+ "profile-symbol-list-cutoff", cl::Hidden, cl::init(-1), cl::ZeroOrMore,
+ cl::desc("Cutoff value about how many symbols in profile symbol list "
+ "will be used. This is very useful for performance debugging"));
+
namespace llvm {
namespace sampleprof {
SampleProfileFormat FunctionSamples::Format;
bool FunctionSamples::ProfileIsProbeBased = false;
bool FunctionSamples::ProfileIsCS = false;
-bool FunctionSamples::UseMD5;
+bool FunctionSamples::UseMD5 = false;
+bool FunctionSamples::HasUniqSuffix = true;
+bool FunctionSamples::ProfileIsFS = false;
} // namespace sampleprof
} // namespace llvm
@@ -106,6 +114,18 @@ raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS,
return OS;
}
+/// Merge the samples in \p Other into this record.
+/// Optionally scale sample counts by \p Weight.
+sampleprof_error SampleRecord::merge(const SampleRecord &Other,
+ uint64_t Weight) {
+ sampleprof_error Result;
+ Result = addSamples(Other.getSamples(), Weight);
+ for (const auto &I : Other.getCallTargets()) {
+ MergeResult(Result, addCalledTarget(I.first(), I.second, Weight));
+ }
+ return Result;
+}
+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void LineLocation::dump() const { print(dbgs()); }
#endif
@@ -204,9 +224,15 @@ const FunctionSamples *FunctionSamples::findFunctionSamples(
const DILocation *PrevDIL = DIL;
for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
- S.push_back(std::make_pair(
- LineLocation(getOffset(DIL), DIL->getBaseDiscriminator()),
- PrevDIL->getScope()->getSubprogram()->getLinkageName()));
+ unsigned Discriminator;
+ if (ProfileIsFS)
+ Discriminator = DIL->getDiscriminator();
+ else
+ Discriminator = DIL->getBaseDiscriminator();
+
+ S.push_back(
+ std::make_pair(LineLocation(getOffset(DIL), Discriminator),
+ PrevDIL->getScope()->getSubprogram()->getLinkageName()));
PrevDIL = DIL;
}
if (S.size() == 0)
@@ -235,6 +261,8 @@ void FunctionSamples::findAllNames(DenseSet<StringRef> &NameSet) const {
const FunctionSamples *FunctionSamples::findFunctionSamplesAt(
const LineLocation &Loc, StringRef CalleeName,
SampleProfileReaderItaniumRemapper *Remapper) const {
+ CalleeName = getCanonicalFnName(CalleeName);
+
std::string CalleeGUID;
CalleeName = getRepInFormat(CalleeName, UseMD5, CalleeGUID);
@@ -274,16 +302,109 @@ std::error_code ProfileSymbolList::read(const uint8_t *Data,
uint64_t ListSize) {
const char *ListStart = reinterpret_cast<const char *>(Data);
uint64_t Size = 0;
- while (Size < ListSize) {
+ uint64_t StrNum = 0;
+ while (Size < ListSize && StrNum < ProfileSymbolListCutOff) {
StringRef Str(ListStart + Size);
add(Str);
Size += Str.size() + 1;
+ StrNum++;
}
- if (Size != ListSize)
+ if (Size != ListSize && StrNum != ProfileSymbolListCutOff)
return sampleprof_error::malformed;
return sampleprof_error::success;
}
+void SampleContextTrimmer::trimAndMergeColdContextProfiles(
+ uint64_t ColdCountThreshold, bool TrimColdContext, bool MergeColdContext,
+ uint32_t ColdContextFrameLength) {
+ if (!TrimColdContext && !MergeColdContext)
+ return;
+
+ // Nothing to merge if sample threshold is zero
+ if (ColdCountThreshold == 0)
+ return;
+
+ // Filter the cold profiles from ProfileMap and move them into a tmp
+ // container
+ std::vector<std::pair<StringRef, const FunctionSamples *>> ColdProfiles;
+ for (const auto &I : ProfileMap) {
+ const FunctionSamples &FunctionProfile = I.second;
+ if (FunctionProfile.getTotalSamples() >= ColdCountThreshold)
+ continue;
+ ColdProfiles.emplace_back(I.getKey(), &I.second);
+ }
+
+ // Remove the cold profile from ProfileMap and merge them into
+ // MergedProfileMap by the last K frames of context
+ StringMap<FunctionSamples> MergedProfileMap;
+ for (const auto &I : ColdProfiles) {
+ if (MergeColdContext) {
+ auto Ret = MergedProfileMap.try_emplace(
+ I.second->getContext().getContextWithLastKFrames(
+ ColdContextFrameLength),
+ FunctionSamples());
+ FunctionSamples &MergedProfile = Ret.first->second;
+ MergedProfile.merge(*I.second);
+ }
+ ProfileMap.erase(I.first);
+ }
+
+ // Move the merged profiles into ProfileMap;
+ for (const auto &I : MergedProfileMap) {
+ // Filter the cold merged profile
+ if (TrimColdContext && I.second.getTotalSamples() < ColdCountThreshold &&
+ ProfileMap.find(I.getKey()) == ProfileMap.end())
+ continue;
+ // Merge the profile if the original profile exists, otherwise just insert
+ // as a new profile
+ auto Ret = ProfileMap.try_emplace(I.getKey(), FunctionSamples());
+ if (Ret.second) {
+ SampleContext FContext(Ret.first->first(), RawContext);
+ FunctionSamples &FProfile = Ret.first->second;
+ FProfile.setContext(FContext);
+ FProfile.setName(FContext.getNameWithoutContext());
+ }
+ FunctionSamples &OrigProfile = Ret.first->second;
+ OrigProfile.merge(I.second);
+ }
+}
+
+void SampleContextTrimmer::canonicalizeContextProfiles() {
+ std::vector<StringRef> ProfilesToBeRemoved;
+ StringMap<FunctionSamples> ProfilesToBeAdded;
+ for (auto &I : ProfileMap) {
+ FunctionSamples &FProfile = I.second;
+ StringRef ContextStr = FProfile.getNameWithContext();
+ if (I.first() == ContextStr)
+ continue;
+
+ // Use the context string from FunctionSamples to update the keys of
+ // ProfileMap. They can get out of sync after context profile promotion
+ // through pre-inliner.
+ // Duplicate the function profile for later insertion to avoid a conflict
+ // caused by a context both to be add and to be removed. This could happen
+ // when a context is promoted to another context which is also promoted to
+ // the third context. For example, given an original context A @ B @ C that
+ // is promoted to B @ C and the original context B @ C which is promoted to
+ // just C, adding B @ C to the profile map while removing same context (but
+ // with different profiles) from the map can cause a conflict if they are
+ // not handled in a right order. This can be solved by just caching the
+ // profiles to be added.
+ auto Ret = ProfilesToBeAdded.try_emplace(ContextStr, FProfile);
+ (void)Ret;
+ assert(Ret.second && "Context conflict during canonicalization");
+ ProfilesToBeRemoved.push_back(I.first());
+ }
+
+ for (auto &I : ProfilesToBeRemoved) {
+ ProfileMap.erase(I);
+ }
+
+ for (auto &I : ProfilesToBeAdded) {
+ ProfileMap.try_emplace(I.first(), I.second);
+ }
+}
+
std::error_code ProfileSymbolList::write(raw_ostream &OS) {
// Sort the symbols before output. If doing compression.
// It will make the compression much more effective.