[llvm] [ProfileData] Support format version 104 for extensible binary sample profiles (PR #206297)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 27 18:29:54 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-pgo
Author: Kazu Hirata (kazutakahirata)
<details>
<summary>Changes</summary>
This patch adds initial support for format version 104 in extensible
binary sample profiles to support the upcoming on-disk hash table.
This patch sets up the versioning scheme in the reader and writer as a
preparation step without actually introducing the on-disk hash table.
The reader is updated to support format version 104. The writer can
now write format version 104 profiles when requested via
-sample-profile-format-version, but continues to default to version
103 as version 104 is a work in progress. We plan to promote the
default version to 104 once the on-disk hash table support is fully
integrated in a subsequent patch.
RFC: https://discourse.llvm.org/t/rfc-faster-sample-profile-loading/90957/4
Assisted-by: Antigravity
---
Full diff: https://github.com/llvm/llvm-project/pull/206297.diff
6 Files Affected:
- (modified) llvm/include/llvm/ProfileData/SampleProf.h (+17)
- (modified) llvm/include/llvm/ProfileData/SampleProfReader.h (+6)
- (modified) llvm/include/llvm/ProfileData/SampleProfWriter.h (+10)
- (modified) llvm/lib/ProfileData/SampleProfReader.cpp (+2-1)
- (modified) llvm/lib/ProfileData/SampleProfWriter.cpp (+11-1)
- (modified) llvm/unittests/ProfileData/SampleProfTest.cpp (+93)
``````````diff
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index cb0344e848c34..ba4ab289a1838 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -116,6 +116,23 @@ static inline uint64_t SPMagic(SampleProfileFormat Format = SPF_Binary) {
uint64_t('2') << (64 - 56) | uint64_t(Format);
}
+// The oldest version of the extensible binary format we support.
+static constexpr uint64_t MinSupportedVersion = 103;
+
+// The default version of the extensible binary profile format written by the
+// compiler. We default to v103 as v104 is work in progress.
+static constexpr uint64_t DefaultVersion = 103;
+
+// The latest supported version of the extensible binary profile format.
+static constexpr uint64_t LatestVersion = 104;
+
+// Query if a given format version is supported by this compiler.
+static inline bool formatVersionIsSupported(uint64_t Version) {
+ return Version >= MinSupportedVersion && Version <= LatestVersion;
+}
+
+// Unused. Retained for downstream uses only.
+LLVM_DEPRECATED("Use DefaultVersion or LatestVersion instead", "DefaultVersion")
static inline uint64_t SPVersion() { return 103; }
// Section Type used by SampleProfileExtBinaryBaseReader and
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 251e6a8f4843a..de85a5aeeaa6e 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -515,6 +515,9 @@ class SampleProfileReader {
/// Print all the profiles on stream \p OS in the JSON format.
LLVM_ABI void dumpJson(raw_ostream &OS = dbgs());
+ /// Return the format version of the profile. For tests only.
+ uint64_t getFormatVersion() const { return FormatVersion; }
+
/// Return the samples collected for function \p F.
FunctionSamples *getSamplesFor(const Function &F) {
// The function name may have been updated by adding suffix. Call
@@ -697,6 +700,9 @@ class SampleProfileReader {
/// Whether the function profiles use FS discriminators.
bool ProfileIsFS = false;
+ /// Format version of the profile.
+ uint64_t FormatVersion = 0;
+
/// If true, the profile has vtable profiles and reader should decode them
/// to parse profiles correctly.
bool ReadVTableProf = false;
diff --git a/llvm/include/llvm/ProfileData/SampleProfWriter.h b/llvm/include/llvm/ProfileData/SampleProfWriter.h
index 3b22f113615e1..df077305525c2 100644
--- a/llvm/include/llvm/ProfileData/SampleProfWriter.h
+++ b/llvm/include/llvm/ProfileData/SampleProfWriter.h
@@ -132,6 +132,13 @@ class LLVM_ABI SampleProfileWriter {
virtual void setPartialProfile() {}
virtual void setUseCtxSplitLayout() {}
+ void setFormatVersion(uint64_t V) {
+ assert(sampleprof::formatVersionIsSupported(V) &&
+ "Unsupported format version");
+ FormatVersion = V;
+ }
+ uint64_t getFormatVersion() const { return FormatVersion; }
+
protected:
SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
: OutputStream(std::move(OS)) {}
@@ -162,6 +169,9 @@ class LLVM_ABI SampleProfileWriter {
/// Profile format.
SampleProfileFormat Format = SPF_None;
+
+ /// Format version to write.
+ uint64_t FormatVersion = sampleprof::DefaultVersion;
};
/// Sample-based profile writer (text format).
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index 14fdaf6581efe..98d36bd3eff7a 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -1636,8 +1636,9 @@ std::error_code SampleProfileReaderBinary::readMagicIdent() {
auto Version = readNumber<uint64_t>();
if (std::error_code EC = Version.getError())
return EC;
- else if (*Version != SPVersion())
+ else if (!formatVersionIsSupported(*Version))
return sampleprof_error::unsupported_version;
+ FormatVersion = *Version;
return sampleprof_error::success;
}
diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp
index e5f31348578b8..eaeed95f6c585 100644
--- a/llvm/lib/ProfileData/SampleProfWriter.cpp
+++ b/llvm/lib/ProfileData/SampleProfWriter.cpp
@@ -46,6 +46,10 @@ static cl::opt<bool> ExtBinaryWriteVTableTypeProf(
"extbinary-write-vtable-type-prof", cl::init(false), cl::Hidden,
cl::desc("Write vtable type profile in ext-binary sample profile writer"));
+static cl::opt<uint64_t> RequestedVersion(
+ "sample-profile-format-version", cl::init(DefaultVersion), cl::Hidden,
+ cl::desc("Format version to write for extensible binary profiles"));
+
namespace llvm {
namespace support {
namespace endian {
@@ -757,7 +761,7 @@ SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
auto &OS = *OutputStream;
// Write file magic identifier.
encodeULEB128(SPMagic(Format), OS);
- encodeULEB128(SPVersion(), OS);
+ encodeULEB128(FormatVersion, OS);
return sampleprof_error::success;
}
@@ -982,6 +986,12 @@ SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
return EC;
Writer->Format = Format;
+ if (Format != SPF_Ext_Binary)
+ Writer->setFormatVersion(DefaultVersion);
+ else if (formatVersionIsSupported(RequestedVersion))
+ Writer->setFormatVersion(RequestedVersion);
+ else
+ return sampleprof_error::unsupported_version;
return std::move(Writer);
}
diff --git a/llvm/unittests/ProfileData/SampleProfTest.cpp b/llvm/unittests/ProfileData/SampleProfTest.cpp
index 0158b584f8504..584d7fbec1e38 100644
--- a/llvm/unittests/ProfileData/SampleProfTest.cpp
+++ b/llvm/unittests/ProfileData/SampleProfTest.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/VirtualFileSystem.h"
@@ -138,6 +139,60 @@ struct SampleProfTest : ::testing::Test {
delete PS;
}
+ // Write a minimal profile with a specific format version to an in-memory
+ // buffer.
+ ErrorOr<SmallVector<char, 128>> writeProfileToBuffer(uint64_t Version) {
+ SmallVector<char, 128> Buffer;
+ std::unique_ptr<raw_ostream> OS =
+ std::make_unique<raw_svector_ostream>(Buffer);
+ auto WriterOrErr =
+ SampleProfileWriter::create(OS, SampleProfileFormat::SPF_Ext_Binary);
+ if (std::error_code EC = WriterOrErr.getError())
+ return EC;
+ auto Writer = std::move(WriterOrErr.get());
+ Writer->setFormatVersion(Version);
+
+ StringRef FooName("_Z3fooi");
+ FunctionSamples FooSamples;
+ FooSamples.setFunction(FunctionId(FooName));
+ FooSamples.addTotalSamples(1);
+
+ SampleProfileMap Profiles;
+ Profiles[FooName] = std::move(FooSamples);
+
+ if (std::error_code EC = Writer->write(Profiles))
+ return EC;
+ Writer->getOutputStream().flush();
+ Writer.reset();
+ return Buffer;
+ }
+
+ // Write a raw profile header (Magic + Version) directly to a buffer.
+ // This bypasses the writer validation and is used to test reader error
+ // handling.
+ SmallVector<char, 128> writeRawHeaderToBuffer(uint64_t Version) {
+ SmallVector<char, 128> Buffer;
+ raw_svector_ostream OS(Buffer);
+ encodeULEB128(SPMagic(SPF_Ext_Binary), OS);
+ encodeULEB128(Version, OS);
+ return Buffer;
+ }
+
+ // Read the format version from a profile stored in an in-memory buffer.
+ ErrorOr<uint64_t> readVersionFromBuffer(ArrayRef<char> Buffer) {
+ std::unique_ptr<MemoryBuffer> MemBuffer = MemoryBuffer::getMemBuffer(
+ StringRef(Buffer.data(), Buffer.size()), "profile",
+ /*RequiresNullTerminator*/ false);
+ auto FS = vfs::getRealFileSystem();
+ auto ReaderOrErr = SampleProfileReader::create(MemBuffer, Context, *FS);
+ if (std::error_code EC = ReaderOrErr.getError())
+ return EC;
+ auto Reader = std::move(ReaderOrErr.get());
+ if (std::error_code EC = Reader->readHeader())
+ return EC;
+ return Reader->getFormatVersion();
+ }
+
void testRoundTrip(SampleProfileFormat Format, bool Remap, bool UseMD5) {
TempFile ProfileFile("profile", "", "", /*Unique*/ true);
createWriter(Format, ProfileFile.path());
@@ -596,4 +651,42 @@ TEST_F(SampleProfTest, SampleProfileFuncOffsetTableOnDisk) {
EXPECT_EQ(Table.lookup(0x1111111122222222ULL), std::nullopt);
}
+// Verify that requesting format version 103 results in a version 103 profile.
+TEST_F(SampleProfTest, SampleProfileFormatVersion103) {
+ auto BufferOrErr = writeProfileToBuffer(103);
+ ASSERT_TRUE(NoError(BufferOrErr.getError()));
+ auto Buffer = std::move(*BufferOrErr);
+
+ auto ReadVersionOrErr = readVersionFromBuffer(Buffer);
+ ASSERT_TRUE(NoError(ReadVersionOrErr.getError()));
+ EXPECT_EQ(*ReadVersionOrErr, 103u);
+}
+
+// Verify that requesting format version 104 results in a version 104 profile.
+TEST_F(SampleProfTest, SampleProfileFormatVersion104) {
+ auto BufferOrErr = writeProfileToBuffer(104);
+ ASSERT_TRUE(NoError(BufferOrErr.getError()));
+ auto Buffer = std::move(*BufferOrErr);
+
+ auto ReadVersionOrErr = readVersionFromBuffer(Buffer);
+ ASSERT_TRUE(NoError(ReadVersionOrErr.getError()));
+ EXPECT_EQ(*ReadVersionOrErr, 104u);
+}
+
+// Verify that requesting format version 102 (below minimum supported) is
+// rejected by the reader.
+TEST_F(SampleProfTest, SampleProfileFormatVersion102) {
+ auto Buffer = writeRawHeaderToBuffer(102);
+ auto ReadVersionOrErr = readVersionFromBuffer(Buffer);
+ EXPECT_EQ(ReadVersionOrErr.getError(), sampleprof_error::unsupported_version);
+}
+
+// Verify that requesting format version 105 (above latest supported) is
+// rejected by the reader.
+TEST_F(SampleProfTest, SampleProfileFormatVersion105) {
+ auto Buffer = writeRawHeaderToBuffer(105);
+ auto ReadVersionOrErr = readVersionFromBuffer(Buffer);
+ EXPECT_EQ(ReadVersionOrErr.getError(), sampleprof_error::unsupported_version);
+}
+
} // end anonymous namespace
``````````
</details>
https://github.com/llvm/llvm-project/pull/206297
More information about the llvm-commits
mailing list