aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ProfileData/SampleProfReader.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
commitb60736ec1405bb0a8dd40989f67ef4c93da068ab (patch)
tree5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /llvm/lib/ProfileData/SampleProfReader.cpp
parentcfca06d7963fa0909f90483b42a6d7d194d01e08 (diff)
Diffstat (limited to 'llvm/lib/ProfileData/SampleProfReader.cpp')
-rw-r--r--llvm/lib/ProfileData/SampleProfReader.cpp257
1 files changed, 209 insertions, 48 deletions
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index 03f1ac190b91..c42931174bc0 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -83,26 +83,52 @@ static bool ParseHead(const StringRef &Input, StringRef &FName,
/// Returns true if line offset \p L is legal (only has 16 bits).
static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; }
+/// Parse \p Input that contains metadata.
+/// Possible metadata:
+/// - CFG Checksum information:
+/// !CFGChecksum: 12345
+/// Stores the FunctionHash (a.k.a. CFG Checksum) into \p FunctionHash.
+static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash) {
+ if (!Input.startswith("!CFGChecksum:"))
+ return false;
+
+ StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim();
+ return !CFGInfo.getAsInteger(10, FunctionHash);
+}
+
+enum class LineType {
+ CallSiteProfile,
+ BodyProfile,
+ Metadata,
+};
+
/// Parse \p Input as line sample.
///
/// \param Input input line.
-/// \param IsCallsite true if the line represents an inlined callsite.
+/// \param LineTy Type of this line.
/// \param Depth the depth of the inline stack.
/// \param NumSamples total samples of the line/inlined callsite.
/// \param LineOffset line offset to the start of the function.
/// \param Discriminator discriminator of the line.
/// \param TargetCountMap map from indirect call target to count.
+/// \param FunctionHash the function's CFG hash, used by pseudo probe.
///
/// returns true if parsing is successful.
-static bool ParseLine(const StringRef &Input, bool &IsCallsite, uint32_t &Depth,
+static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth,
uint64_t &NumSamples, uint32_t &LineOffset,
uint32_t &Discriminator, StringRef &CalleeName,
- DenseMap<StringRef, uint64_t> &TargetCountMap) {
+ DenseMap<StringRef, uint64_t> &TargetCountMap,
+ uint64_t &FunctionHash) {
for (Depth = 0; Input[Depth] == ' '; Depth++)
;
if (Depth == 0)
return false;
+ if (Depth == 1 && Input[Depth] == '!') {
+ LineTy = LineType::Metadata;
+ return parseMetadata(Input.substr(Depth), FunctionHash);
+ }
+
size_t n1 = Input.find(':');
StringRef Loc = Input.substr(Depth, n1 - Depth);
size_t n2 = Loc.find('.');
@@ -118,8 +144,8 @@ static bool ParseLine(const StringRef &Input, bool &IsCallsite, uint32_t &Depth,
}
StringRef Rest = Input.substr(n1 + 2);
- if (Rest[0] >= '0' && Rest[0] <= '9') {
- IsCallsite = false;
+ if (isDigit(Rest[0])) {
+ LineTy = LineType::BodyProfile;
size_t n3 = Rest.find(' ');
if (n3 == StringRef::npos) {
if (Rest.getAsInteger(10, NumSamples))
@@ -176,7 +202,7 @@ static bool ParseLine(const StringRef &Input, bool &IsCallsite, uint32_t &Depth,
n3 = n4;
}
} else {
- IsCallsite = true;
+ LineTy = LineType::CallSiteProfile;
size_t n3 = Rest.find_last_of(':');
CalleeName = Rest.substr(0, n3);
if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
@@ -196,6 +222,13 @@ std::error_code SampleProfileReaderText::readImpl() {
sampleprof_error Result = sampleprof_error::success;
InlineCallStack InlineStack;
+ int CSProfileCount = 0;
+ int RegularProfileCount = 0;
+ uint32_t ProbeProfileCount = 0;
+
+ // SeenMetadata tracks whether we have processed metadata for the current
+ // top-level function profile.
+ bool SeenMetadata = false;
for (; !LineIt.is_at_eof(); ++LineIt) {
if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#')
@@ -220,9 +253,16 @@ std::error_code SampleProfileReaderText::readImpl() {
"Expected 'mangled_name:NUM:NUM', found " + *LineIt);
return sampleprof_error::malformed;
}
- Profiles[FName] = FunctionSamples();
- FunctionSamples &FProfile = Profiles[FName];
- FProfile.setName(FName);
+ SeenMetadata = false;
+ SampleContext FContext(FName);
+ if (FContext.hasContext())
+ ++CSProfileCount;
+ else
+ ++RegularProfileCount;
+ Profiles[FContext] = FunctionSamples();
+ FunctionSamples &FProfile = Profiles[FContext];
+ FProfile.setName(FContext.getName());
+ FProfile.setContext(FContext);
MergeResult(Result, FProfile.addTotalSamples(NumSamples));
MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
InlineStack.clear();
@@ -231,25 +271,35 @@ std::error_code SampleProfileReaderText::readImpl() {
uint64_t NumSamples;
StringRef FName;
DenseMap<StringRef, uint64_t> TargetCountMap;
- bool IsCallsite;
uint32_t Depth, LineOffset, Discriminator;
- if (!ParseLine(*LineIt, IsCallsite, Depth, NumSamples, LineOffset,
- Discriminator, FName, TargetCountMap)) {
+ LineType LineTy;
+ uint64_t FunctionHash;
+ if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
+ Discriminator, FName, TargetCountMap, FunctionHash)) {
reportError(LineIt.line_number(),
"Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
*LineIt);
return sampleprof_error::malformed;
}
- if (IsCallsite) {
- while (InlineStack.size() > Depth) {
- InlineStack.pop_back();
- }
+ if (SeenMetadata && LineTy != LineType::Metadata) {
+ // Metadata must be put at the end of a function profile.
+ reportError(LineIt.line_number(),
+ "Found non-metadata after metadata: " + *LineIt);
+ return sampleprof_error::malformed;
+ }
+ while (InlineStack.size() > Depth) {
+ InlineStack.pop_back();
+ }
+ switch (LineTy) {
+ case LineType::CallSiteProfile: {
FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
LineLocation(LineOffset, Discriminator))[std::string(FName)];
FSamples.setName(FName);
MergeResult(Result, FSamples.addTotalSamples(NumSamples));
InlineStack.push_back(&FSamples);
- } else {
+ break;
+ }
+ case LineType::BodyProfile: {
while (InlineStack.size() > Depth) {
InlineStack.pop_back();
}
@@ -261,9 +311,27 @@ std::error_code SampleProfileReaderText::readImpl() {
}
MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
NumSamples));
+ break;
+ }
+ case LineType::Metadata: {
+ FunctionSamples &FProfile = *InlineStack.back();
+ FProfile.setFunctionHash(FunctionHash);
+ ++ProbeProfileCount;
+ SeenMetadata = true;
+ break;
+ }
}
}
}
+
+ assert((RegularProfileCount == 0 || CSProfileCount == 0) &&
+ "Cannot have both context-sensitive and regular profile");
+ ProfileIsCS = (CSProfileCount > 0);
+ assert((ProbeProfileCount == 0 || ProbeProfileCount == Profiles.size()) &&
+ "Cannot have both probe-based profiles and regular profiles");
+ ProfileIsProbeBased = (ProbeProfileCount > 0);
+ FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
+
if (Result == sampleprof_error::success)
computeSummary();
@@ -354,6 +422,34 @@ ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
return NameTable[*Idx];
}
+ErrorOr<StringRef> SampleProfileReaderExtBinaryBase::readStringFromTable() {
+ if (!FixedLengthMD5)
+ return SampleProfileReaderBinary::readStringFromTable();
+
+ // read NameTable index.
+ auto Idx = readStringIndex(NameTable);
+ if (std::error_code EC = Idx.getError())
+ return EC;
+
+ // Check whether the name to be accessed has been accessed before,
+ // if not, read it from memory directly.
+ StringRef &SR = NameTable[*Idx];
+ if (SR.empty()) {
+ const uint8_t *SavedData = Data;
+ Data = MD5NameMemStart + ((*Idx) * sizeof(uint64_t));
+ auto FID = readUnencodedNumber<uint64_t>();
+ if (std::error_code EC = FID.getError())
+ return EC;
+ // Save the string converted from uint64_t in MD5StringBuf. All the
+ // references to the name are all StringRefs refering to the string
+ // in MD5StringBuf.
+ MD5StringBuf->push_back(std::to_string(*FID));
+ SR = MD5StringBuf->back();
+ Data = SavedData;
+ }
+ return SR;
+}
+
ErrorOr<StringRef> SampleProfileReaderCompactBinary::readStringFromTable() {
auto Idx = readStringIndex(NameTable);
if (std::error_code EC = Idx.getError())
@@ -470,7 +566,7 @@ std::error_code SampleProfileReaderBinary::readImpl() {
return sampleprof_error::success;
}
-std::error_code SampleProfileReaderExtBinary::readOneSection(
+std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
Data = Start;
End = Start + Size;
@@ -481,37 +577,56 @@ std::error_code SampleProfileReaderExtBinary::readOneSection(
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
Summary->setPartialProfile(true);
break;
- case SecNameTable:
- if (std::error_code EC = readNameTableSec(
- hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name)))
+ case SecNameTable: {
+ FixedLengthMD5 =
+ hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5);
+ bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
+ assert((!FixedLengthMD5 || UseMD5) &&
+ "If FixedLengthMD5 is true, UseMD5 has to be true");
+ if (std::error_code EC = readNameTableSec(UseMD5))
return EC;
break;
+ }
case SecLBRProfile:
if (std::error_code EC = readFuncProfiles())
return EC;
break;
- case SecProfileSymbolList:
- if (std::error_code EC = readProfileSymbolList())
- return EC;
- break;
case SecFuncOffsetTable:
if (std::error_code EC = readFuncOffsetTable())
return EC;
break;
+ case SecFuncMetadata:
+ ProfileIsProbeBased =
+ hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased);
+ FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
+ if (std::error_code EC = readFuncMetadata())
+ return EC;
+ break;
+ case SecProfileSymbolList:
+ if (std::error_code EC = readProfileSymbolList())
+ return EC;
+ break;
default:
+ if (std::error_code EC = readCustomSection(Entry))
+ return EC;
break;
}
return sampleprof_error::success;
}
-void SampleProfileReaderExtBinary::collectFuncsFrom(const Module &M) {
+void SampleProfileReaderExtBinaryBase::collectFuncsFrom(const Module &M) {
UseAllFuncs = false;
FuncsToUse.clear();
for (auto &F : M)
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
}
-std::error_code SampleProfileReaderExtBinary::readFuncOffsetTable() {
+std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
+ // If there are more than one FuncOffsetTable, the profile read associated
+ // with previous FuncOffsetTable has to be done before next FuncOffsetTable
+ // is read.
+ FuncOffsetTable.clear();
+
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;
@@ -531,7 +646,7 @@ std::error_code SampleProfileReaderExtBinary::readFuncOffsetTable() {
return sampleprof_error::success;
}
-std::error_code SampleProfileReaderExtBinary::readFuncProfiles() {
+std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
const uint8_t *Start = Data;
if (UseAllFuncs) {
while (Data < End) {
@@ -576,7 +691,7 @@ std::error_code SampleProfileReaderExtBinary::readFuncProfiles() {
return sampleprof_error::success;
}
-std::error_code SampleProfileReaderExtBinary::readProfileSymbolList() {
+std::error_code SampleProfileReaderExtBinaryBase::readProfileSymbolList() {
if (!ProfSymList)
ProfSymList = std::make_unique<ProfileSymbolList>();
@@ -625,6 +740,10 @@ std::error_code SampleProfileReaderExtBinaryBase::readImpl() {
if (!Entry.Size)
continue;
+ // Skip sections without context when SkipFlatProf is true.
+ if (SkipFlatProf && hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
+ continue;
+
const uint8_t *SecStart = BufStart + Entry.Offset;
uint64_t SecSize = Entry.Size;
@@ -709,7 +828,7 @@ std::error_code SampleProfileReaderBinary::readNameTable() {
auto Size = readNumber<uint32_t>();
if (std::error_code EC = Size.getError())
return EC;
- NameTable.reserve(*Size);
+ NameTable.reserve(*Size + NameTable.size());
for (uint32_t I = 0; I < *Size; ++I) {
auto Name(readString());
if (std::error_code EC = Name.getError())
@@ -720,13 +839,24 @@ std::error_code SampleProfileReaderBinary::readNameTable() {
return sampleprof_error::success;
}
-std::error_code SampleProfileReaderExtBinary::readMD5NameTable() {
+std::error_code SampleProfileReaderExtBinaryBase::readMD5NameTable() {
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;
- NameTable.reserve(*Size);
MD5StringBuf = std::make_unique<std::vector<std::string>>();
MD5StringBuf->reserve(*Size);
+ if (FixedLengthMD5) {
+ // Preallocate and initialize NameTable so we can check whether a name
+ // index has been read before by checking whether the element in the
+ // NameTable is empty, meanwhile readStringIndex can do the boundary
+ // check using the size of NameTable.
+ NameTable.resize(*Size + NameTable.size());
+
+ MD5NameMemStart = Data;
+ Data = Data + (*Size) * sizeof(uint64_t);
+ return sampleprof_error::success;
+ }
+ NameTable.reserve(*Size);
for (uint32_t I = 0; I < *Size; ++I) {
auto FID = readNumber<uint64_t>();
if (std::error_code EC = FID.getError())
@@ -739,12 +869,29 @@ std::error_code SampleProfileReaderExtBinary::readMD5NameTable() {
return sampleprof_error::success;
}
-std::error_code SampleProfileReaderExtBinary::readNameTableSec(bool IsMD5) {
+std::error_code SampleProfileReaderExtBinaryBase::readNameTableSec(bool IsMD5) {
if (IsMD5)
return readMD5NameTable();
return SampleProfileReaderBinary::readNameTable();
}
+std::error_code SampleProfileReaderExtBinaryBase::readFuncMetadata() {
+ if (!ProfileIsProbeBased)
+ return sampleprof_error::success;
+ for (unsigned I = 0; I < Profiles.size(); ++I) {
+ auto FName(readStringFromTable());
+ if (std::error_code EC = FName.getError())
+ return EC;
+
+ auto Checksum = readNumber<uint64_t>();
+ if (std::error_code EC = Checksum.getError())
+ return EC;
+
+ Profiles[*FName].setFunctionHash(*Checksum);
+ }
+ return sampleprof_error::success;
+}
+
std::error_code SampleProfileReaderCompactBinary::readNameTable() {
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
@@ -759,7 +906,8 @@ std::error_code SampleProfileReaderCompactBinary::readNameTable() {
return sampleprof_error::success;
}
-std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTableEntry() {
+std::error_code
+SampleProfileReaderExtBinaryBase::readSecHdrTableEntry(uint32_t Idx) {
SecHdrTableEntry Entry;
auto Type = readUnencodedNumber<uint64_t>();
if (std::error_code EC = Type.getError())
@@ -781,6 +929,7 @@ std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTableEntry() {
return EC;
Entry.Size = *Size;
+ Entry.LayoutIndex = Idx;
SecHdrTable.push_back(std::move(Entry));
return sampleprof_error::success;
}
@@ -791,7 +940,7 @@ std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() {
return EC;
for (uint32_t i = 0; i < (*EntryNum); i++)
- if (std::error_code EC = readSecHdrTableEntry())
+ if (std::error_code EC = readSecHdrTableEntry(i))
return EC;
return sampleprof_error::success;
@@ -813,11 +962,12 @@ std::error_code SampleProfileReaderExtBinaryBase::readHeader() {
}
uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) {
+ uint64_t Size = 0;
for (auto &Entry : SecHdrTable) {
if (Entry.Type == Type)
- return Entry.Size;
+ Size += Entry.Size;
}
- return 0;
+ return Size;
}
uint64_t SampleProfileReaderExtBinaryBase::getFileSize() {
@@ -840,9 +990,14 @@ static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
else
Flags.append("{");
+ if (hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
+ Flags.append("flat,");
+
switch (Entry.Type) {
case SecNameTable:
- if (hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name))
+ if (hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5))
+ Flags.append("fixlenmd5,");
+ else if (hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name))
Flags.append("md5,");
break;
case SecProfSummary:
@@ -867,7 +1022,7 @@ bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) {
<< ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
<< "\n";
;
- TotalSecsSize += getSectionSize(Entry.Type);
+ TotalSecsSize += Entry.Size;
}
uint64_t HeaderSize = SecHdrTable.front().Offset;
assert(HeaderSize + TotalSecsSize == getFileSize() &&
@@ -1201,7 +1356,7 @@ std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
InlineCallStack NewStack;
NewStack.push_back(FProfile);
- NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end());
+ llvm::append_range(NewStack, InlineStack);
if (Update) {
// Walk up the inline stack, adding the samples on this line to
// the total sample count of the callers in the chain.
@@ -1249,7 +1404,7 @@ std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
return sampleprof_error::truncated;
InlineCallStack NewStack;
NewStack.push_back(FProfile);
- NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end());
+ llvm::append_range(NewStack, InlineStack);
if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
return EC;
}
@@ -1290,19 +1445,25 @@ void SampleProfileReaderItaniumRemapper::applyRemapping(LLVMContext &Ctx) {
return;
}
+ // CSSPGO-TODO: Remapper is not yet supported.
+ // We will need to remap the entire context string.
assert(Remappings && "should be initialized while creating remapper");
- for (auto &Sample : Reader.getProfiles())
- if (auto Key = Remappings->insert(Sample.first()))
- SampleMap.insert({Key, &Sample.second});
+ for (auto &Sample : Reader.getProfiles()) {
+ DenseSet<StringRef> NamesInSample;
+ Sample.second.findAllNames(NamesInSample);
+ for (auto &Name : NamesInSample)
+ if (auto Key = Remappings->insert(Name))
+ NameMap.insert({Key, Name});
+ }
RemappingApplied = true;
}
-FunctionSamples *
-SampleProfileReaderItaniumRemapper::getSamplesFor(StringRef Fname) {
+Optional<StringRef>
+SampleProfileReaderItaniumRemapper::lookUpNameInProfile(StringRef Fname) {
if (auto Key = Remappings->lookup(Fname))
- return SampleMap.lookup(Key);
- return nullptr;
+ return NameMap.lookup(Key);
+ return None;
}
/// Prepare a memory buffer for the contents of \p Filename.