forked from OSchip/llvm-project
Revert "Handle inline stacks in gcov-encoded sample profiles."
This reverts commit r249644. The buildbots are failing the new test I added. Investigating. llvm-svn: 249648
This commit is contained in:
parent
129552b375
commit
a082040ded
|
@ -208,7 +208,7 @@ typedef DenseMap<CallsiteLocation, FunctionSamples> CallsiteSampleMap;
|
||||||
class FunctionSamples {
|
class FunctionSamples {
|
||||||
public:
|
public:
|
||||||
FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
|
FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
|
||||||
void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const;
|
void print(raw_ostream &OS = dbgs());
|
||||||
void addTotalSamples(unsigned Num) { TotalSamples += Num; }
|
void addTotalSamples(unsigned Num) { TotalSamples += Num; }
|
||||||
void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
|
void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
|
||||||
void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
|
void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
|
||||||
|
@ -302,22 +302,6 @@ private:
|
||||||
/// are an offset from the start of the function.
|
/// are an offset from the start of the function.
|
||||||
BodySampleMap BodySamples;
|
BodySampleMap BodySamples;
|
||||||
|
|
||||||
/// Map call sites to collected samples for the called function.
|
|
||||||
///
|
|
||||||
/// Each entry in this map corresponds to all the samples
|
|
||||||
/// collected for the inlined function call at the given
|
|
||||||
/// location. For example, given:
|
|
||||||
///
|
|
||||||
/// void foo() {
|
|
||||||
/// 1 bar();
|
|
||||||
/// ...
|
|
||||||
/// 8 baz();
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// If the bar() and baz() calls were inlined inside foo(), this
|
|
||||||
/// map will contain two entries. One for all the samples collected
|
|
||||||
/// in the call to bar() at line offset 1, the other for all the samples
|
|
||||||
/// collected in the call to baz() at line offset 8.
|
|
||||||
CallsiteSampleMap CallsiteSamples;
|
CallsiteSampleMap CallsiteSamples;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,7 @@ struct SourceInfo {
|
||||||
uint32_t Discriminator;
|
uint32_t Discriminator;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SmallVector<FunctionSamples *, 10> InlineCallStack;
|
typedef std::vector<SourceInfo> SourceStack;
|
||||||
|
|
||||||
// Supported histogram types in GCC. Currently, we only need support for
|
// Supported histogram types in GCC. Currently, we only need support for
|
||||||
// call target histograms.
|
// call target histograms.
|
||||||
|
@ -220,8 +220,9 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::error_code readNameTable();
|
std::error_code readNameTable();
|
||||||
std::error_code readOneFunctionProfile(const InlineCallStack &InlineStack,
|
std::error_code addSourceCount(StringRef Name, const SourceStack &Src,
|
||||||
bool Update, uint32_t Offset);
|
uint64_t Count);
|
||||||
|
std::error_code readOneFunctionProfile(const SourceStack &Stack, bool Update);
|
||||||
std::error_code readFunctionProfiles();
|
std::error_code readFunctionProfiles();
|
||||||
std::error_code skipNextWord();
|
std::error_code skipNextWord();
|
||||||
template <typename T> ErrorOr<T> readNumber();
|
template <typename T> ErrorOr<T> readNumber();
|
||||||
|
|
|
@ -84,18 +84,12 @@ protected:
|
||||||
class SampleProfileWriterText : public SampleProfileWriter {
|
class SampleProfileWriterText : public SampleProfileWriter {
|
||||||
public:
|
public:
|
||||||
SampleProfileWriterText(StringRef F, std::error_code &EC)
|
SampleProfileWriterText(StringRef F, std::error_code &EC)
|
||||||
: SampleProfileWriter(F, EC, sys::fs::F_Text), Indent(0) {}
|
: SampleProfileWriter(F, EC, sys::fs::F_Text) {}
|
||||||
|
|
||||||
bool write(StringRef FName, const FunctionSamples &S) override;
|
bool write(StringRef FName, const FunctionSamples &S) override;
|
||||||
bool write(const Module &M, StringMap<FunctionSamples> &P) {
|
bool write(const Module &M, StringMap<FunctionSamples> &P) {
|
||||||
return SampleProfileWriter::write(M, P);
|
return SampleProfileWriter::write(M, P);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/// Indent level to use when writing.
|
|
||||||
///
|
|
||||||
/// This is used when printing inlined callees.
|
|
||||||
unsigned Indent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Sample-based profile writer (binary format).
|
/// \brief Sample-based profile writer (binary format).
|
||||||
|
|
|
@ -132,14 +132,13 @@ using namespace llvm;
|
||||||
/// \brief Print the samples collected for a function on stream \p OS.
|
/// \brief Print the samples collected for a function on stream \p OS.
|
||||||
///
|
///
|
||||||
/// \param OS Stream to emit the output to.
|
/// \param OS Stream to emit the output to.
|
||||||
void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const {
|
void FunctionSamples::print(raw_ostream &OS) {
|
||||||
OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size()
|
OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size()
|
||||||
<< " sampled lines\n";
|
<< " sampled lines\n";
|
||||||
for (const auto &SI : BodySamples) {
|
for (const auto &SI : BodySamples) {
|
||||||
LineLocation Loc = SI.first;
|
LineLocation Loc = SI.first;
|
||||||
const SampleRecord &Sample = SI.second;
|
const SampleRecord &Sample = SI.second;
|
||||||
OS.indent(Indent);
|
OS << "\tline offset: " << Loc.LineOffset
|
||||||
OS << "line offset: " << Loc.LineOffset
|
|
||||||
<< ", discriminator: " << Loc.Discriminator
|
<< ", discriminator: " << Loc.Discriminator
|
||||||
<< ", number of samples: " << Sample.getSamples();
|
<< ", number of samples: " << Sample.getSamples();
|
||||||
if (Sample.hasCalls()) {
|
if (Sample.hasCalls()) {
|
||||||
|
@ -149,15 +148,7 @@ void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const {
|
||||||
}
|
}
|
||||||
OS << "\n";
|
OS << "\n";
|
||||||
}
|
}
|
||||||
for (const auto &CS : CallsiteSamples) {
|
OS << "\n";
|
||||||
CallsiteLocation Loc = CS.first;
|
|
||||||
const FunctionSamples &CalleeSamples = CS.second;
|
|
||||||
OS.indent(Indent);
|
|
||||||
OS << "line offset: " << Loc.LineOffset
|
|
||||||
<< ", discriminator: " << Loc.Discriminator
|
|
||||||
<< ", inlined callee: " << Loc.CalleeName << ": ";
|
|
||||||
CalleeSamples.print(OS, Indent + 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Dump the function profile for \p FName.
|
/// \brief Dump the function profile for \p FName.
|
||||||
|
@ -275,7 +266,7 @@ static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth,
|
||||||
std::error_code SampleProfileReaderText::read() {
|
std::error_code SampleProfileReaderText::read() {
|
||||||
line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
|
line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
|
||||||
|
|
||||||
InlineCallStack InlineStack;
|
SmallVector<FunctionSamples *, 10> InlineStack;
|
||||||
|
|
||||||
for (; !LineIt.is_at_eof(); ++LineIt) {
|
for (; !LineIt.is_at_eof(); ++LineIt) {
|
||||||
if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#')
|
if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#')
|
||||||
|
@ -568,18 +559,31 @@ std::error_code SampleProfileReaderGCC::readFunctionProfiles() {
|
||||||
if (!GcovBuffer.readInt(NumFunctions))
|
if (!GcovBuffer.readInt(NumFunctions))
|
||||||
return sampleprof_error::truncated;
|
return sampleprof_error::truncated;
|
||||||
|
|
||||||
InlineCallStack Stack;
|
SourceStack Stack;
|
||||||
for (uint32_t I = 0; I < NumFunctions; ++I)
|
for (uint32_t I = 0; I < NumFunctions; ++I)
|
||||||
if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
|
if (std::error_code EC = readOneFunctionProfile(Stack, true))
|
||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
return sampleprof_error::success;
|
return sampleprof_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
|
std::error_code SampleProfileReaderGCC::addSourceCount(StringRef Name,
|
||||||
const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
|
const SourceStack &Src,
|
||||||
|
uint64_t Count) {
|
||||||
|
if (Src.size() == 0 || Src[0].Malformed())
|
||||||
|
return sampleprof_error::malformed;
|
||||||
|
FunctionSamples &FProfile = Profiles[Name];
|
||||||
|
FProfile.addTotalSamples(Count);
|
||||||
|
// FIXME(dnovillo) - Properly update inline stack for FnName.
|
||||||
|
FProfile.addBodySamples(Src[0].Line, Src[0].Discriminator, Count);
|
||||||
|
return sampleprof_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code
|
||||||
|
SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack,
|
||||||
|
bool Update) {
|
||||||
uint64_t HeadCount = 0;
|
uint64_t HeadCount = 0;
|
||||||
if (InlineStack.size() == 0)
|
if (Stack.size() == 0)
|
||||||
if (!GcovBuffer.readInt64(HeadCount))
|
if (!GcovBuffer.readInt64(HeadCount))
|
||||||
return sampleprof_error::truncated;
|
return sampleprof_error::truncated;
|
||||||
|
|
||||||
|
@ -593,31 +597,15 @@ std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
|
||||||
if (!GcovBuffer.readInt(NumPosCounts))
|
if (!GcovBuffer.readInt(NumPosCounts))
|
||||||
return sampleprof_error::truncated;
|
return sampleprof_error::truncated;
|
||||||
|
|
||||||
uint32_t NumCallsites;
|
uint32_t NumCallSites;
|
||||||
if (!GcovBuffer.readInt(NumCallsites))
|
if (!GcovBuffer.readInt(NumCallSites))
|
||||||
return sampleprof_error::truncated;
|
return sampleprof_error::truncated;
|
||||||
|
|
||||||
FunctionSamples *FProfile = nullptr;
|
if (Stack.size() == 0) {
|
||||||
if (InlineStack.size() == 0) {
|
FunctionSamples &FProfile = Profiles[Name];
|
||||||
// If this is a top function that we have already processed, do not
|
FProfile.addHeadSamples(HeadCount);
|
||||||
// update its profile again. This happens in the presence of
|
if (FProfile.getTotalSamples() > 0)
|
||||||
// function aliases. Since these aliases share the same function
|
|
||||||
// body, there will be identical replicated profiles for the
|
|
||||||
// original function. In this case, we simply not bother updating
|
|
||||||
// the profile of the original function.
|
|
||||||
FProfile = &Profiles[Name];
|
|
||||||
FProfile->addHeadSamples(HeadCount);
|
|
||||||
if (FProfile->getTotalSamples() > 0)
|
|
||||||
Update = false;
|
Update = false;
|
||||||
} else {
|
|
||||||
// Otherwise, we are reading an inlined instance. The top of the
|
|
||||||
// inline stack contains the profile of the caller. Insert this
|
|
||||||
// callee in the caller's CallsiteMap.
|
|
||||||
FunctionSamples *CallerProfile = InlineStack.front();
|
|
||||||
uint32_t LineOffset = Offset >> 16;
|
|
||||||
uint32_t Discriminator = Offset & 0xffff;
|
|
||||||
FProfile = &CallerProfile->functionSamplesAt(
|
|
||||||
CallsiteLocation(LineOffset, Discriminator, Name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t I = 0; I < NumPosCounts; ++I) {
|
for (uint32_t I = 0; I < NumPosCounts; ++I) {
|
||||||
|
@ -633,28 +621,13 @@ std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
|
||||||
if (!GcovBuffer.readInt64(Count))
|
if (!GcovBuffer.readInt64(Count))
|
||||||
return sampleprof_error::truncated;
|
return sampleprof_error::truncated;
|
||||||
|
|
||||||
// The line location is encoded in the offset as:
|
SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff);
|
||||||
// high 16 bits: line offset to the start of the function.
|
SourceStack NewStack;
|
||||||
// low 16 bits: discriminator.
|
NewStack.push_back(Info);
|
||||||
uint32_t LineOffset = Offset >> 16;
|
NewStack.insert(NewStack.end(), Stack.begin(), Stack.end());
|
||||||
uint32_t Discriminator = Offset & 0xffff;
|
if (Update)
|
||||||
|
addSourceCount(NewStack[NewStack.size() - 1].FuncName, NewStack, Count);
|
||||||
|
|
||||||
InlineCallStack NewStack;
|
|
||||||
NewStack.push_back(FProfile);
|
|
||||||
NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end());
|
|
||||||
if (Update) {
|
|
||||||
// Walk up the inline stack, adding the samples on this line to
|
|
||||||
// the total sample count of the callers in the chain.
|
|
||||||
for (auto CallerProfile : NewStack)
|
|
||||||
CallerProfile->addTotalSamples(Count);
|
|
||||||
|
|
||||||
// Update the body samples for the current profile.
|
|
||||||
FProfile->addBodySamples(LineOffset, Discriminator, Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the list of functions called at an indirect call site.
|
|
||||||
// These are all the targets that a function pointer (or virtual
|
|
||||||
// function) resolved at runtime.
|
|
||||||
for (uint32_t J = 0; J < NumTargets; J++) {
|
for (uint32_t J = 0; J < NumTargets; J++) {
|
||||||
uint32_t HistVal;
|
uint32_t HistVal;
|
||||||
if (!GcovBuffer.readInt(HistVal))
|
if (!GcovBuffer.readInt(HistVal))
|
||||||
|
@ -674,25 +647,24 @@ std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
|
||||||
|
|
||||||
if (Update) {
|
if (Update) {
|
||||||
FunctionSamples &TargetProfile = Profiles[TargetName];
|
FunctionSamples &TargetProfile = Profiles[TargetName];
|
||||||
TargetProfile.addCalledTargetSamples(LineOffset, Discriminator,
|
TargetProfile.addBodySamples(NewStack[0].Line,
|
||||||
TargetName, TargetCount);
|
NewStack[0].Discriminator, TargetCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process all the inlined callers into the current function. These
|
for (uint32_t I = 0; I < NumCallSites; I++) {
|
||||||
// are all the callsites that were inlined into this function.
|
|
||||||
for (uint32_t I = 0; I < NumCallsites; I++) {
|
|
||||||
// The offset is encoded as:
|
// The offset is encoded as:
|
||||||
// high 16 bits: line offset to the start of the function.
|
// high 16 bits: line offset to the start of the function.
|
||||||
// low 16 bits: discriminator.
|
// low 16 bits: discriminator.
|
||||||
uint32_t Offset;
|
uint32_t Offset;
|
||||||
if (!GcovBuffer.readInt(Offset))
|
if (!GcovBuffer.readInt(Offset))
|
||||||
return sampleprof_error::truncated;
|
return sampleprof_error::truncated;
|
||||||
InlineCallStack NewStack;
|
SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff);
|
||||||
NewStack.push_back(FProfile);
|
SourceStack NewStack;
|
||||||
NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end());
|
NewStack.push_back(Info);
|
||||||
if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
|
NewStack.insert(NewStack.end(), Stack.begin(), Stack.end());
|
||||||
|
if (std::error_code EC = readOneFunctionProfile(NewStack, Update))
|
||||||
return EC;
|
return EC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,15 +31,15 @@ using namespace llvm;
|
||||||
|
|
||||||
/// \brief Write samples to a text file.
|
/// \brief Write samples to a text file.
|
||||||
bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
|
bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
|
||||||
OS << FName << ":" << S.getTotalSamples();
|
if (S.empty())
|
||||||
if (Indent == 0)
|
return true;
|
||||||
OS << ":" << S.getHeadSamples();
|
|
||||||
OS << "\n";
|
OS << FName << ":" << S.getTotalSamples() << ":" << S.getHeadSamples()
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
for (const auto &I : S.getBodySamples()) {
|
for (const auto &I : S.getBodySamples()) {
|
||||||
LineLocation Loc = I.first;
|
LineLocation Loc = I.first;
|
||||||
const SampleRecord &Sample = I.second;
|
const SampleRecord &Sample = I.second;
|
||||||
OS.indent(Indent + 1);
|
|
||||||
if (Loc.Discriminator == 0)
|
if (Loc.Discriminator == 0)
|
||||||
OS << Loc.LineOffset << ": ";
|
OS << Loc.LineOffset << ": ";
|
||||||
else
|
else
|
||||||
|
@ -52,19 +52,6 @@ bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
|
||||||
OS << "\n";
|
OS << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
Indent += 1;
|
|
||||||
for (const auto &I : S.getCallsiteSamples()) {
|
|
||||||
CallsiteLocation Loc = I.first;
|
|
||||||
const FunctionSamples &CalleeSamples = I.second;
|
|
||||||
OS.indent(Indent);
|
|
||||||
if (Loc.Discriminator == 0)
|
|
||||||
OS << Loc.LineOffset << ": ";
|
|
||||||
else
|
|
||||||
OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
|
|
||||||
write(Loc.CalleeName, CalleeSamples);
|
|
||||||
}
|
|
||||||
Indent -= 1;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,24 +0,0 @@
|
||||||
Tests for sample profiles encoded in GCC's gcov format.
|
|
||||||
|
|
||||||
1- Show all functions. This profile has a single main() function with several
|
|
||||||
inlined callees.
|
|
||||||
RUN: llvm-profdata show --sample %p/Inputs/gcc-sample-profile.gcov | FileCheck %s --check-prefix=SHOW1
|
|
||||||
SHOW1: Function: main: 364084, 0, 6 sampled lines
|
|
||||||
SHOW1: line offset: 2, discriminator: 3, inlined callee: _Z3fool: 243786, 0, 3 sampled lines
|
|
||||||
SHOW1: line offset: 1, discriminator: 3, inlined callee: _Z3bari: 0, 0, 2 sampled lines
|
|
||||||
SHOW1: line offset: 1, discriminator: 8, inlined callee: _Z3bari: 0, 0, 2 sampled lines
|
|
||||||
SHOW1: line offset: 1, discriminator: 7, inlined callee: _Z3bari: 98558, 0, 2 sampled lines
|
|
||||||
|
|
||||||
2- Convert the profile to text encoding and check that they are both
|
|
||||||
identical.
|
|
||||||
RUN: llvm-profdata merge --sample %p/Inputs/gcc-sample-profile.gcov --text -o - | llvm-profdata show --sample - -o %t-text
|
|
||||||
RUN: llvm-profdata show --sample %p/Inputs/gcc-sample-profile.gcov -o %t-gcov
|
|
||||||
RUN: diff %t-text %t-gcov
|
|
||||||
|
|
||||||
4- Merge the gcov and text encodings of the profile and check that the
|
|
||||||
counters have doubled.
|
|
||||||
RUN: llvm-profdata merge --sample --text %p/Inputs/gcc-sample-profile.gcov -o %t-gcov
|
|
||||||
RUN: llvm-profdata merge --sample --text %p/Inputs/gcc-sample-profile.gcov %t-gcov -o - | FileCheck %s --check-prefix=MERGE1
|
|
||||||
MERGE1: main:728168:0
|
|
||||||
MERGE1: 2.3: 120298
|
|
||||||
MERGE1: 2.3: _Z3fool:487572
|
|
Loading…
Reference in New Issue