aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ProfileData/SampleProfWriter.cpp
diff options
context:
space:
mode:
authorMingming Liu <mingmingl@google.com>2025-09-12 15:58:16 -0700
committerGitHub <noreply@github.com>2025-09-12 15:58:16 -0700
commit52c583b3f95a0e666ab837e39a5db900b66adf15 (patch)
tree1da839e57d9c62fa64056c366143fb4f095f7f59 /llvm/lib/ProfileData/SampleProfWriter.cpp
parent1131e44ed3f5fadb2d22ff155d4e47f69757d02f (diff)
downloadllvm-52c583b3f95a0e666ab837e39a5db900b66adf15.zip
llvm-52c583b3f95a0e666ab837e39a5db900b66adf15.tar.gz
llvm-52c583b3f95a0e666ab837e39a5db900b66adf15.tar.bz2
[SampleFDO][TypeProf]Support vtable type profiling for ext-binary and text format (#148002)
This change extends SampleFDO ext-binary and text format to record the vtable symbols and their counts for virtual calls inside a function. The vtable profiles will allow the compiler to annotate vtable types on IR instructions and perform vtable-based indirect call promotion. An RFC is in https://discourse.llvm.org/t/rfc-vtable-type-profiling-for-samplefdo/87283 Given a function below, the before vs after of a function's profile is illustrated in text format in the table: ``` __attribute__((noinline)) int loop_func(int i, int a, int b) { Base *ptr = createType(i); int sum = ptr->func(a, b); delete ptr; return sum; } ``` | before | after | | --- | --- | | Samples collected in the function's body { <br> 0: 636241 <br> 1: 681458, calls: _Z10createTypei:681458 <br> 3: 543499, calls: _ZN12_GLOBAL__N_18Derived24funcEii:410621 _ZN8Derived14funcEii:132878 <br> 5.1: 602201, calls: _ZN12_GLOBAL__N_18Derived2D0Ev:454635 _ZN8Derived1D0Ev:147566 <br> 7: 511057 <br> } | Samples collected in the function's body { <br> 0: 636241 <br> 1: 681458, calls: _Z10createTypei:681458 <br> 3: 543499, calls: _ZN12_GLOBAL__N_18Derived24funcEii:410621 _ZN8Derived14funcEii:132878 <br> 3: vtables: _ZTV8Derived1:1377 _ZTVN12_GLOBAL__N_18Derived2E:4250 <br> 5.1: 602201, calls: _ZN12_GLOBAL__N_18Derived2D0Ev:454635 _ZN8Derived1D0Ev:147566 <br> 5.1: vtables: _ZTV8Derived1:227 _ZTVN12_GLOBAL__N_18Derived2E:765 <br> 7: 511057 <br> } | Key points for this change: 1. In-memory representation of vtable profiles * A field of type `map<LineLocation, map<FunctionId, uint64_t>>` is introduced in a function's in-memory representation [FunctionSamples](https://github.com/llvm/llvm-project/blob/ccc416312ed72e92a885425d9cb9c01f9afa58eb/llvm/include/llvm/ProfileData/SampleProf.h#L749-L754). 2. The vtable counters for one LineLocation represents the relative frequency among vtables for this LineLocation. They are not required to be comparable across LineLocations. 3. For backward compatibility of ext-binary format, we take one bit from ProfSummaryFlag as illustrated in the enum class `SecProfSummaryFlags`. The ext-binary profile reader parses the integer type flag and reads this bit. If it's set, the profile reader will parse vtable profiles. 4. The vtable profiles are optional in ext-binary format, and not serialized out by default, we introduce an LLVM boolean option (named `-extbinary-write-vtable-type-prof`). The ext-binary profile writer reads the boolean option and decide whether to set the section flag bit and serialize the in-memory class members corresponding to vtables. 5. This change doesn't implement `llvm-profdata overlap --sample` for the vtable profiles. A subsequent change will do it to keep this one focused on the profile format change. We don't plan to add the vtable support to non-extensible format mainly because of the maintenance cost to keep backward compatibility for prior versions of profile data. * Currently, the [non-extensible binary format](https://github.com/llvm/llvm-project/blob/5c28af409978c19a35021855a29dcaa65e95da00/llvm/lib/ProfileData/SampleProfWriter.cpp#L899-L900) does not have feature parity with extensible binary format today, for instance, the former doesn't support [profile symbol list](https://github.com/llvm/llvm-project/blob/41e22aa31b1905aa3e9d83c0343a96ec0d5187ec/llvm/include/llvm/ProfileData/SampleProf.h#L1518-L1522) or context-sensitive PGO, both of which give measurable performance boost. Presumably the non-extensible format is not in wide use. --------- Co-authored-by: Paschalis Mpeis <paschalis.mpeis@arm.com>
Diffstat (limited to 'llvm/lib/ProfileData/SampleProfWriter.cpp')
-rw-r--r--llvm/lib/ProfileData/SampleProfWriter.cpp80
1 files changed, 75 insertions, 5 deletions
diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp
index 9173a0f..e5f3134 100644
--- a/llvm/lib/ProfileData/SampleProfWriter.cpp
+++ b/llvm/lib/ProfileData/SampleProfWriter.cpp
@@ -41,6 +41,11 @@
using namespace llvm;
using namespace sampleprof;
+// To begin with, make this option off by default.
+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"));
+
namespace llvm {
namespace support {
namespace endian {
@@ -435,6 +440,9 @@ std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagIsPreInlined);
if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
+ if (Type == SecProfSummary && ExtBinaryWriteVTableTypeProf)
+ addSectionFlag(SecProfSummary,
+ SecProfSummaryFlags::SecFlagHasVTableTypeProf);
uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
switch (Type) {
@@ -478,6 +486,12 @@ std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
return sampleprof_error::success;
}
+SampleProfileWriterExtBinary::SampleProfileWriterExtBinary(
+ std::unique_ptr<raw_ostream> &OS)
+ : SampleProfileWriterExtBinaryBase(OS) {
+ WriteVTableProf = ExtBinaryWriteVTableTypeProf;
+}
+
std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
const SampleProfileMap &ProfileMap) {
// The const indices passed to writeOneSection below are specifying the
@@ -587,6 +601,19 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
OS << " " << J.first << ":" << J.second;
OS << "\n";
LineCount++;
+
+ if (const TypeCountMap *Map = S.findCallsiteTypeSamplesAt(Loc);
+ Map && !Map->empty()) {
+ OS.indent(Indent + 1);
+ Loc.print(OS);
+ OS << ": ";
+ OS << kVTableProfPrefix;
+ for (const auto [TypeName, Count] : *Map) {
+ OS << TypeName << ":" << Count << " ";
+ }
+ OS << "\n";
+ LineCount++;
+ }
}
SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
@@ -603,7 +630,21 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
if (std::error_code EC = writeSample(CalleeSamples))
return EC;
}
+
+ if (const TypeCountMap *Map = S.findCallsiteTypeSamplesAt(Loc);
+ Map && !Map->empty()) {
+ OS.indent(Indent);
+ Loc.print(OS);
+ OS << ": ";
+ OS << kVTableProfPrefix;
+ for (const auto [TypeId, Count] : *Map) {
+ OS << TypeId << ":" << Count << " ";
+ }
+ OS << "\n";
+ LineCount++;
+ }
}
+
Indent -= 1;
if (FunctionSamples::ProfileIsProbeBased) {
@@ -663,6 +704,17 @@ void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
addName(CalleeSamples.getFunction());
addNames(CalleeSamples);
}
+
+ if (!WriteVTableProf)
+ return;
+ // Add all the vtable names to NameTable.
+ for (const auto &VTableAccessCountMap :
+ llvm::make_second_range(S.getCallsiteTypeCounts())) {
+ // Add type name to NameTable.
+ for (const auto Type : llvm::make_first_range(VTableAccessCountMap)) {
+ addName(Type);
+ }
+ }
}
void SampleProfileWriterExtBinaryBase::addContext(
@@ -801,6 +853,22 @@ std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
return sampleprof_error::success;
}
+std::error_code SampleProfileWriterBinary::writeCallsiteVTableProf(
+ const CallsiteTypeMap &CallsiteTypeMap, raw_ostream &OS) {
+ assert(WriteVTableProf &&
+ "writeCallsiteVTableProf should not be called if WriteVTableProf is "
+ "false");
+
+ encodeULEB128(CallsiteTypeMap.size(), OS);
+ for (const auto &[Loc, TypeMap] : CallsiteTypeMap) {
+ Loc.serialize(OS);
+ if (std::error_code EC = serializeTypeMap(TypeMap, getNameTable(), OS))
+ return EC;
+ }
+
+ return sampleprof_error::success;
+}
+
std::error_code SampleProfileWriterBinary::writeSummary() {
auto &OS = *OutputStream;
encodeULEB128(Summary->getTotalCount(), OS);
@@ -838,14 +906,16 @@ std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
for (const auto &J : S.getCallsiteSamples())
NumCallsites += J.second.size();
encodeULEB128(NumCallsites, OS);
- for (const auto &[Loc, CalleeFunctionSampleMap] : S.getCallsiteSamples())
- for (const auto &FunctionSample :
- llvm::make_second_range(CalleeFunctionSampleMap)) {
- Loc.serialize(OS);
- if (std::error_code EC = writeBody(FunctionSample))
+ for (const auto &J : S.getCallsiteSamples())
+ for (const auto &FS : J.second) {
+ J.first.serialize(OS);
+ if (std::error_code EC = writeBody(FS.second))
return EC;
}
+ if (WriteVTableProf)
+ return writeCallsiteVTableProf(S.getCallsiteTypeCounts(), OS);
+
return sampleprof_error::success;
}