aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/ProfileData/SampleProfReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/ProfileData/SampleProfReader.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/ProfileData/SampleProfReader.cpp262
1 files changed, 182 insertions, 80 deletions
diff --git a/contrib/llvm-project/llvm/lib/ProfileData/SampleProfReader.cpp b/contrib/llvm-project/llvm/lib/ProfileData/SampleProfReader.cpp
index 6058eddb13dc..c99a19020511 100644
--- a/contrib/llvm-project/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/contrib/llvm-project/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -53,21 +53,23 @@ using namespace sampleprof;
// For ext-binary format profiles, the flag is set in the summary.
static cl::opt<bool> ProfileIsFSDisciminator(
"profile-isfs", cl::Hidden, cl::init(false),
- cl::desc("Profile uses flow senstive discriminators"));
+ cl::desc("Profile uses flow sensitive discriminators"));
/// Dump the function profile for \p FName.
///
-/// \param FName Name of the function to print.
+/// \param FContext Name + context of the function to print.
/// \param OS Stream to emit the output to.
-void SampleProfileReader::dumpFunctionProfile(StringRef FName,
+void SampleProfileReader::dumpFunctionProfile(SampleContext FContext,
raw_ostream &OS) {
- OS << "Function: " << FName << ": " << Profiles[FName];
+ OS << "Function: " << FContext.toString() << ": " << Profiles[FContext];
}
/// Dump all the function profiles found on stream \p OS.
void SampleProfileReader::dump(raw_ostream &OS) {
- for (const auto &I : Profiles)
- dumpFunctionProfile(I.getKey(), OS);
+ std::vector<NameFunctionSamples> V;
+ sortFuncProfiles(Profiles, V);
+ for (const auto &I : V)
+ dumpFunctionProfile(I.first, OS);
}
/// Parse \p Input as function head.
@@ -249,6 +251,7 @@ std::error_code SampleProfileReaderText::readImpl() {
bool SeenMetadata = false;
ProfileIsFS = ProfileIsFSDisciminator;
+ FunctionSamples::ProfileIsFS = ProfileIsFS;
for (; !LineIt.is_at_eof(); ++LineIt) {
if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#')
continue;
@@ -273,12 +276,11 @@ std::error_code SampleProfileReaderText::readImpl() {
return sampleprof_error::malformed;
}
SeenMetadata = false;
- SampleContext FContext(FName);
+ SampleContext FContext(FName, CSNameTable);
if (FContext.hasContext())
++CSProfileCount;
Profiles[FContext] = FunctionSamples();
FunctionSamples &FProfile = Profiles[FContext];
- FProfile.setName(FContext.getNameWithoutContext());
FProfile.setContext(FContext);
MergeResult(Result, FProfile.addTotalSamples(NumSamples));
MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
@@ -450,6 +452,13 @@ ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
return NameTable[*Idx];
}
+ErrorOr<SampleContext> SampleProfileReaderBinary::readSampleContextFromTable() {
+ auto FName(readStringFromTable());
+ if (std::error_code EC = FName.getError())
+ return EC;
+ return SampleContext(*FName);
+}
+
ErrorOr<StringRef> SampleProfileReaderExtBinaryBase::readStringFromTable() {
if (!FixedLengthMD5)
return SampleProfileReaderBinary::readStringFromTable();
@@ -576,18 +585,16 @@ SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
if (std::error_code EC = NumHeadSamples.getError())
return EC;
- auto FName(readStringFromTable());
- if (std::error_code EC = FName.getError())
+ ErrorOr<SampleContext> FContext(readSampleContextFromTable());
+ if (std::error_code EC = FContext.getError())
return EC;
- SampleContext FContext(*FName);
- Profiles[FContext] = FunctionSamples();
- FunctionSamples &FProfile = Profiles[FContext];
- FProfile.setName(FContext.getNameWithoutContext());
- FProfile.setContext(FContext);
+ Profiles[*FContext] = FunctionSamples();
+ FunctionSamples &FProfile = Profiles[*FContext];
+ FProfile.setContext(*FContext);
FProfile.addHeadSamples(*NumHeadSamples);
- if (FContext.hasContext())
+ if (FContext->hasContext())
CSProfileCount++;
if (std::error_code EC = readProfile(FProfile))
@@ -597,6 +604,7 @@ SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
std::error_code SampleProfileReaderBinary::readImpl() {
ProfileIsFS = ProfileIsFSDisciminator;
+ FunctionSamples::ProfileIsFS = ProfileIsFS;
while (!at_eof()) {
if (std::error_code EC = readFuncProfile(Data))
return EC;
@@ -605,6 +613,31 @@ std::error_code SampleProfileReaderBinary::readImpl() {
return sampleprof_error::success;
}
+ErrorOr<SampleContextFrames>
+SampleProfileReaderExtBinaryBase::readContextFromTable() {
+ auto ContextIdx = readNumber<uint32_t>();
+ if (std::error_code EC = ContextIdx.getError())
+ return EC;
+ if (*ContextIdx >= CSNameTable->size())
+ return sampleprof_error::truncated_name_table;
+ return (*CSNameTable)[*ContextIdx];
+}
+
+ErrorOr<SampleContext>
+SampleProfileReaderExtBinaryBase::readSampleContextFromTable() {
+ if (ProfileIsCS) {
+ auto FContext(readContextFromTable());
+ if (std::error_code EC = FContext.getError())
+ return EC;
+ return SampleContext(*FContext);
+ } else {
+ auto FName(readStringFromTable());
+ if (std::error_code EC = FName.getError())
+ return EC;
+ return SampleContext(*FName);
+ }
+}
+
std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
Data = Start;
@@ -632,11 +665,17 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
return EC;
break;
}
+ case SecCSNameTable: {
+ if (std::error_code EC = readCSNameTableSec())
+ return EC;
+ break;
+ }
case SecLBRProfile:
if (std::error_code EC = readFuncProfiles())
return EC;
break;
case SecFuncOffsetTable:
+ FuncOffsetsOrdered = hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered);
if (std::error_code EC = readFuncOffsetTable())
return EC;
break;
@@ -682,17 +721,27 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
return EC;
FuncOffsetTable.reserve(*Size);
+
+ if (FuncOffsetsOrdered) {
+ OrderedFuncOffsets =
+ std::make_unique<std::vector<std::pair<SampleContext, uint64_t>>>();
+ OrderedFuncOffsets->reserve(*Size);
+ }
+
for (uint32_t I = 0; I < *Size; ++I) {
- auto FName(readStringFromTable());
- if (std::error_code EC = FName.getError())
+ auto FContext(readSampleContextFromTable());
+ if (std::error_code EC = FContext.getError())
return EC;
auto Offset = readNumber<uint64_t>();
if (std::error_code EC = Offset.getError())
return EC;
- FuncOffsetTable[*FName] = *Offset;
+ FuncOffsetTable[*FContext] = *Offset;
+ if (FuncOffsetsOrdered)
+ OrderedFuncOffsets->emplace_back(*FContext, *Offset);
}
+
return sampleprof_error::success;
}
@@ -721,75 +770,77 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
}
}
- if (useMD5()) {
- for (auto Name : FuncsToUse) {
- auto GUID = std::to_string(MD5Hash(Name));
- auto iter = FuncOffsetTable.find(StringRef(GUID));
- if (iter == FuncOffsetTable.end())
- continue;
- const uint8_t *FuncProfileAddr = Start + iter->second;
- assert(FuncProfileAddr < End && "out of LBRProfile section");
- if (std::error_code EC = readFuncProfile(FuncProfileAddr))
- return EC;
+ if (ProfileIsCS) {
+ DenseSet<uint64_t> FuncGuidsToUse;
+ if (useMD5()) {
+ for (auto Name : FuncsToUse)
+ FuncGuidsToUse.insert(Function::getGUID(Name));
}
- } else if (FunctionSamples::ProfileIsCS) {
- // Compute the ordered set of names, so we can
- // get all context profiles under a subtree by
- // iterating through the ordered names.
- struct Comparer {
- // Ignore the closing ']' when ordering context
- bool operator()(const StringRef &L, const StringRef &R) const {
- return L.substr(0, L.size() - 1) < R.substr(0, R.size() - 1);
+
+ // For each function in current module, load all context profiles for
+ // the function as well as their callee contexts which can help profile
+ // guided importing for ThinLTO. This can be achieved by walking
+ // through an ordered context container, where contexts are laid out
+ // as if they were walked in preorder of a context trie. While
+ // traversing the trie, a link to the highest common ancestor node is
+ // kept so that all of its decendants will be loaded.
+ assert(OrderedFuncOffsets.get() &&
+ "func offset table should always be sorted in CS profile");
+ const SampleContext *CommonContext = nullptr;
+ for (const auto &NameOffset : *OrderedFuncOffsets) {
+ const auto &FContext = NameOffset.first;
+ auto FName = FContext.getName();
+ // For function in the current module, keep its farthest ancestor
+ // context. This can be used to load itself and its child and
+ // sibling contexts.
+ if ((useMD5() && FuncGuidsToUse.count(std::stoull(FName.data()))) ||
+ (!useMD5() && (FuncsToUse.count(FName) ||
+ (Remapper && Remapper->exist(FName))))) {
+ if (!CommonContext || !CommonContext->IsPrefixOf(FContext))
+ CommonContext = &FContext;
}
- };
- std::set<StringRef, Comparer> OrderedNames;
- for (auto Name : FuncOffsetTable) {
- OrderedNames.insert(Name.first);
- }
- // For each function in current module, load all
- // context profiles for the function.
- for (auto NameOffset : FuncOffsetTable) {
- StringRef ContextName = NameOffset.first;
- SampleContext FContext(ContextName);
- auto FuncName = FContext.getNameWithoutContext();
- if (!FuncsToUse.count(FuncName) &&
- (!Remapper || !Remapper->exist(FuncName)))
- continue;
-
- // For each context profile we need, try to load
- // all context profile in the subtree. This can
- // help profile guided importing for ThinLTO.
- auto It = OrderedNames.find(ContextName);
- while (It != OrderedNames.end() &&
- It->startswith(ContextName.substr(0, ContextName.size() - 1))) {
- const uint8_t *FuncProfileAddr = Start + FuncOffsetTable[*It];
+ if (CommonContext == &FContext ||
+ (CommonContext && CommonContext->IsPrefixOf(FContext))) {
+ // Load profile for the current context which originated from
+ // the common ancestor.
+ const uint8_t *FuncProfileAddr = Start + NameOffset.second;
assert(FuncProfileAddr < End && "out of LBRProfile section");
if (std::error_code EC = readFuncProfile(FuncProfileAddr))
return EC;
- // Remove loaded context profile so we won't
- // load it repeatedly.
- It = OrderedNames.erase(It);
}
}
} else {
- for (auto NameOffset : FuncOffsetTable) {
- SampleContext FContext(NameOffset.first);
- auto FuncName = FContext.getNameWithoutContext();
- if (!FuncsToUse.count(FuncName) &&
- (!Remapper || !Remapper->exist(FuncName)))
- continue;
- const uint8_t *FuncProfileAddr = Start + NameOffset.second;
- assert(FuncProfileAddr < End && "out of LBRProfile section");
- if (std::error_code EC = readFuncProfile(FuncProfileAddr))
- return EC;
+ if (useMD5()) {
+ for (auto Name : FuncsToUse) {
+ auto GUID = std::to_string(MD5Hash(Name));
+ auto iter = FuncOffsetTable.find(StringRef(GUID));
+ if (iter == FuncOffsetTable.end())
+ continue;
+ const uint8_t *FuncProfileAddr = Start + iter->second;
+ assert(FuncProfileAddr < End && "out of LBRProfile section");
+ if (std::error_code EC = readFuncProfile(FuncProfileAddr))
+ return EC;
+ }
+ } else {
+ for (auto NameOffset : FuncOffsetTable) {
+ SampleContext FContext(NameOffset.first);
+ auto FuncName = FContext.getName();
+ if (!FuncsToUse.count(FuncName) &&
+ (!Remapper || !Remapper->exist(FuncName)))
+ continue;
+ const uint8_t *FuncProfileAddr = Start + NameOffset.second;
+ assert(FuncProfileAddr < End && "out of LBRProfile section");
+ if (std::error_code EC = readFuncProfile(FuncProfileAddr))
+ return EC;
+ }
}
}
Data = End;
}
assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
"Cannot have both context-sensitive and regular profile");
- assert(ProfileIsCS == (CSProfileCount > 0) &&
+ assert((!CSProfileCount || ProfileIsCS) &&
"Section flag should be consistent with actual profile");
return sampleprof_error::success;
}
@@ -885,6 +936,7 @@ std::error_code SampleProfileReaderCompactBinary::readImpl() {
// given a module.
bool LoadFuncsToBeUsed = collectFuncsFromModule();
ProfileIsFS = ProfileIsFSDisciminator;
+ FunctionSamples::ProfileIsFS = ProfileIsFS;
std::vector<uint64_t> OffsetsToUse;
if (!LoadFuncsToBeUsed) {
// load all the function profiles.
@@ -983,22 +1035,62 @@ std::error_code SampleProfileReaderExtBinaryBase::readNameTableSec(bool IsMD5) {
return SampleProfileReaderBinary::readNameTable();
}
+// Read in the CS name table section, which basically contains a list of context
+// vectors. Each element of a context vector, aka a frame, refers to the
+// underlying raw function names that are stored in the name table, as well as
+// a callsite identifier that only makes sense for non-leaf frames.
+std::error_code SampleProfileReaderExtBinaryBase::readCSNameTableSec() {
+ auto Size = readNumber<uint32_t>();
+ if (std::error_code EC = Size.getError())
+ return EC;
+
+ std::vector<SampleContextFrameVector> *PNameVec =
+ new std::vector<SampleContextFrameVector>();
+ PNameVec->reserve(*Size);
+ for (uint32_t I = 0; I < *Size; ++I) {
+ PNameVec->emplace_back(SampleContextFrameVector());
+ auto ContextSize = readNumber<uint32_t>();
+ if (std::error_code EC = ContextSize.getError())
+ return EC;
+ for (uint32_t J = 0; J < *ContextSize; ++J) {
+ auto FName(readStringFromTable());
+ if (std::error_code EC = FName.getError())
+ return EC;
+ auto LineOffset = readNumber<uint64_t>();
+ if (std::error_code EC = LineOffset.getError())
+ return EC;
+
+ if (!isOffsetLegal(*LineOffset))
+ return std::error_code();
+
+ auto Discriminator = readNumber<uint64_t>();
+ if (std::error_code EC = Discriminator.getError())
+ return EC;
+
+ PNameVec->back().emplace_back(
+ FName.get(), LineLocation(LineOffset.get(), Discriminator.get()));
+ }
+ }
+
+ // From this point the underlying object of CSNameTable should be immutable.
+ CSNameTable.reset(PNameVec);
+ return sampleprof_error::success;
+}
+
std::error_code
SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) {
while (Data < End) {
- auto FName(readStringFromTable());
- if (std::error_code EC = FName.getError())
+ auto FContext(readSampleContextFromTable());
+ if (std::error_code EC = FContext.getError())
return EC;
- SampleContext FContext(*FName);
- bool ProfileInMap = Profiles.count(FContext);
-
+ bool ProfileInMap = Profiles.count(*FContext);
if (ProfileIsProbeBased) {
auto Checksum = readNumber<uint64_t>();
if (std::error_code EC = Checksum.getError())
return EC;
if (ProfileInMap)
- Profiles[FContext].setFunctionHash(*Checksum);
+ Profiles[*FContext].setFunctionHash(*Checksum);
}
if (ProfileHasAttribute) {
@@ -1006,7 +1098,7 @@ SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) {
if (std::error_code EC = Attributes.getError())
return EC;
if (ProfileInMap)
- Profiles[FContext].getContext().setAllAttributes(*Attributes);
+ Profiles[*FContext].getContext().setAllAttributes(*Attributes);
}
}
@@ -1132,6 +1224,16 @@ static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator))
Flags.append("fs-discriminator,");
break;
+ case SecFuncOffsetTable:
+ if (hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered))
+ Flags.append("ordered,");
+ break;
+ case SecFuncMetadata:
+ if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased))
+ Flags.append("probe,");
+ if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute))
+ Flags.append("attr,");
+ break;
default:
break;
}