Sample profiles - Add a name table to the binary encoding.

Binary encoded profiles used to encode all function names inline at
every reference.  This is clearly suboptimal in terms of space.  This
patch fixes this by adding a name table to the header of the file.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@250241 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Diego Novillo 2015-10-13 22:48:46 +00:00
parent 5fa57d9ce3
commit db271655dd
7 changed files with 146 additions and 38 deletions

View File

@ -34,6 +34,8 @@ enum class sampleprof_error {
truncated,
malformed,
unrecognized_format,
unsupported_writing_format,
truncated_name_table,
not_implemented
};
@ -59,7 +61,7 @@ static inline uint64_t SPMagic() {
uint64_t('2') << (64 - 56) | uint64_t(0xff);
}
static inline uint64_t SPVersion() { return 100; }
static inline uint64_t SPVersion() { return 101; }
/// Represents the relative location of an instruction.
///

View File

@ -154,6 +154,9 @@ protected:
/// \returns the read value.
ErrorOr<StringRef> readString();
/// Read a string indirectly via the name table.
ErrorOr<StringRef> readStringFromTable();
/// \brief Return true if we've reached the end of file.
bool at_eof() const { return Data >= End; }
@ -165,6 +168,9 @@ protected:
/// \brief Points to the end of the buffer.
const uint8_t *End;
/// Function name table.
std::vector<StringRef> NameTable;
};
// Represents the source position in GCC sample profiles.

View File

@ -13,6 +13,7 @@
#ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
#define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
@ -35,30 +36,38 @@ public:
: OS(Filename, EC, Flags) {}
virtual ~SampleProfileWriter() {}
/// \brief Write sample profiles in \p S for function \p FName.
/// Write sample profiles in \p S for function \p FName.
///
/// \returns true if the file was updated successfully. False, otherwise.
virtual bool write(StringRef FName, const FunctionSamples &S) = 0;
/// \returns status code of the file update operation.
virtual std::error_code write(StringRef FName, const FunctionSamples &S) = 0;
/// \brief Write all the sample profiles in the given map of samples.
/// Write all the sample profiles in the given map of samples.
///
/// \returns true if the file was updated successfully. False, otherwise.
bool write(StringMap<FunctionSamples> &ProfileMap) {
for (auto &I : ProfileMap) {
/// \returns status code of the file update operation.
std::error_code write(const StringMap<FunctionSamples> &ProfileMap) {
if (std::error_code EC = writeHeader(ProfileMap))
return EC;
for (const auto &I : ProfileMap) {
StringRef FName = I.first();
FunctionSamples &Profile = I.second;
if (!write(FName, Profile))
return false;
const FunctionSamples &Profile = I.second;
if (std::error_code EC = write(FName, Profile))
return EC;
}
return true;
return sampleprof_error::success;
}
/// \brief Profile writer factory. Create a new writer based on the value of
/// \p Format.
/// Profile writer factory.
///
/// Create a new writer based on the value of \p Format.
static ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename, SampleProfileFormat Format);
protected:
/// \brief Write a file header for the profile file.
virtual std::error_code
writeHeader(const StringMap<FunctionSamples> &ProfileMap) = 0;
/// \brief Output stream where to emit the profile to.
raw_fd_ostream OS;
};
@ -69,7 +78,13 @@ public:
SampleProfileWriterText(StringRef F, std::error_code &EC)
: SampleProfileWriter(F, EC, sys::fs::F_Text), Indent(0) {}
bool write(StringRef FName, const FunctionSamples &S) override;
std::error_code write(StringRef FName, const FunctionSamples &S) override;
protected:
std::error_code
writeHeader(const StringMap<FunctionSamples> &ProfileMap) override {
return sampleprof_error::success;
}
private:
/// Indent level to use when writing.
@ -81,9 +96,21 @@ private:
/// \brief Sample-based profile writer (binary format).
class SampleProfileWriterBinary : public SampleProfileWriter {
public:
SampleProfileWriterBinary(StringRef F, std::error_code &EC);
SampleProfileWriterBinary(StringRef F, std::error_code &EC)
: SampleProfileWriter(F, EC, sys::fs::F_None), NameTable() {}
bool write(StringRef F, const FunctionSamples &S) override;
std::error_code write(StringRef F, const FunctionSamples &S) override;
protected:
std::error_code
writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
std::error_code writeNameIdx(StringRef FName);
private:
void addName(StringRef FName);
void addNames(const FunctionSamples &S);
MapVector<StringRef, unsigned> NameTable;
};
} // End namespace sampleprof

View File

@ -38,6 +38,10 @@ class SampleProfErrorCategoryType : public std::error_category {
return "Malformed profile data";
case sampleprof_error::unrecognized_format:
return "Unrecognized profile encoding format";
case sampleprof_error::unsupported_writing_format:
return "Profile encoding format unsupported for writing operations";
case sampleprof_error::truncated_name_table:
return "Truncated function name table";
case sampleprof_error::not_implemented:
return "Unimplemented feature";
}

View File

@ -378,6 +378,16 @@ ErrorOr<StringRef> SampleProfileReaderBinary::readString() {
return Str;
}
ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
std::error_code EC;
auto Idx = readNumber<unsigned>();
if (std::error_code EC = Idx.getError())
return EC;
if (*Idx >= NameTable.size())
return sampleprof_error::truncated_name_table;
return NameTable[*Idx];
}
std::error_code
SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
auto Val = readNumber<unsigned>();
@ -413,7 +423,7 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
return EC;
for (unsigned J = 0; J < *NumCalls; ++J) {
auto CalledFunction(readString());
auto CalledFunction(readStringFromTable());
if (std::error_code EC = CalledFunction.getError())
return EC;
@ -442,7 +452,7 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
if (std::error_code EC = Discriminator.getError())
return EC;
auto FName(readString());
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
@ -457,7 +467,7 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
std::error_code SampleProfileReaderBinary::read() {
while (!at_eof()) {
auto FName(readString());
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
@ -489,6 +499,18 @@ std::error_code SampleProfileReaderBinary::readHeader() {
else if (*Version != SPVersion())
return sampleprof_error::unsupported_version;
// Read the name table.
auto Size = readNumber<size_t>();
if (std::error_code EC = Size.getError())
return EC;
NameTable.reserve(*Size);
for (size_t I = 0; I < *Size; ++I) {
auto Name(readString());
if (std::error_code EC = Name.getError())
return EC;
NameTable.push_back(*Name);
}
return sampleprof_error::success;
}

View File

@ -30,7 +30,8 @@ using namespace llvm::sampleprof;
using namespace llvm;
/// \brief Write samples to a text file.
bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
std::error_code SampleProfileWriterText::write(StringRef FName,
const FunctionSamples &S) {
OS << FName << ":" << S.getTotalSamples();
if (Indent == 0)
OS << ":" << S.getHeadSamples();
@ -61,31 +62,74 @@ bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
OS << Loc.LineOffset << ": ";
else
OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
write(Loc.CalleeName, CalleeSamples);
if (std::error_code EC = write(Loc.CalleeName, CalleeSamples))
return EC;
}
Indent -= 1;
return true;
return sampleprof_error::success;
}
SampleProfileWriterBinary::SampleProfileWriterBinary(StringRef F,
std::error_code &EC)
: SampleProfileWriter(F, EC, sys::fs::F_None) {
if (EC)
return;
std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
const auto &ret = NameTable.find(FName);
if (ret == NameTable.end())
return sampleprof_error::truncated_name_table;
encodeULEB128(ret->second, OS);
return sampleprof_error::success;
}
// Write the file header.
void SampleProfileWriterBinary::addName(StringRef FName) {
auto NextIdx = NameTable.size();
NameTable.insert(std::make_pair(FName, NextIdx));
}
void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
// Add all the names in indirect call targets.
for (const auto &I : S.getBodySamples()) {
const SampleRecord &Sample = I.second;
for (const auto &J : Sample.getCallTargets())
addName(J.first());
}
// Recursively add all the names for inlined callsites.
for (const auto &J : S.getCallsiteSamples()) {
CallsiteLocation Loc = J.first;
const FunctionSamples &CalleeSamples = J.second;
addName(Loc.CalleeName);
addNames(CalleeSamples);
}
}
std::error_code SampleProfileWriterBinary::writeHeader(
const StringMap<FunctionSamples> &ProfileMap) {
// Write file magic identifier.
encodeULEB128(SPMagic(), OS);
encodeULEB128(SPVersion(), OS);
// Generate the name table for all the functions referenced in the profile.
for (const auto &I : ProfileMap) {
addName(I.first());
addNames(I.second);
}
// Write out the name table.
encodeULEB128(NameTable.size(), OS);
for (auto N : NameTable) {
OS << N.first;
encodeULEB128(0, OS);
}
return sampleprof_error::success;
}
/// \brief Write samples to a binary file.
///
/// \returns true if the samples were written successfully, false otherwise.
bool SampleProfileWriterBinary::write(StringRef FName,
const FunctionSamples &S) {
OS << FName;
encodeULEB128(0, OS);
std::error_code SampleProfileWriterBinary::write(StringRef FName,
const FunctionSamples &S) {
if (std::error_code EC = writeNameIdx(FName))
return EC;
encodeULEB128(S.getTotalSamples(), OS);
encodeULEB128(S.getHeadSamples(), OS);
encodeULEB128(S.getBodySamples().size(), OS);
@ -99,10 +143,10 @@ bool SampleProfileWriterBinary::write(StringRef FName,
encodeULEB128(Sample.getSamples(), OS);
encodeULEB128(Sample.getCallTargets().size(), OS);
for (const auto &J : Sample.getCallTargets()) {
std::string Callee = J.first();
StringRef Callee = J.first();
unsigned CalleeSamples = J.second;
OS << Callee;
encodeULEB128(0, OS);
if (std::error_code EC = writeNameIdx(Callee))
return EC;
encodeULEB128(CalleeSamples, OS);
}
}
@ -114,10 +158,11 @@ bool SampleProfileWriterBinary::write(StringRef FName,
const FunctionSamples &CalleeSamples = J.second;
encodeULEB128(Loc.LineOffset, OS);
encodeULEB128(Loc.Discriminator, OS);
write(Loc.CalleeName, CalleeSamples);
if (std::error_code EC = write(Loc.CalleeName, CalleeSamples))
return EC;
}
return true;
return sampleprof_error::success;
}
/// \brief Create a sample profile writer based on the specified format.
@ -138,6 +183,8 @@ SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
Writer.reset(new SampleProfileWriterBinary(Filename, EC));
else if (Format == SPF_Text)
Writer.reset(new SampleProfileWriterText(Filename, EC));
else if (Format == SPF_GCC)
EC = sampleprof_error::unsupported_writing_format;
else
EC = sampleprof_error::unrecognized_format;