Skip to content

Commit

Permalink
[SampleFDO] Add indexing for function profiles so they can be loaded …
Browse files Browse the repository at this point in the history
…on demand

in ExtBinary format

Currently for Text, Binary and ExtBinary format profiles, when we compile a
module with samplefdo, even if there is no function showing up in the profile,
we have to load all the function profiles from the profile input. That is a
waste of compile time.

CompactBinary format profile has already had the support of loading function
profiles on demand. In this patch, we add the support to load profile on
demand for ExtBinary format. It will work no matter the sections in ExtBinary
format profile are compressed or not. Experiment shows it reduces the time to
compile a server benchmark by 30%.

When profile remapping and loading function profiles on demand are both used,
extra work needs to be done so that the loading on demand process will take
the name remapping into consideration. It will be addressed in a follow-up
patch.

Differential Revision: https://reviews.llvm.org/D68601

llvm-svn: 374233
  • Loading branch information
wmi-11 committed Oct 9, 2019
1 parent 411497c commit 09dcfe6
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 58 deletions.
3 changes: 3 additions & 0 deletions llvm/include/llvm/ProfileData/SampleProf.h
Expand Up @@ -120,6 +120,7 @@ enum SecType {
SecProfSummary = 1,
SecNameTable = 2,
SecProfileSymbolList = 3,
SecFuncOffsetTable = 4,
// marker for the first type of profile.
SecFuncProfileFirst = 32,
SecLBRProfile = SecFuncProfileFirst
Expand All @@ -135,6 +136,8 @@ static inline std::string getSecName(SecType Type) {
return "NameTableSection";
case SecProfileSymbolList:
return "ProfileSymbolListSection";
case SecFuncOffsetTable:
return "FuncOffsetTableSection";
case SecLBRProfile:
return "LBRProfileSection";
}
Expand Down
21 changes: 17 additions & 4 deletions llvm/include/llvm/ProfileData/SampleProfReader.h
Expand Up @@ -279,7 +279,7 @@ class SampleProfileReader {
/// Print the profile for \p FName on stream \p OS.
void dumpFunctionProfile(StringRef FName, raw_ostream &OS = dbgs());

virtual void collectFuncsToUse(const Module &M) {}
virtual void collectFuncsFrom(const Module &M) {}

/// Print all the profiles on stream \p OS.
void dump(raw_ostream &OS = dbgs());
Expand Down Expand Up @@ -424,7 +424,7 @@ class SampleProfileReaderBinary : public SampleProfileReader {
bool at_eof() const { return Data >= End; }

/// Read the next function profile instance.
std::error_code readFuncProfile();
std::error_code readFuncProfile(const uint8_t *Start);

/// Read the contents of the given profile instance.
std::error_code readProfile(FunctionSamples &FProfile);
Expand Down Expand Up @@ -526,7 +526,17 @@ class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
virtual std::error_code verifySPMagic(uint64_t Magic) override;
virtual std::error_code readOneSection(const uint8_t *Start, uint64_t Size,
SecType Type) override;
std::error_code readProfileSymbolList(uint64_t Size);
std::error_code readProfileSymbolList();
std::error_code readFuncOffsetTable();
std::error_code readFuncProfiles();

/// The table mapping from function name to the offset of its FunctionSample
/// towards file start.
DenseMap<StringRef, uint64_t> FuncOffsetTable;
/// The set containing the functions to use when compiling a module.
DenseSet<StringRef> FuncsToUse;
/// Use all functions from the input profile.
bool UseAllFuncs = true;

public:
SampleProfileReaderExtBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
Expand All @@ -539,6 +549,9 @@ class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
virtual std::unique_ptr<ProfileSymbolList> getProfileSymbolList() override {
return std::move(ProfSymList);
};

/// Collect functions with definitions in Module \p M.
void collectFuncsFrom(const Module &M) override;
};

class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary {
Expand Down Expand Up @@ -571,7 +584,7 @@ class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary {
std::error_code read() override;

/// Collect functions to be used when compiling Module \p M.
void collectFuncsToUse(const Module &M) override;
void collectFuncsFrom(const Module &M) override;
};

using InlineCallStack = SmallVector<FunctionSamples *, 10>;
Expand Down
44 changes: 33 additions & 11 deletions llvm/include/llvm/ProfileData/SampleProfWriter.h
Expand Up @@ -153,14 +153,15 @@ class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
protected:
uint64_t markSectionStart(SecType Type);
std::error_code addNewSection(SecType Sec, uint64_t SectionStart);
virtual void initSectionLayout() = 0;
virtual void initSectionHdrLayout() = 0;
virtual std::error_code
writeSections(const StringMap<FunctionSamples> &ProfileMap) = 0;

// Specifiy the section layout in the profile. Note that the order in
// SecHdrTable (order to collect sections) may be different from the
// order in SectionLayout (order to write out sections into profile).
SmallVector<SecHdrTableEntry, 8> SectionLayout;
// Specifiy the order of sections in section header table. Note
// the order of sections in the profile may be different that the
// order in SectionHdrLayout. sample Reader will follow the order
// in SectionHdrLayout to read each section.
SmallVector<SecHdrTableEntry, 8> SectionHdrLayout;

private:
void allocSecHdrTable();
Expand Down Expand Up @@ -193,23 +194,44 @@ class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase {
public:
SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS)
: SampleProfileWriterExtBinaryBase(OS) {
initSectionLayout();
initSectionHdrLayout();
}

virtual std::error_code writeSample(const FunctionSamples &S) override;
virtual void setProfileSymbolList(ProfileSymbolList *PSL) override {
ProfSymList = PSL;
};

private:
virtual void initSectionLayout() override {
SectionLayout = {{SecProfSummary, 0, 0, 0},
{SecNameTable, 0, 0, 0},
{SecLBRProfile, 0, 0, 0},
{SecProfileSymbolList, 0, 0, 0}};
virtual void initSectionHdrLayout() override {
// Note that SecFuncOffsetTable section is written after SecLBRProfile
// in the profile, but is put before SecLBRProfile in SectionHdrLayout.
//
// This is because sample reader follows the order of SectionHdrLayout to
// read each section, to read function profiles on demand sample reader
// need to get the offset of each function profile first.
//
// SecFuncOffsetTable section is written after SecLBRProfile in the
// profile because FuncOffsetTable needs to be populated while section
// SecLBRProfile is written.
SectionHdrLayout = {{SecProfSummary, 0, 0, 0},
{SecNameTable, 0, 0, 0},
{SecFuncOffsetTable, 0, 0, 0},
{SecLBRProfile, 0, 0, 0},
{SecProfileSymbolList, 0, 0, 0}};
};
virtual std::error_code
writeSections(const StringMap<FunctionSamples> &ProfileMap) override;
ProfileSymbolList *ProfSymList = nullptr;

// Save the start of SecLBRProfile so we can compute the offset to the
// start of SecLBRProfile for each Function's Profile and will keep it
// in FuncOffsetTable.
uint64_t SecLBRProfileStart;
// FuncOffsetTable maps function name to its profile offset in SecLBRProfile
// section. It is used to load function profile on demand.
MapVector<StringRef, uint64_t> FuncOffsetTable;
std::error_code writeFuncOffsetTable();
};

// CompactBinary is a compact format of binary profile which both reduces
Expand Down
102 changes: 81 additions & 21 deletions llvm/lib/ProfileData/SampleProfReader.cpp
Expand Up @@ -439,7 +439,9 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
return sampleprof_error::success;
}

std::error_code SampleProfileReaderBinary::readFuncProfile() {
std::error_code
SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
Data = Start;
auto NumHeadSamples = readNumber<uint64_t>();
if (std::error_code EC = NumHeadSamples.getError())
return EC;
Expand All @@ -461,7 +463,7 @@ std::error_code SampleProfileReaderBinary::readFuncProfile() {

std::error_code SampleProfileReaderBinary::read() {
while (!at_eof()) {
if (std::error_code EC = readFuncProfile())
if (std::error_code EC = readFuncProfile(Data))
return EC;
}

Expand All @@ -483,13 +485,15 @@ SampleProfileReaderExtBinary::readOneSection(const uint8_t *Start,
return EC;
break;
case SecLBRProfile:
while (Data < Start + Size) {
if (std::error_code EC = readFuncProfile())
return EC;
}
if (std::error_code EC = readFuncProfiles())
return EC;
break;
case SecProfileSymbolList:
if (std::error_code EC = readProfileSymbolList(Size))
if (std::error_code EC = readProfileSymbolList())
return EC;
break;
case SecFuncOffsetTable:
if (std::error_code EC = readFuncOffsetTable())
return EC;
break;
default:
Expand All @@ -498,15 +502,65 @@ SampleProfileReaderExtBinary::readOneSection(const uint8_t *Start,
return sampleprof_error::success;
}

std::error_code
SampleProfileReaderExtBinary::readProfileSymbolList(uint64_t Size) {
void SampleProfileReaderExtBinary::collectFuncsFrom(const Module &M) {
UseAllFuncs = false;
FuncsToUse.clear();
for (auto &F : M)
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
}

std::error_code SampleProfileReaderExtBinary::readFuncOffsetTable() {
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;

FuncOffsetTable.reserve(*Size);
for (uint32_t I = 0; I < *Size; ++I) {
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;

auto Offset = readNumber<uint64_t>();
if (std::error_code EC = Offset.getError())
return EC;

FuncOffsetTable[*FName] = *Offset;
}
return sampleprof_error::success;
}

std::error_code SampleProfileReaderExtBinary::readFuncProfiles() {
const uint8_t *Start = Data;
if (UseAllFuncs) {
while (Data < End) {
if (std::error_code EC = readFuncProfile(Data))
return EC;
}
assert(Data == End && "More data is read than expected");
return sampleprof_error::success;
}

for (auto Name : FuncsToUse) {
auto iter = FuncOffsetTable.find(Name);
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;
}
Data = End;
return sampleprof_error::success;
}

std::error_code SampleProfileReaderExtBinary::readProfileSymbolList() {
if (!ProfSymList)
ProfSymList = std::make_unique<ProfileSymbolList>();

if (std::error_code EC = ProfSymList->read(Data, Size))
if (std::error_code EC = ProfSymList->read(Data, End - Data))
return EC;

Data = Data + Size;
Data = End;
return sampleprof_error::success;
}

Expand Down Expand Up @@ -600,9 +654,9 @@ std::error_code SampleProfileReaderCompactBinary::read() {

for (auto Offset : OffsetsToUse) {
const uint8_t *SavedData = Data;
Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
Offset;
if (std::error_code EC = readFuncProfile())
if (std::error_code EC = readFuncProfile(
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
Offset))
return EC;
Data = SavedData;
}
Expand Down Expand Up @@ -719,8 +773,16 @@ uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) {
}

uint64_t SampleProfileReaderExtBinaryBase::getFileSize() {
auto &LastEntry = SecHdrTable.back();
return LastEntry.Offset + LastEntry.Size;
// Sections in SecHdrTable is not necessarily in the same order as
// sections in the profile because section like FuncOffsetTable needs
// to be written after section LBRProfile but needs to be read before
// section LBRProfile, so we cannot simply use the last entry in
// SecHdrTable to calculate the file size.
uint64_t FileSize = 0;
for (auto &Entry : SecHdrTable) {
FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
}
return FileSize;
}

bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) {
Expand Down Expand Up @@ -812,13 +874,11 @@ std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() {
return sampleprof_error::success;
}

void SampleProfileReaderCompactBinary::collectFuncsToUse(const Module &M) {
void SampleProfileReaderCompactBinary::collectFuncsFrom(const Module &M) {
UseAllFuncs = false;
FuncsToUse.clear();
for (auto &F : M) {
StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
FuncsToUse.insert(CanonName);
}
for (auto &F : M)
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
}

std::error_code SampleProfileReaderBinary::readSummaryEntry(
Expand Down

0 comments on commit 09dcfe6

Please sign in to comment.