Skip to content

Commit 09dcfe6

Browse files
committed
[SampleFDO] Add indexing for function profiles so they can be loaded 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
1 parent 411497c commit 09dcfe6

File tree

9 files changed

+207
-58
lines changed

9 files changed

+207
-58
lines changed

llvm/include/llvm/ProfileData/SampleProf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ enum SecType {
120120
SecProfSummary = 1,
121121
SecNameTable = 2,
122122
SecProfileSymbolList = 3,
123+
SecFuncOffsetTable = 4,
123124
// marker for the first type of profile.
124125
SecFuncProfileFirst = 32,
125126
SecLBRProfile = SecFuncProfileFirst
@@ -135,6 +136,8 @@ static inline std::string getSecName(SecType Type) {
135136
return "NameTableSection";
136137
case SecProfileSymbolList:
137138
return "ProfileSymbolListSection";
139+
case SecFuncOffsetTable:
140+
return "FuncOffsetTableSection";
138141
case SecLBRProfile:
139142
return "LBRProfileSection";
140143
}

llvm/include/llvm/ProfileData/SampleProfReader.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ class SampleProfileReader {
279279
/// Print the profile for \p FName on stream \p OS.
280280
void dumpFunctionProfile(StringRef FName, raw_ostream &OS = dbgs());
281281

282-
virtual void collectFuncsToUse(const Module &M) {}
282+
virtual void collectFuncsFrom(const Module &M) {}
283283

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

426426
/// Read the next function profile instance.
427-
std::error_code readFuncProfile();
427+
std::error_code readFuncProfile(const uint8_t *Start);
428428

429429
/// Read the contents of the given profile instance.
430430
std::error_code readProfile(FunctionSamples &FProfile);
@@ -526,7 +526,17 @@ class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
526526
virtual std::error_code verifySPMagic(uint64_t Magic) override;
527527
virtual std::error_code readOneSection(const uint8_t *Start, uint64_t Size,
528528
SecType Type) override;
529-
std::error_code readProfileSymbolList(uint64_t Size);
529+
std::error_code readProfileSymbolList();
530+
std::error_code readFuncOffsetTable();
531+
std::error_code readFuncProfiles();
532+
533+
/// The table mapping from function name to the offset of its FunctionSample
534+
/// towards file start.
535+
DenseMap<StringRef, uint64_t> FuncOffsetTable;
536+
/// The set containing the functions to use when compiling a module.
537+
DenseSet<StringRef> FuncsToUse;
538+
/// Use all functions from the input profile.
539+
bool UseAllFuncs = true;
530540

531541
public:
532542
SampleProfileReaderExtBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
@@ -539,6 +549,9 @@ class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
539549
virtual std::unique_ptr<ProfileSymbolList> getProfileSymbolList() override {
540550
return std::move(ProfSymList);
541551
};
552+
553+
/// Collect functions with definitions in Module \p M.
554+
void collectFuncsFrom(const Module &M) override;
542555
};
543556

544557
class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary {
@@ -571,7 +584,7 @@ class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary {
571584
std::error_code read() override;
572585

573586
/// Collect functions to be used when compiling Module \p M.
574-
void collectFuncsToUse(const Module &M) override;
587+
void collectFuncsFrom(const Module &M) override;
575588
};
576589

577590
using InlineCallStack = SmallVector<FunctionSamples *, 10>;

llvm/include/llvm/ProfileData/SampleProfWriter.h

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,15 @@ class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
153153
protected:
154154
uint64_t markSectionStart(SecType Type);
155155
std::error_code addNewSection(SecType Sec, uint64_t SectionStart);
156-
virtual void initSectionLayout() = 0;
156+
virtual void initSectionHdrLayout() = 0;
157157
virtual std::error_code
158158
writeSections(const StringMap<FunctionSamples> &ProfileMap) = 0;
159159

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

165166
private:
166167
void allocSecHdrTable();
@@ -193,23 +194,44 @@ class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase {
193194
public:
194195
SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS)
195196
: SampleProfileWriterExtBinaryBase(OS) {
196-
initSectionLayout();
197+
initSectionHdrLayout();
197198
}
198199

200+
virtual std::error_code writeSample(const FunctionSamples &S) override;
199201
virtual void setProfileSymbolList(ProfileSymbolList *PSL) override {
200202
ProfSymList = PSL;
201203
};
202204

203205
private:
204-
virtual void initSectionLayout() override {
205-
SectionLayout = {{SecProfSummary, 0, 0, 0},
206-
{SecNameTable, 0, 0, 0},
207-
{SecLBRProfile, 0, 0, 0},
208-
{SecProfileSymbolList, 0, 0, 0}};
206+
virtual void initSectionHdrLayout() override {
207+
// Note that SecFuncOffsetTable section is written after SecLBRProfile
208+
// in the profile, but is put before SecLBRProfile in SectionHdrLayout.
209+
//
210+
// This is because sample reader follows the order of SectionHdrLayout to
211+
// read each section, to read function profiles on demand sample reader
212+
// need to get the offset of each function profile first.
213+
//
214+
// SecFuncOffsetTable section is written after SecLBRProfile in the
215+
// profile because FuncOffsetTable needs to be populated while section
216+
// SecLBRProfile is written.
217+
SectionHdrLayout = {{SecProfSummary, 0, 0, 0},
218+
{SecNameTable, 0, 0, 0},
219+
{SecFuncOffsetTable, 0, 0, 0},
220+
{SecLBRProfile, 0, 0, 0},
221+
{SecProfileSymbolList, 0, 0, 0}};
209222
};
210223
virtual std::error_code
211224
writeSections(const StringMap<FunctionSamples> &ProfileMap) override;
212225
ProfileSymbolList *ProfSymList = nullptr;
226+
227+
// Save the start of SecLBRProfile so we can compute the offset to the
228+
// start of SecLBRProfile for each Function's Profile and will keep it
229+
// in FuncOffsetTable.
230+
uint64_t SecLBRProfileStart;
231+
// FuncOffsetTable maps function name to its profile offset in SecLBRProfile
232+
// section. It is used to load function profile on demand.
233+
MapVector<StringRef, uint64_t> FuncOffsetTable;
234+
std::error_code writeFuncOffsetTable();
213235
};
214236

215237
// CompactBinary is a compact format of binary profile which both reduces

llvm/lib/ProfileData/SampleProfReader.cpp

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,9 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
439439
return sampleprof_error::success;
440440
}
441441

442-
std::error_code SampleProfileReaderBinary::readFuncProfile() {
442+
std::error_code
443+
SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
444+
Data = Start;
443445
auto NumHeadSamples = readNumber<uint64_t>();
444446
if (std::error_code EC = NumHeadSamples.getError())
445447
return EC;
@@ -461,7 +463,7 @@ std::error_code SampleProfileReaderBinary::readFuncProfile() {
461463

462464
std::error_code SampleProfileReaderBinary::read() {
463465
while (!at_eof()) {
464-
if (std::error_code EC = readFuncProfile())
466+
if (std::error_code EC = readFuncProfile(Data))
465467
return EC;
466468
}
467469

@@ -483,13 +485,15 @@ SampleProfileReaderExtBinary::readOneSection(const uint8_t *Start,
483485
return EC;
484486
break;
485487
case SecLBRProfile:
486-
while (Data < Start + Size) {
487-
if (std::error_code EC = readFuncProfile())
488-
return EC;
489-
}
488+
if (std::error_code EC = readFuncProfiles())
489+
return EC;
490490
break;
491491
case SecProfileSymbolList:
492-
if (std::error_code EC = readProfileSymbolList(Size))
492+
if (std::error_code EC = readProfileSymbolList())
493+
return EC;
494+
break;
495+
case SecFuncOffsetTable:
496+
if (std::error_code EC = readFuncOffsetTable())
493497
return EC;
494498
break;
495499
default:
@@ -498,15 +502,65 @@ SampleProfileReaderExtBinary::readOneSection(const uint8_t *Start,
498502
return sampleprof_error::success;
499503
}
500504

501-
std::error_code
502-
SampleProfileReaderExtBinary::readProfileSymbolList(uint64_t Size) {
505+
void SampleProfileReaderExtBinary::collectFuncsFrom(const Module &M) {
506+
UseAllFuncs = false;
507+
FuncsToUse.clear();
508+
for (auto &F : M)
509+
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
510+
}
511+
512+
std::error_code SampleProfileReaderExtBinary::readFuncOffsetTable() {
513+
auto Size = readNumber<uint64_t>();
514+
if (std::error_code EC = Size.getError())
515+
return EC;
516+
517+
FuncOffsetTable.reserve(*Size);
518+
for (uint32_t I = 0; I < *Size; ++I) {
519+
auto FName(readStringFromTable());
520+
if (std::error_code EC = FName.getError())
521+
return EC;
522+
523+
auto Offset = readNumber<uint64_t>();
524+
if (std::error_code EC = Offset.getError())
525+
return EC;
526+
527+
FuncOffsetTable[*FName] = *Offset;
528+
}
529+
return sampleprof_error::success;
530+
}
531+
532+
std::error_code SampleProfileReaderExtBinary::readFuncProfiles() {
533+
const uint8_t *Start = Data;
534+
if (UseAllFuncs) {
535+
while (Data < End) {
536+
if (std::error_code EC = readFuncProfile(Data))
537+
return EC;
538+
}
539+
assert(Data == End && "More data is read than expected");
540+
return sampleprof_error::success;
541+
}
542+
543+
for (auto Name : FuncsToUse) {
544+
auto iter = FuncOffsetTable.find(Name);
545+
if (iter == FuncOffsetTable.end())
546+
continue;
547+
const uint8_t *FuncProfileAddr = Start + iter->second;
548+
assert(FuncProfileAddr < End && "out of LBRProfile section");
549+
if (std::error_code EC = readFuncProfile(FuncProfileAddr))
550+
return EC;
551+
}
552+
Data = End;
553+
return sampleprof_error::success;
554+
}
555+
556+
std::error_code SampleProfileReaderExtBinary::readProfileSymbolList() {
503557
if (!ProfSymList)
504558
ProfSymList = std::make_unique<ProfileSymbolList>();
505559

506-
if (std::error_code EC = ProfSymList->read(Data, Size))
560+
if (std::error_code EC = ProfSymList->read(Data, End - Data))
507561
return EC;
508562

509-
Data = Data + Size;
563+
Data = End;
510564
return sampleprof_error::success;
511565
}
512566

@@ -600,9 +654,9 @@ std::error_code SampleProfileReaderCompactBinary::read() {
600654

601655
for (auto Offset : OffsetsToUse) {
602656
const uint8_t *SavedData = Data;
603-
Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
604-
Offset;
605-
if (std::error_code EC = readFuncProfile())
657+
if (std::error_code EC = readFuncProfile(
658+
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
659+
Offset))
606660
return EC;
607661
Data = SavedData;
608662
}
@@ -719,8 +773,16 @@ uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) {
719773
}
720774

721775
uint64_t SampleProfileReaderExtBinaryBase::getFileSize() {
722-
auto &LastEntry = SecHdrTable.back();
723-
return LastEntry.Offset + LastEntry.Size;
776+
// Sections in SecHdrTable is not necessarily in the same order as
777+
// sections in the profile because section like FuncOffsetTable needs
778+
// to be written after section LBRProfile but needs to be read before
779+
// section LBRProfile, so we cannot simply use the last entry in
780+
// SecHdrTable to calculate the file size.
781+
uint64_t FileSize = 0;
782+
for (auto &Entry : SecHdrTable) {
783+
FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
784+
}
785+
return FileSize;
724786
}
725787

726788
bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) {
@@ -812,13 +874,11 @@ std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() {
812874
return sampleprof_error::success;
813875
}
814876

815-
void SampleProfileReaderCompactBinary::collectFuncsToUse(const Module &M) {
877+
void SampleProfileReaderCompactBinary::collectFuncsFrom(const Module &M) {
816878
UseAllFuncs = false;
817879
FuncsToUse.clear();
818-
for (auto &F : M) {
819-
StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
820-
FuncsToUse.insert(CanonName);
821-
}
880+
for (auto &F : M)
881+
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
822882
}
823883

824884
std::error_code SampleProfileReaderBinary::readSummaryEntry(

0 commit comments

Comments
 (0)