Skip to content

Commit be90732

Browse files
committedAug 23, 2019
[SampleFDO] Add ExtBinary format to support extension of binary profile.
This is a patch split from https://reviews.llvm.org/D66374. It tries to add a new format of profile called ExtBinary. The format adds a section header table to the profile and organize the profile in sections, so the future extension like adding a new section or extending an existing section will be easier while keeping backward compatiblity feasible. Differential Revision: https://reviews.llvm.org/D66513 llvm-svn: 369798
1 parent b4051e5 commit be90732

File tree

10 files changed

+441
-66
lines changed

10 files changed

+441
-66
lines changed
 

Diff for: ‎llvm/include/llvm/ProfileData/SampleProf.h

+22
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ enum SampleProfileFormat {
8484
SPF_Text = 0x1,
8585
SPF_Compact_Binary = 0x2,
8686
SPF_GCC = 0x3,
87+
SPF_Ext_Binary = 0x4,
8788
SPF_Binary = 0xff
8889
};
8990

@@ -106,6 +107,27 @@ static inline StringRef getRepInFormat(StringRef Name,
106107

107108
static inline uint64_t SPVersion() { return 103; }
108109

110+
// Section Type used by SampleProfileExtBinaryBaseReader and
111+
// SampleProfileExtBinaryBaseWriter. Never change the existing
112+
// value of enum. Only append new ones.
113+
enum SecType {
114+
SecInValid = 0,
115+
SecProfSummary = 1,
116+
SecNameTable = 2,
117+
// marker for the first type of profile.
118+
SecFuncProfileFirst = 32,
119+
SecLBRProfile = SecFuncProfileFirst
120+
};
121+
122+
// Entry type of section header table used by SampleProfileExtBinaryBaseReader
123+
// and SampleProfileExtBinaryBaseWriter.
124+
struct SecHdrTableEntry {
125+
SecType Type;
126+
uint64_t Flag;
127+
uint64_t Offset;
128+
uint64_t Size;
129+
};
130+
109131
/// Represents the relative location of an instruction.
110132
///
111133
/// Instruction locations are specified by the line offset from the

Diff for: ‎llvm/include/llvm/ProfileData/SampleProfReader.h

+65-14
Original file line numberDiff line numberDiff line change
@@ -416,38 +416,89 @@ class SampleProfileReaderBinary : public SampleProfileReader {
416416
/// Read the contents of the given profile instance.
417417
std::error_code readProfile(FunctionSamples &FProfile);
418418

419+
/// Read the contents of Magic number and Version number.
420+
std::error_code readMagicIdent();
421+
422+
/// Read profile summary.
423+
std::error_code readSummary();
424+
425+
/// Read the whole name table.
426+
virtual std::error_code readNameTable();
427+
419428
/// Points to the current location in the buffer.
420429
const uint8_t *Data = nullptr;
421430

422431
/// Points to the end of the buffer.
423432
const uint8_t *End = nullptr;
424433

434+
/// Function name table.
435+
std::vector<StringRef> NameTable;
436+
437+
/// Read a string indirectly via the name table.
438+
virtual ErrorOr<StringRef> readStringFromTable();
439+
425440
private:
426441
std::error_code readSummaryEntry(std::vector<ProfileSummaryEntry> &Entries);
427442
virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
443+
};
428444

429-
/// Read profile summary.
430-
std::error_code readSummary();
445+
class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
446+
private:
447+
virtual std::error_code verifySPMagic(uint64_t Magic) override;
431448

432-
/// Read the whole name table.
433-
virtual std::error_code readNameTable() = 0;
449+
public:
450+
SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
451+
SampleProfileFormat Format = SPF_Binary)
452+
: SampleProfileReaderBinary(std::move(B), C, Format) {}
434453

435-
/// Read a string indirectly via the name table.
436-
virtual ErrorOr<StringRef> readStringFromTable() = 0;
454+
/// \brief Return true if \p Buffer is in the format supported by this class.
455+
static bool hasFormat(const MemoryBuffer &Buffer);
437456
};
438457

439-
class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
458+
/// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase defines
459+
/// the basic structure of the extensible binary format.
460+
/// The format is organized in sections except the magic and version number
461+
/// at the beginning. There is a section table before all the sections, and
462+
/// each entry in the table describes the entry type, start, size and
463+
/// attributes. The format in each section is defined by the section itself.
464+
///
465+
/// It is easy to add a new section while maintaining the backward
466+
/// compatibility of the profile. Nothing extra needs to be done. If we want
467+
/// to extend an existing section, like add cache misses information in
468+
/// addition to the sample count in the profile body, we can add a new section
469+
/// with the extension and retire the existing section, and we could choose
470+
/// to keep the parser of the old section if we want the reader to be able
471+
/// to read both new and old format profile.
472+
///
473+
/// SampleProfileReaderExtBinary/SampleProfileWriterExtBinary define the
474+
/// commonly used sections of a profile in extensible binary format. It is
475+
/// possible to define other types of profile inherited from
476+
/// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase.
477+
class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary {
478+
protected:
479+
std::vector<SecHdrTableEntry> SecHdrTable;
480+
std::error_code readSecHdrTableEntry();
481+
std::error_code readSecHdrTable();
482+
virtual std::error_code readHeader() override;
483+
virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
484+
485+
public:
486+
SampleProfileReaderExtBinaryBase(std::unique_ptr<MemoryBuffer> B,
487+
LLVMContext &C, SampleProfileFormat Format)
488+
: SampleProfileReaderBinary(std::move(B), C, Format) {}
489+
490+
/// Read sample profiles in extensible format from the associated file.
491+
std::error_code read() override;
492+
};
493+
494+
class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
440495
private:
441-
/// Function name table.
442-
std::vector<StringRef> NameTable;
443496
virtual std::error_code verifySPMagic(uint64_t Magic) override;
444-
virtual std::error_code readNameTable() override;
445-
/// Read a string indirectly via the name table.
446-
virtual ErrorOr<StringRef> readStringFromTable() override;
447497

448498
public:
449-
SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
450-
: SampleProfileReaderBinary(std::move(B), C, SPF_Binary) {}
499+
SampleProfileReaderExtBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
500+
SampleProfileFormat Format = SPF_Ext_Binary)
501+
: SampleProfileReaderExtBinaryBase(std::move(B), C, Format) {}
451502

452503
/// \brief Return true if \p Buffer is in the format supported by this class.
453504
static bool hasFormat(const MemoryBuffer &Buffer);

Diff for: ‎llvm/include/llvm/ProfileData/SampleProfWriter.h

+58-11
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class SampleProfileWriter {
3636
/// Write sample profiles in \p S.
3737
///
3838
/// \returns status code of the file update operation.
39-
virtual std::error_code write(const FunctionSamples &S) = 0;
39+
virtual std::error_code writeSample(const FunctionSamples &S) = 0;
4040

4141
/// Write all the sample profiles in the given map of samples.
4242
///
@@ -64,6 +64,10 @@ class SampleProfileWriter {
6464
virtual std::error_code
6565
writeHeader(const StringMap<FunctionSamples> &ProfileMap) = 0;
6666

67+
// Write function profiles to the profile file.
68+
virtual std::error_code
69+
writeFuncProfiles(const StringMap<FunctionSamples> &ProfileMap);
70+
6771
/// Output stream where to emit the profile to.
6872
std::unique_ptr<raw_ostream> OutputStream;
6973

@@ -72,12 +76,15 @@ class SampleProfileWriter {
7276

7377
/// Compute summary for this profile.
7478
void computeSummary(const StringMap<FunctionSamples> &ProfileMap);
79+
80+
/// Profile format.
81+
SampleProfileFormat Format;
7582
};
7683

7784
/// Sample-based profile writer (text format).
7885
class SampleProfileWriterText : public SampleProfileWriter {
7986
public:
80-
std::error_code write(const FunctionSamples &S) override;
87+
std::error_code writeSample(const FunctionSamples &S) override;
8188

8289
protected:
8390
SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
@@ -102,13 +109,14 @@ class SampleProfileWriterText : public SampleProfileWriter {
102109
/// Sample-based profile writer (binary format).
103110
class SampleProfileWriterBinary : public SampleProfileWriter {
104111
public:
105-
virtual std::error_code write(const FunctionSamples &S) override;
112+
virtual std::error_code writeSample(const FunctionSamples &S) override;
113+
114+
protected:
106115
SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
107116
: SampleProfileWriter(OS) {}
108117

109-
protected:
110-
virtual std::error_code writeNameTable() = 0;
111-
virtual std::error_code writeMagicIdent() = 0;
118+
virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
119+
virtual std::error_code writeNameTable();
112120
virtual std::error_code
113121
writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
114122
std::error_code writeSummary();
@@ -118,21 +126,61 @@ class SampleProfileWriterBinary : public SampleProfileWriter {
118126

119127
MapVector<StringRef, uint32_t> NameTable;
120128

121-
private:
122129
void addName(StringRef FName);
123130
void addNames(const FunctionSamples &S);
124131

132+
private:
125133
friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
126134
SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
127135
SampleProfileFormat Format);
128136
};
129137

130138
class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
131139
using SampleProfileWriterBinary::SampleProfileWriterBinary;
140+
};
141+
142+
class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
143+
using SampleProfileWriterBinary::SampleProfileWriterBinary;
144+
145+
public:
146+
virtual std::error_code
147+
write(const StringMap<FunctionSamples> &ProfileMap) override;
132148

133149
protected:
134-
virtual std::error_code writeNameTable() override;
135-
virtual std::error_code writeMagicIdent() override;
150+
uint64_t markSectionStart();
151+
uint64_t addNewSection(SecType Sec, uint64_t SectionStart);
152+
virtual void initSectionLayout() = 0;
153+
virtual std::error_code
154+
writeSections(const StringMap<FunctionSamples> &ProfileMap) = 0;
155+
156+
// Specifiy the section layout in the profile. Note that the order in
157+
// SecHdrTable (order to collect sections) may be different from the
158+
// order in SectionLayout (order to write out sections into profile).
159+
SmallVector<SecType, 8> SectionLayout;
160+
161+
private:
162+
void allocSecHdrTable();
163+
std::error_code writeSecHdrTable();
164+
virtual std::error_code
165+
writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
166+
167+
// The location where the output stream starts.
168+
uint64_t FileStart;
169+
// The location in the output stream where the SecHdrTable should be
170+
// written to.
171+
uint64_t SecHdrTableOffset;
172+
std::vector<SecHdrTableEntry> SecHdrTable;
173+
};
174+
175+
class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase {
176+
using SampleProfileWriterExtBinaryBase::SampleProfileWriterExtBinaryBase;
177+
178+
private:
179+
virtual void initSectionLayout() {
180+
SectionLayout = {SecProfSummary, SecNameTable, SecLBRProfile};
181+
};
182+
virtual std::error_code
183+
writeSections(const StringMap<FunctionSamples> &ProfileMap) override;
136184
};
137185

138186
// CompactBinary is a compact format of binary profile which both reduces
@@ -169,7 +217,7 @@ class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary {
169217
using SampleProfileWriterBinary::SampleProfileWriterBinary;
170218

171219
public:
172-
virtual std::error_code write(const FunctionSamples &S) override;
220+
virtual std::error_code writeSample(const FunctionSamples &S) override;
173221
virtual std::error_code
174222
write(const StringMap<FunctionSamples> &ProfileMap) override;
175223

@@ -181,7 +229,6 @@ class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary {
181229
/// towards profile start.
182230
uint64_t TableOffset;
183231
virtual std::error_code writeNameTable() override;
184-
virtual std::error_code writeMagicIdent() override;
185232
virtual std::error_code
186233
writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
187234
std::error_code writeFuncOffsetTable();

Diff for: ‎llvm/lib/ProfileData/SampleProfReader.cpp

+116-6
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ inline ErrorOr<uint32_t> SampleProfileReaderBinary::readStringIndex(T &Table) {
345345
return *Idx;
346346
}
347347

348-
ErrorOr<StringRef> SampleProfileReaderRawBinary::readStringFromTable() {
348+
ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
349349
auto Idx = readStringIndex(NameTable);
350350
if (std::error_code EC = Idx.getError())
351351
return EC;
@@ -467,6 +467,40 @@ std::error_code SampleProfileReaderBinary::read() {
467467
return sampleprof_error::success;
468468
}
469469

470+
std::error_code SampleProfileReaderExtBinaryBase::read() {
471+
const uint8_t *BufStart =
472+
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
473+
474+
for (auto &Entry : SecHdrTable) {
475+
// Skip empty section.
476+
if (!Entry.Size)
477+
continue;
478+
Data = BufStart + Entry.Offset;
479+
switch (Entry.Type) {
480+
case SecProfSummary:
481+
if (std::error_code EC = readSummary())
482+
return EC;
483+
break;
484+
case SecNameTable:
485+
if (std::error_code EC = readNameTable())
486+
return EC;
487+
break;
488+
case SecLBRProfile:
489+
while (Data < BufStart + Entry.Offset + Entry.Size) {
490+
if (std::error_code EC = readFuncProfile())
491+
return EC;
492+
}
493+
break;
494+
default:
495+
continue;
496+
}
497+
if (Data != BufStart + Entry.Offset + Entry.Size)
498+
return sampleprof_error::malformed;
499+
}
500+
501+
return sampleprof_error::success;
502+
}
503+
470504
std::error_code SampleProfileReaderCompactBinary::read() {
471505
std::vector<uint64_t> OffsetsToUse;
472506
if (UseAllFuncs) {
@@ -501,14 +535,20 @@ std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
501535
return sampleprof_error::bad_magic;
502536
}
503537

538+
std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
539+
if (Magic == SPMagic(SPF_Ext_Binary))
540+
return sampleprof_error::success;
541+
return sampleprof_error::bad_magic;
542+
}
543+
504544
std::error_code
505545
SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) {
506546
if (Magic == SPMagic(SPF_Compact_Binary))
507547
return sampleprof_error::success;
508548
return sampleprof_error::bad_magic;
509549
}
510550

511-
std::error_code SampleProfileReaderRawBinary::readNameTable() {
551+
std::error_code SampleProfileReaderBinary::readNameTable() {
512552
auto Size = readNumber<uint32_t>();
513553
if (std::error_code EC = Size.getError())
514554
return EC;
@@ -537,10 +577,60 @@ std::error_code SampleProfileReaderCompactBinary::readNameTable() {
537577
return sampleprof_error::success;
538578
}
539579

540-
std::error_code SampleProfileReaderBinary::readHeader() {
541-
Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
542-
End = Data + Buffer->getBufferSize();
580+
std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTableEntry() {
581+
SecHdrTableEntry Entry;
582+
auto Type = readUnencodedNumber<uint64_t>();
583+
if (std::error_code EC = Type.getError())
584+
return EC;
585+
Entry.Type = static_cast<SecType>(*Type);
586+
587+
auto Flag = readUnencodedNumber<uint64_t>();
588+
if (std::error_code EC = Flag.getError())
589+
return EC;
590+
Entry.Flag = *Flag;
591+
592+
auto Offset = readUnencodedNumber<uint64_t>();
593+
if (std::error_code EC = Offset.getError())
594+
return EC;
595+
Entry.Offset = *Offset;
596+
597+
auto Size = readUnencodedNumber<uint64_t>();
598+
if (std::error_code EC = Size.getError())
599+
return EC;
600+
Entry.Size = *Size;
601+
602+
SecHdrTable.push_back(std::move(Entry));
603+
return sampleprof_error::success;
604+
}
543605

606+
std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() {
607+
auto EntryNum = readUnencodedNumber<uint64_t>();
608+
if (std::error_code EC = EntryNum.getError())
609+
return EC;
610+
611+
for (uint32_t i = 0; i < (*EntryNum); i++)
612+
if (std::error_code EC = readSecHdrTableEntry())
613+
return EC;
614+
615+
return sampleprof_error::success;
616+
}
617+
618+
std::error_code SampleProfileReaderExtBinaryBase::readHeader() {
619+
const uint8_t *BufStart =
620+
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
621+
Data = BufStart;
622+
End = BufStart + Buffer->getBufferSize();
623+
624+
if (std::error_code EC = readMagicIdent())
625+
return EC;
626+
627+
if (std::error_code EC = readSecHdrTable())
628+
return EC;
629+
630+
return sampleprof_error::success;
631+
}
632+
633+
std::error_code SampleProfileReaderBinary::readMagicIdent() {
544634
// Read and check the magic identifier.
545635
auto Magic = readNumber<uint64_t>();
546636
if (std::error_code EC = Magic.getError())
@@ -555,6 +645,16 @@ std::error_code SampleProfileReaderBinary::readHeader() {
555645
else if (*Version != SPVersion())
556646
return sampleprof_error::unsupported_version;
557647

648+
return sampleprof_error::success;
649+
}
650+
651+
std::error_code SampleProfileReaderBinary::readHeader() {
652+
Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
653+
End = Data + Buffer->getBufferSize();
654+
655+
if (std::error_code EC = readMagicIdent())
656+
return EC;
657+
558658
if (std::error_code EC = readSummary())
559659
return EC;
560660

@@ -674,6 +774,13 @@ bool SampleProfileReaderRawBinary::hasFormat(const MemoryBuffer &Buffer) {
674774
return Magic == SPMagic();
675775
}
676776

777+
bool SampleProfileReaderExtBinary::hasFormat(const MemoryBuffer &Buffer) {
778+
const uint8_t *Data =
779+
reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
780+
uint64_t Magic = decodeULEB128(Data);
781+
return Magic == SPMagic(SPF_Ext_Binary);
782+
}
783+
677784
bool SampleProfileReaderCompactBinary::hasFormat(const MemoryBuffer &Buffer) {
678785
const uint8_t *Data =
679786
reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
@@ -1023,6 +1130,8 @@ SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C) {
10231130
std::unique_ptr<SampleProfileReader> Reader;
10241131
if (SampleProfileReaderRawBinary::hasFormat(*B))
10251132
Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
1133+
else if (SampleProfileReaderExtBinary::hasFormat(*B))
1134+
Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
10261135
else if (SampleProfileReaderCompactBinary::hasFormat(*B))
10271136
Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C));
10281137
else if (SampleProfileReaderGCC::hasFormat(*B))
@@ -1033,8 +1142,9 @@ SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C) {
10331142
return sampleprof_error::unrecognized_format;
10341143

10351144
FunctionSamples::Format = Reader->getFormat();
1036-
if (std::error_code EC = Reader->readHeader())
1145+
if (std::error_code EC = Reader->readHeader()) {
10371146
return EC;
1147+
}
10381148

10391149
return std::move(Reader);
10401150
}

Diff for: ‎llvm/lib/ProfileData/SampleProfWriter.cpp

+142-23
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,8 @@
3939
using namespace llvm;
4040
using namespace sampleprof;
4141

42-
std::error_code
43-
SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
44-
if (std::error_code EC = writeHeader(ProfileMap))
45-
return EC;
46-
42+
std::error_code SampleProfileWriter::writeFuncProfiles(
43+
const StringMap<FunctionSamples> &ProfileMap) {
4744
// Sort the ProfileMap by total samples.
4845
typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
4946
std::vector<NameFunctionSamples> V;
@@ -58,12 +55,77 @@ SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
5855
});
5956

6057
for (const auto &I : V) {
61-
if (std::error_code EC = write(*I.second))
58+
if (std::error_code EC = writeSample(*I.second))
6259
return EC;
6360
}
6461
return sampleprof_error::success;
6562
}
6663

64+
std::error_code
65+
SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
66+
if (std::error_code EC = writeHeader(ProfileMap))
67+
return EC;
68+
69+
if (std::error_code EC = writeFuncProfiles(ProfileMap))
70+
return EC;
71+
72+
return sampleprof_error::success;
73+
}
74+
75+
/// Return the current position and prepare to use it as the start
76+
/// position of a section.
77+
uint64_t SampleProfileWriterExtBinaryBase::markSectionStart() {
78+
return OutputStream->tell();
79+
}
80+
81+
/// Add a new section into section header table. Return the position
82+
/// of SectionEnd.
83+
uint64_t
84+
SampleProfileWriterExtBinaryBase::addNewSection(SecType Sec,
85+
uint64_t SectionStart) {
86+
uint64_t SectionEnd = OutputStream->tell();
87+
SecHdrTable.push_back(
88+
{Sec, 0, SectionStart - FileStart, SectionEnd - SectionStart});
89+
return SectionEnd;
90+
}
91+
92+
std::error_code SampleProfileWriterExtBinaryBase::write(
93+
const StringMap<FunctionSamples> &ProfileMap) {
94+
if (std::error_code EC = writeHeader(ProfileMap))
95+
return EC;
96+
97+
if (std::error_code EC = writeSections(ProfileMap))
98+
return EC;
99+
100+
if (std::error_code EC = writeSecHdrTable())
101+
return EC;
102+
103+
return sampleprof_error::success;
104+
}
105+
106+
std::error_code SampleProfileWriterExtBinary::writeSections(
107+
const StringMap<FunctionSamples> &ProfileMap) {
108+
uint64_t SectionStart = markSectionStart();
109+
computeSummary(ProfileMap);
110+
if (auto EC = writeSummary())
111+
return EC;
112+
SectionStart = addNewSection(SecProfSummary, SectionStart);
113+
114+
// Generate the name table for all the functions referenced in the profile.
115+
for (const auto &I : ProfileMap) {
116+
addName(I.first());
117+
addNames(I.second);
118+
}
119+
writeNameTable();
120+
SectionStart = addNewSection(SecNameTable, SectionStart);
121+
122+
if (std::error_code EC = writeFuncProfiles(ProfileMap))
123+
return EC;
124+
addNewSection(SecLBRProfile, SectionStart);
125+
126+
return sampleprof_error::success;
127+
}
128+
67129
std::error_code SampleProfileWriterCompactBinary::write(
68130
const StringMap<FunctionSamples> &ProfileMap) {
69131
if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
@@ -81,7 +143,7 @@ std::error_code SampleProfileWriterCompactBinary::write(
81143
///
82144
/// The format used here is more structured and deliberate because
83145
/// it needs to be parsed by the SampleProfileReaderText class.
84-
std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
146+
std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
85147
auto &OS = *OutputStream;
86148
OS << S.getName() << ":" << S.getTotalSamples();
87149
if (Indent == 0)
@@ -117,7 +179,7 @@ std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
117179
OS << Loc.LineOffset << ": ";
118180
else
119181
OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
120-
if (std::error_code EC = write(CalleeSamples))
182+
if (std::error_code EC = writeSample(CalleeSamples))
121183
return EC;
122184
}
123185
Indent -= 1;
@@ -163,7 +225,7 @@ void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
163225
NameTable[N] = i++;
164226
}
165227

166-
std::error_code SampleProfileWriterRawBinary::writeNameTable() {
228+
std::error_code SampleProfileWriterBinary::writeNameTable() {
167229
auto &OS = *OutputStream;
168230
std::set<StringRef> V;
169231
stablizeNameTable(V);
@@ -214,25 +276,18 @@ std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
214276
return sampleprof_error::success;
215277
}
216278

217-
std::error_code SampleProfileWriterRawBinary::writeMagicIdent() {
218-
auto &OS = *OutputStream;
219-
// Write file magic identifier.
220-
encodeULEB128(SPMagic(), OS);
221-
encodeULEB128(SPVersion(), OS);
222-
return sampleprof_error::success;
223-
}
224-
225-
std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() {
279+
std::error_code
280+
SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
226281
auto &OS = *OutputStream;
227282
// Write file magic identifier.
228-
encodeULEB128(SPMagic(SPF_Compact_Binary), OS);
283+
encodeULEB128(SPMagic(Format), OS);
229284
encodeULEB128(SPVersion(), OS);
230285
return sampleprof_error::success;
231286
}
232287

233288
std::error_code SampleProfileWriterBinary::writeHeader(
234289
const StringMap<FunctionSamples> &ProfileMap) {
235-
writeMagicIdent();
290+
writeMagicIdent(Format);
236291

237292
computeSummary(ProfileMap);
238293
if (auto EC = writeSummary())
@@ -248,6 +303,65 @@ std::error_code SampleProfileWriterBinary::writeHeader(
248303
return sampleprof_error::success;
249304
}
250305

306+
void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
307+
support::endian::Writer Writer(*OutputStream, support::little);
308+
309+
Writer.write(static_cast<uint64_t>(SectionLayout.size()));
310+
SecHdrTableOffset = OutputStream->tell();
311+
for (uint32_t i = 0; i < SectionLayout.size(); i++) {
312+
Writer.write(static_cast<uint64_t>(-1));
313+
Writer.write(static_cast<uint64_t>(-1));
314+
Writer.write(static_cast<uint64_t>(-1));
315+
Writer.write(static_cast<uint64_t>(-1));
316+
}
317+
}
318+
319+
std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
320+
auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
321+
uint64_t Saved = OutputStream->tell();
322+
323+
// Set OutputStream to the location saved in SecHdrTableOffset.
324+
if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
325+
return sampleprof_error::ostream_seek_unsupported;
326+
support::endian::Writer Writer(*OutputStream, support::little);
327+
328+
DenseMap<uint32_t, uint32_t> IndexMap;
329+
for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
330+
IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i});
331+
}
332+
333+
// Write the sections in the order specified in SectionLayout.
334+
// That is the sections order Reader will see. Note that the
335+
// sections order in which Reader expects to read may be different
336+
// from the order in which Writer is able to write, so we need
337+
// to adjust the order in SecHdrTable to be consistent with
338+
// SectionLayout when we write SecHdrTable to the memory.
339+
for (uint32_t i = 0; i < SectionLayout.size(); i++) {
340+
uint32_t idx = IndexMap[static_cast<uint32_t>(SectionLayout[i])];
341+
Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type));
342+
Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flag));
343+
Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset));
344+
Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size));
345+
}
346+
347+
// Reset OutputStream.
348+
if (OFS.seek(Saved) == (uint64_t)-1)
349+
return sampleprof_error::ostream_seek_unsupported;
350+
351+
return sampleprof_error::success;
352+
}
353+
354+
std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
355+
const StringMap<FunctionSamples> &ProfileMap) {
356+
auto &OS = *OutputStream;
357+
FileStart = OS.tell();
358+
writeMagicIdent(Format);
359+
360+
initSectionLayout();
361+
allocSecHdrTable();
362+
return sampleprof_error::success;
363+
}
364+
251365
std::error_code SampleProfileWriterCompactBinary::writeHeader(
252366
const StringMap<FunctionSamples> &ProfileMap) {
253367
support::endian::Writer Writer(*OutputStream, support::little);
@@ -324,13 +438,14 @@ std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
324438
/// Write samples of a top-level function to a binary file.
325439
///
326440
/// \returns true if the samples were written successfully, false otherwise.
327-
std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) {
441+
std::error_code
442+
SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
328443
encodeULEB128(S.getHeadSamples(), *OutputStream);
329444
return writeBody(S);
330445
}
331446

332447
std::error_code
333-
SampleProfileWriterCompactBinary::write(const FunctionSamples &S) {
448+
SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
334449
uint64_t Offset = OutputStream->tell();
335450
StringRef Name = S.getName();
336451
FuncOffsetTable[Name] = Offset;
@@ -349,7 +464,8 @@ ErrorOr<std::unique_ptr<SampleProfileWriter>>
349464
SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
350465
std::error_code EC;
351466
std::unique_ptr<raw_ostream> OS;
352-
if (Format == SPF_Binary || Format == SPF_Compact_Binary)
467+
if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
468+
Format == SPF_Compact_Binary)
353469
OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
354470
else
355471
OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
@@ -374,6 +490,8 @@ SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
374490

375491
if (Format == SPF_Binary)
376492
Writer.reset(new SampleProfileWriterRawBinary(OS));
493+
else if (Format == SPF_Ext_Binary)
494+
Writer.reset(new SampleProfileWriterExtBinary(OS));
377495
else if (Format == SPF_Compact_Binary)
378496
Writer.reset(new SampleProfileWriterCompactBinary(OS));
379497
else if (Format == SPF_Text)
@@ -386,6 +504,7 @@ SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
386504
if (EC)
387505
return EC;
388506

507+
Writer->Format = Format;
389508
return std::move(Writer);
390509
}
391510

272 Bytes
Binary file not shown.

Diff for: ‎llvm/test/Transforms/SampleProfile/compact-binary-profile.ll renamed to ‎llvm/test/Transforms/SampleProfile/profile-format.ll

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
33
; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
44
; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
5+
; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.extbinary.afdo -S | FileCheck %s
6+
; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.extbinary.afdo -S | FileCheck %s
57

68
; Original C++ test case
79
;
@@ -21,8 +23,8 @@
2123
;
2224
@.str = private unnamed_addr constant [11 x i8] c"sum is %d\0A\00", align 1
2325

24-
; Check sample-profile phase using compactbinary format profile will annotate
25-
; the IR with exactly the same result as using text format.
26+
; Check sample-profile phase using compactbinary or extbinary format profile
27+
; will annotate the IR with exactly the same result as using text format.
2628
; CHECK: br i1 %cmp, label %while.body, label %while.end{{.*}} !prof ![[IDX1:[0-9]*]]
2729
; CHECK: br i1 %cmp1, label %if.then, label %if.else{{.*}} !prof ![[IDX2:[0-9]*]]
2830
; CHECK: call i32 (i8*, ...) @printf{{.*}} !prof ![[IDX3:[0-9]*]]

Diff for: ‎llvm/test/tools/llvm-profdata/roundtrip.test

+10-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,13 @@ RUN: llvm-profdata show -o %t.1.proftext -all-functions -text %t.1.profdata
66
RUN: diff %t.1.proftext %S/Inputs/IR_profile.proftext
77
RUN: llvm-profdata merge --sample --binary -output=%t.2.profdata %S/Inputs/sample-profile.proftext
88
RUN: llvm-profdata merge --sample --text -output=%t.2.proftext %t.2.profdata
9-
RUN: diff %t.2.proftext %S/Inputs/sample-profile.proftext
9+
RUN: diff %t.2.proftext %S/Inputs/sample-profile.proftext
10+
# Round trip from text --> extbinary --> text
11+
RUN: llvm-profdata merge --sample --extbinary -output=%t.3.profdata %S/Inputs/sample-profile.proftext
12+
RUN: llvm-profdata merge --sample --text -output=%t.3.proftext %t.3.profdata
13+
RUN: diff %t.3.proftext %S/Inputs/sample-profile.proftext
14+
# Round trip from text --> binary --> extbinary --> text
15+
RUN: llvm-profdata merge --sample --binary -output=%t.4.profdata %S/Inputs/sample-profile.proftext
16+
RUN: llvm-profdata merge --sample --extbinary -output=%t.5.profdata %t.4.profdata
17+
RUN: llvm-profdata merge --sample --text -output=%t.4.proftext %t.5.profdata
18+
RUN: diff %t.4.proftext %S/Inputs/sample-profile.proftext

Diff for: ‎llvm/tools/llvm-profdata/llvm-profdata.cpp

+16-9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum ProfileFormat {
3737
PF_None = 0,
3838
PF_Text,
3939
PF_Compact_Binary,
40+
PF_Ext_Binary,
4041
PF_GCC,
4142
PF_Binary
4243
};
@@ -314,7 +315,7 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
314315
exitWithError("Cannot write indexed profdata format to stdout.");
315316

316317
if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary &&
317-
OutputFormat != PF_Text)
318+
OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)
318319
exitWithError("Unknown format is specified.");
319320

320321
std::mutex ErrorLock;
@@ -425,8 +426,12 @@ remapSamples(const sampleprof::FunctionSamples &Samples,
425426
}
426427

427428
static sampleprof::SampleProfileFormat FormatMap[] = {
428-
sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Compact_Binary,
429-
sampleprof::SPF_GCC, sampleprof::SPF_Binary};
429+
sampleprof::SPF_None,
430+
sampleprof::SPF_Text,
431+
sampleprof::SPF_Compact_Binary,
432+
sampleprof::SPF_Ext_Binary,
433+
sampleprof::SPF_GCC,
434+
sampleprof::SPF_Binary};
430435

431436
static void mergeSampleProfile(const WeightedFileVector &Inputs,
432437
SymbolRemapper *Remapper,
@@ -583,12 +588,14 @@ static int merge_main(int argc, const char *argv[]) {
583588
clEnumVal(sample, "Sample profile")));
584589
cl::opt<ProfileFormat> OutputFormat(
585590
cl::desc("Format of output profile"), cl::init(PF_Binary),
586-
cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
587-
clEnumValN(PF_Compact_Binary, "compbinary",
588-
"Compact binary encoding"),
589-
clEnumValN(PF_Text, "text", "Text encoding"),
590-
clEnumValN(PF_GCC, "gcc",
591-
"GCC encoding (only meaningful for -sample)")));
591+
cl::values(
592+
clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
593+
clEnumValN(PF_Compact_Binary, "compbinary",
594+
"Compact binary encoding"),
595+
clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding"),
596+
clEnumValN(PF_Text, "text", "Text encoding"),
597+
clEnumValN(PF_GCC, "gcc",
598+
"GCC encoding (only meaningful for -sample)")));
592599
cl::opt<bool> OutputSparse("sparse", cl::init(false),
593600
cl::desc("Generate a sparse profile (only meaningful for -instr)"));
594601
cl::opt<unsigned> NumThreads(

Diff for: ‎llvm/unittests/ProfileData/SampleProfTest.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ TEST_F(SampleProfTest, roundtrip_compact_binary_profile) {
285285
testRoundTrip(SampleProfileFormat::SPF_Compact_Binary, false);
286286
}
287287

288+
TEST_F(SampleProfTest, roundtrip_ext_binary_profile) {
289+
testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, false);
290+
}
291+
288292
TEST_F(SampleProfTest, remap_text_profile) {
289293
testRoundTrip(SampleProfileFormat::SPF_Text, true);
290294
}
@@ -293,6 +297,10 @@ TEST_F(SampleProfTest, remap_raw_binary_profile) {
293297
testRoundTrip(SampleProfileFormat::SPF_Binary, true);
294298
}
295299

300+
TEST_F(SampleProfTest, remap_ext_binary_profile) {
301+
testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, true);
302+
}
303+
296304
TEST_F(SampleProfTest, sample_overflow_saturation) {
297305
const uint64_t Max = std::numeric_limits<uint64_t>::max();
298306
sampleprof_error Result;

0 commit comments

Comments
 (0)
Please sign in to comment.