//===----------------------------------------------------------------------===//
#include "llvm/ProfileData/SampleProfReader.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallVector.h"
using namespace llvm::sampleprof;
using namespace llvm;
-/// \brief Print the samples collected for a function on stream \p OS.
-///
-/// \param OS Stream to emit the output to.
-void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const {
- OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size()
- << " sampled lines\n";
- for (const auto &SI : BodySamples) {
- LineLocation Loc = SI.first;
- const SampleRecord &Sample = SI.second;
- OS.indent(Indent);
- OS << "line offset: " << Loc.LineOffset
- << ", discriminator: " << Loc.Discriminator
- << ", number of samples: " << Sample.getSamples();
- if (Sample.hasCalls()) {
- OS << ", calls:";
- for (const auto &I : Sample.getCallTargets())
- OS << " " << I.first() << ":" << I.second;
- }
- OS << "\n";
- }
- for (const auto &CS : CallsiteSamples) {
- 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.
///
/// \param FName Name of the function to print.
/// \param OS Stream to emit the output to.
void SampleProfileReader::dumpFunctionProfile(StringRef FName,
raw_ostream &OS) {
- OS << "Function: " << FName << ": ";
- Profiles[FName].print(OS);
+ OS << "Function: " << FName << ": " << Profiles[FName];
}
/// \brief Dump all the function profiles found on stream \p OS.
///
/// \returns true if parsing is successful.
static bool ParseHead(const StringRef &Input, StringRef &FName,
- unsigned &NumSamples, unsigned &NumHeadSamples) {
+ uint64_t &NumSamples, uint64_t &NumHeadSamples) {
if (Input[0] == ' ')
return false;
size_t n2 = Input.rfind(':');
return true;
}
+
+/// \brief Returns true if line offset \p L is legal (only has 16 bits).
+static bool isOffsetLegal(unsigned L) {
+ return (L & 0xffff) == L;
+}
+
/// \brief Parse \p Input as line sample.
///
/// \param Input input line.
/// \param TargetCountMap map from indirect call target to count.
///
/// returns true if parsing is successful.
-static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth,
- unsigned &NumSamples, unsigned &LineOffset,
- unsigned &Discriminator, StringRef &CalleeName,
- DenseMap<StringRef, unsigned> &TargetCountMap) {
+static bool ParseLine(const StringRef &Input, bool &IsCallsite, uint32_t &Depth,
+ uint64_t &NumSamples, uint32_t &LineOffset,
+ uint32_t &Discriminator, StringRef &CalleeName,
+ DenseMap<StringRef, uint64_t> &TargetCountMap) {
for (Depth = 0; Input[Depth] == ' '; Depth++)
;
if (Depth == 0)
StringRef Loc = Input.substr(Depth, n1 - Depth);
size_t n2 = Loc.find('.');
if (n2 == StringRef::npos) {
- if (Loc.getAsInteger(10, LineOffset))
+ if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset))
return false;
Discriminator = 0;
} else {
if (n3 != StringRef::npos) {
pair = Rest.substr(0, n3);
}
- int n4 = pair.find(':');
- unsigned count;
+ size_t n4 = pair.find(':');
+ uint64_t count;
if (pair.substr(n4 + 1).getAsInteger(10, count))
return false;
TargetCountMap[pair.substr(0, n4)] = count;
}
} else {
IsCallsite = true;
- int n3 = Rest.find_last_of(':');
+ size_t n3 = Rest.find_last_of(':');
CalleeName = Rest.substr(0, n3);
if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
return false;
/// \returns true if the file was loaded successfully, false otherwise.
std::error_code SampleProfileReaderText::read() {
line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
+ sampleprof_error Result = sampleprof_error::success;
InlineCallStack InlineStack;
// The only requirement we place on the identifier, then, is that it
// should not begin with a number.
if ((*LineIt)[0] != ' ') {
- unsigned NumSamples, NumHeadSamples;
+ uint64_t NumSamples, NumHeadSamples;
StringRef FName;
if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) {
reportError(LineIt.line_number(),
}
Profiles[FName] = FunctionSamples();
FunctionSamples &FProfile = Profiles[FName];
- FProfile.addTotalSamples(NumSamples);
- FProfile.addHeadSamples(NumHeadSamples);
+ MergeResult(Result, FProfile.addTotalSamples(NumSamples));
+ MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
InlineStack.clear();
InlineStack.push_back(&FProfile);
} else {
- unsigned NumSamples;
+ uint64_t NumSamples;
StringRef FName;
- DenseMap<StringRef, unsigned> TargetCountMap;
+ DenseMap<StringRef, uint64_t> TargetCountMap;
bool IsCallsite;
- unsigned Depth, LineOffset, Discriminator;
+ uint32_t Depth, LineOffset, Discriminator;
if (!ParseLine(*LineIt, IsCallsite, Depth, NumSamples, LineOffset,
Discriminator, FName, TargetCountMap)) {
reportError(LineIt.line_number(),
}
FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
CallsiteLocation(LineOffset, Discriminator, FName));
- FSamples.addTotalSamples(NumSamples);
+ MergeResult(Result, FSamples.addTotalSamples(NumSamples));
InlineStack.push_back(&FSamples);
} else {
while (InlineStack.size() > Depth) {
}
FunctionSamples &FProfile = *InlineStack.back();
for (const auto &name_count : TargetCountMap) {
- FProfile.addCalledTargetSamples(LineOffset, Discriminator,
- name_count.first, name_count.second);
+ MergeResult(Result, FProfile.addCalledTargetSamples(
+ LineOffset, Discriminator, name_count.first,
+ name_count.second));
}
- FProfile.addBodySamples(LineOffset, Discriminator, NumSamples);
+ MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
+ NumSamples));
}
}
}
- return sampleprof_error::success;
+ return Result;
+}
+
+bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) {
+ bool result = false;
+
+ // Check that the first non-comment line is a valid function header.
+ line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
+ if (!LineIt.is_at_eof()) {
+ if ((*LineIt)[0] != ' ') {
+ uint64_t NumSamples, NumHeadSamples;
+ StringRef FName;
+ result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
+ }
+ }
+
+ return result;
}
template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
std::error_code EC;
- auto Idx = readNumber<unsigned>();
+ auto Idx = readNumber<uint32_t>();
if (std::error_code EC = Idx.getError())
return EC;
if (*Idx >= NameTable.size())
std::error_code
SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
- auto Val = readNumber<unsigned>();
- if (std::error_code EC = Val.getError())
- return EC;
- FProfile.addTotalSamples(*Val);
-
- Val = readNumber<unsigned>();
- if (std::error_code EC = Val.getError())
+ auto NumSamples = readNumber<uint64_t>();
+ if (std::error_code EC = NumSamples.getError())
return EC;
- FProfile.addHeadSamples(*Val);
+ FProfile.addTotalSamples(*NumSamples);
// Read the samples in the body.
- auto NumRecords = readNumber<unsigned>();
+ auto NumRecords = readNumber<uint32_t>();
if (std::error_code EC = NumRecords.getError())
return EC;
- for (unsigned I = 0; I < *NumRecords; ++I) {
+ for (uint32_t I = 0; I < *NumRecords; ++I) {
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;
if (std::error_code EC = NumSamples.getError())
return EC;
- auto NumCalls = readNumber<unsigned>();
+ auto NumCalls = readNumber<uint32_t>();
if (std::error_code EC = NumCalls.getError())
return EC;
- for (unsigned J = 0; J < *NumCalls; ++J) {
+ for (uint32_t J = 0; J < *NumCalls; ++J) {
auto CalledFunction(readStringFromTable());
if (std::error_code EC = CalledFunction.getError())
return EC;
}
// Read all the samples for inlined function calls.
- auto NumCallsites = readNumber<unsigned>();
+ auto NumCallsites = readNumber<uint32_t>();
if (std::error_code EC = NumCallsites.getError())
return EC;
- for (unsigned J = 0; J < *NumCallsites; ++J) {
+ for (uint32_t J = 0; J < *NumCallsites; ++J) {
auto LineOffset = readNumber<uint64_t>();
if (std::error_code EC = LineOffset.getError())
return EC;
std::error_code SampleProfileReaderBinary::read() {
while (!at_eof()) {
+ auto NumHeadSamples = readNumber<uint64_t>();
+ if (std::error_code EC = NumHeadSamples.getError())
+ return EC;
+
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
Profiles[*FName] = FunctionSamples();
FunctionSamples &FProfile = Profiles[*FName];
+ FProfile.addHeadSamples(*NumHeadSamples);
+
if (std::error_code EC = readProfile(FProfile))
return EC;
}
return sampleprof_error::unsupported_version;
// Read the name table.
- auto Size = readNumber<size_t>();
+ auto Size = readNumber<uint32_t>();
if (std::error_code EC = Size.getError())
return EC;
NameTable.reserve(*Size);
- for (size_t I = 0; I < *Size; ++I) {
+ for (uint32_t I = 0; I < *Size; ++I) {
auto Name(readString());
if (std::error_code EC = Name.getError())
return EC;
auto Buffer = std::move(BufferOrErr.get());
// Sanity check the file.
- if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
+ if (Buffer->getBufferSize() > std::numeric_limits<uint32_t>::max())
return sampleprof_error::too_large;
return std::move(Buffer);
auto BufferOrError = setupMemoryBuffer(Filename);
if (std::error_code EC = BufferOrError.getError())
return EC;
+ return create(BufferOrError.get(), C);
+}
- auto Buffer = std::move(BufferOrError.get());
+/// \brief Create a sample profile reader based on the format of the input data.
+///
+/// \param B The memory buffer to create the reader from (assumes ownership).
+///
+/// \param Reader The reader to instantiate according to \p Filename's format.
+///
+/// \param C The LLVM context to use to emit diagnostics.
+///
+/// \returns an error code indicating the status of the created reader.
+ErrorOr<std::unique_ptr<SampleProfileReader>>
+SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C) {
std::unique_ptr<SampleProfileReader> Reader;
- if (SampleProfileReaderBinary::hasFormat(*Buffer))
- Reader.reset(new SampleProfileReaderBinary(std::move(Buffer), C));
- else if (SampleProfileReaderGCC::hasFormat(*Buffer))
- Reader.reset(new SampleProfileReaderGCC(std::move(Buffer), C));
+ if (SampleProfileReaderBinary::hasFormat(*B))
+ Reader.reset(new SampleProfileReaderBinary(std::move(B), C));
+ else if (SampleProfileReaderGCC::hasFormat(*B))
+ Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
+ else if (SampleProfileReaderText::hasFormat(*B))
+ Reader.reset(new SampleProfileReaderText(std::move(B), C));
else
- Reader.reset(new SampleProfileReaderText(std::move(Buffer), C));
+ return sampleprof_error::unrecognized_format;
if (std::error_code EC = Reader->readHeader())
return EC;