Skip to content

[PGO] Add support for writing previous indexed format #84505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion llvm/include/llvm/ProfileData/InstrProfWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,18 @@ class InstrProfWriter {
// Use raw pointer here for the incomplete type object.
InstrProfRecordWriterTrait *InfoObj;

// Temporary support for writing the previous version of the format, to enable
// some forward compatibility. Currently this suppresses the writing of the
// new vtable names section and header fields.
// TODO: Consider enabling this with future version changes as well, to ease
// deployment of newer versions of llvm-profdata.
bool WritePrevVersion = false;

public:
InstrProfWriter(bool Sparse = false,
uint64_t TemporalProfTraceReservoirSize = 0,
uint64_t MaxTemporalProfTraceLength = 0);
uint64_t MaxTemporalProfTraceLength = 0,
bool WritePrevVersion = false);
~InstrProfWriter();

StringMap<ProfilingData> &getProfileData() { return FunctionData; }
Expand Down
113 changes: 73 additions & 40 deletions llvm/lib/ProfileData/InstrProfWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,12 @@ class InstrProfRecordWriterTrait {

InstrProfWriter::InstrProfWriter(bool Sparse,
uint64_t TemporalProfTraceReservoirSize,
uint64_t MaxTemporalProfTraceLength)
uint64_t MaxTemporalProfTraceLength,
bool WritePrevVersion)
: Sparse(Sparse), MaxTemporalProfTraceLength(MaxTemporalProfTraceLength),
TemporalProfTraceReservoirSize(TemporalProfTraceReservoirSize),
InfoObj(new InstrProfRecordWriterTrait()) {}
InfoObj(new InstrProfRecordWriterTrait()),
WritePrevVersion(WritePrevVersion) {}

InstrProfWriter::~InstrProfWriter() { delete InfoObj; }

Expand Down Expand Up @@ -432,7 +434,13 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
// Write the header.
IndexedInstrProf::Header Header;
Header.Magic = IndexedInstrProf::Magic;
Header.Version = IndexedInstrProf::ProfVersion::CurrentVersion;
Header.Version = WritePrevVersion
? IndexedInstrProf::ProfVersion::Version11
: IndexedInstrProf::ProfVersion::CurrentVersion;
// The WritePrevVersion handling will either need to be removed or updated
// if the version is advanced beyond 12.
assert(IndexedInstrProf::ProfVersion::CurrentVersion ==
IndexedInstrProf::ProfVersion::Version12);
if (static_cast<bool>(ProfileKind & InstrProfKind::IRInstrumentation))
Header.Version |= VARIANT_MASK_IR_PROF;
if (static_cast<bool>(ProfileKind & InstrProfKind::ContextSensitive))
Expand Down Expand Up @@ -484,7 +492,8 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
OS.write(0);

uint64_t VTableNamesOffset = OS.tell();
OS.write(0);
if (!WritePrevVersion)
OS.write(0);

// Reserve space to write profile summary data.
uint32_t NumEntries = ProfileSummaryBuilder::DefaultCutoffs.size();
Expand Down Expand Up @@ -608,27 +617,29 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {

uint64_t VTableNamesSectionStart = OS.tell();

// Use a dummy (and uncompressed) string as compressed vtable names and get
// the necessary profile format change in place for version 12.
// TODO: Store the list of vtable names in InstrProfWriter and use the
// real compressed name.
std::string CompressedVTableNames = "VTableNames";
if (!WritePrevVersion) {
// Use a dummy (and uncompressed) string as compressed vtable names and get
// the necessary profile format change in place for version 12.
// TODO: Store the list of vtable names in InstrProfWriter and use the
// real compressed name.
std::string CompressedVTableNames = "VTableNames";

uint64_t CompressedStringLen = CompressedVTableNames.length();
uint64_t CompressedStringLen = CompressedVTableNames.length();

// Record the length of compressed string.
OS.write(CompressedStringLen);
// Record the length of compressed string.
OS.write(CompressedStringLen);

// Write the chars in compressed strings.
for (auto &c : CompressedVTableNames)
OS.writeByte(static_cast<uint8_t>(c));
// Write the chars in compressed strings.
for (auto &c : CompressedVTableNames)
OS.writeByte(static_cast<uint8_t>(c));

// Pad up to a multiple of 8.
// InstrProfReader would read bytes according to 'CompressedStringLen'.
uint64_t PaddedLength = alignTo(CompressedStringLen, 8);
// Pad up to a multiple of 8.
// InstrProfReader would read bytes according to 'CompressedStringLen'.
uint64_t PaddedLength = alignTo(CompressedStringLen, 8);

for (uint64_t K = CompressedStringLen; K < PaddedLength; K++) {
OS.writeByte(0);
for (uint64_t K = CompressedStringLen; K < PaddedLength; K++) {
OS.writeByte(0);
}
}

uint64_t TemporalProfTracesSectionStart = 0;
Expand Down Expand Up @@ -662,26 +673,48 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
}
InfoObj->CSSummaryBuilder = nullptr;

// Now do the final patch:
PatchItem PatchItems[] = {
// Patch the Header.HashOffset field.
{HashTableStartFieldOffset, &HashTableStart, 1},
// Patch the Header.MemProfOffset (=0 for profiles without MemProf
// data).
{MemProfSectionOffset, &MemProfSectionStart, 1},
// Patch the Header.BinaryIdSectionOffset.
{BinaryIdSectionOffset, &BinaryIdSectionStart, 1},
// Patch the Header.TemporalProfTracesOffset (=0 for profiles without
// traces).
{TemporalProfTracesOffset, &TemporalProfTracesSectionStart, 1},
{VTableNamesOffset, &VTableNamesSectionStart, 1},
// Patch the summary data.
{SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()),
(int)(SummarySize / sizeof(uint64_t))},
{CSSummaryOffset, reinterpret_cast<uint64_t *>(TheCSSummary.get()),
(int)CSSummarySize}};

OS.patch(PatchItems, std::size(PatchItems));
if (!WritePrevVersion) {
// Now do the final patch:
PatchItem PatchItems[] = {
// Patch the Header.HashOffset field.
{HashTableStartFieldOffset, &HashTableStart, 1},
// Patch the Header.MemProfOffset (=0 for profiles without MemProf
// data).
{MemProfSectionOffset, &MemProfSectionStart, 1},
// Patch the Header.BinaryIdSectionOffset.
{BinaryIdSectionOffset, &BinaryIdSectionStart, 1},
// Patch the Header.TemporalProfTracesOffset (=0 for profiles without
// traces).
{TemporalProfTracesOffset, &TemporalProfTracesSectionStart, 1},
{VTableNamesOffset, &VTableNamesSectionStart, 1},
// Patch the summary data.
{SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()),
(int)(SummarySize / sizeof(uint64_t))},
{CSSummaryOffset, reinterpret_cast<uint64_t *>(TheCSSummary.get()),
(int)CSSummarySize}};

OS.patch(PatchItems, std::size(PatchItems));
} else {
// Now do the final patch:
PatchItem PatchItems[] = {
// Patch the Header.HashOffset field.
{HashTableStartFieldOffset, &HashTableStart, 1},
// Patch the Header.MemProfOffset (=0 for profiles without MemProf
// data).
{MemProfSectionOffset, &MemProfSectionStart, 1},
// Patch the Header.BinaryIdSectionOffset.
{BinaryIdSectionOffset, &BinaryIdSectionStart, 1},
// Patch the Header.TemporalProfTracesOffset (=0 for profiles without
// traces).
{TemporalProfTracesOffset, &TemporalProfTracesSectionStart, 1},
// Patch the summary data.
{SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()),
(int)(SummarySize / sizeof(uint64_t))},
{CSSummaryOffset, reinterpret_cast<uint64_t *>(TheCSSummary.get()),
(int)CSSummarySize}};

OS.patch(PatchItems, std::size(PatchItems));
}

for (const auto &I : FunctionData)
for (const auto &F : I.getValue())
Expand Down
9 changes: 9 additions & 0 deletions llvm/test/tools/llvm-profdata/profile-version.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Test the profile version.

RUN: llvm-profdata merge -o %t.profdata %p/Inputs/basic.proftext
RUN: llvm-profdata show --profile-version %t.profdata | FileCheck %s
CHECK: Profile version: 12

RUN: llvm-profdata merge -o %t.prev.profdata %p/Inputs/basic.proftext --write-prev-version
RUN: llvm-profdata show --profile-version %t.prev.profdata | FileCheck %s --check-prefix=PREV
PREV: Profile version: 11
13 changes: 11 additions & 2 deletions llvm/tools/llvm-profdata/llvm-profdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,15 @@ cl::opt<bool> DropProfileSymbolList(
cl::desc("Drop the profile symbol list when merging AutoFDO profiles "
"(only meaningful for -sample)"));

// Temporary support for writing the previous version of the format, to enable
// some forward compatibility.
// TODO: Consider enabling this with future version changes as well, to ease
// deployment of newer versions of llvm-profdata.
cl::opt<bool> DoWritePrevVersion(
"write-prev-version", cl::init(false), cl::Hidden,
cl::desc("Write the previous version of indexed format, to enable "
"some forward compatibility."));

// Options specific to overlap subcommand.
cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
cl::desc("<base profile file>"),
Expand Down Expand Up @@ -579,8 +588,8 @@ struct WriterContext {
WriterContext(bool IsSparse, std::mutex &ErrLock,
SmallSet<instrprof_error, 4> &WriterErrorCodes,
uint64_t ReservoirSize = 0, uint64_t MaxTraceLength = 0)
: Writer(IsSparse, ReservoirSize, MaxTraceLength), ErrLock(ErrLock),
WriterErrorCodes(WriterErrorCodes) {}
: Writer(IsSparse, ReservoirSize, MaxTraceLength, DoWritePrevVersion),
ErrLock(ErrLock), WriterErrorCodes(WriterErrorCodes) {}
};

/// Computer the overlap b/w profile BaseFilename and TestFileName,
Expand Down