diff options
author | Mingming Liu <mingmingl@google.com> | 2025-09-12 15:58:16 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-09-12 15:58:16 -0700 |
commit | 52c583b3f95a0e666ab837e39a5db900b66adf15 (patch) | |
tree | 1da839e57d9c62fa64056c366143fb4f095f7f59 /llvm/lib/ProfileData/SampleProfWriter.cpp | |
parent | 1131e44ed3f5fadb2d22ff155d4e47f69757d02f (diff) | |
download | llvm-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.cpp | 80 |
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; } |