Skip to content

Commit 75e9d19

Browse files
authored
[llvm-profdata] Enabled functionality to write split-layout profile (#101795)
Using the flag `-split_layout` in llvm-profdata merge, the output profile can write profiles with and without inlined function into two different extbinary sections (and their FuncOffsetTable too). The section without inlined functions are marked with `SecFlagFlat` and is skipped by ThinLTO because it provides no useful info. The split layout feature was already implemented in SampleProfWriter but previously there is no way to use it from llvm-profdata.
1 parent a7ba73b commit 75e9d19

File tree

8 files changed

+100
-19
lines changed

8 files changed

+100
-19
lines changed

llvm/docs/CommandGuide/llvm-profdata.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ OPTIONS
162162
coverage for the optimized target. This option can only be used with
163163
sample-based profile in extbinary format.
164164

165+
.. option:: --split-layout=[true|false]
166+
167+
Split the profile data section to two with one containing sample profiles with
168+
inlined functions and the other not. This option can only be used with
169+
sample-based profile in extbinary format.
170+
165171
.. option:: --convert-sample-profile-layout=[nest|flat]
166172

167173
Convert the merged profile into a profile with a new layout. Supported

llvm/include/llvm/ProfileData/SampleProfReader.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,9 @@ class SampleProfileReader {
495495
/// are present.
496496
virtual void setProfileUseMD5() { ProfileIsMD5 = true; }
497497

498-
/// Don't read profile without context if the flag is set. This is only meaningful
499-
/// for ExtBinary format.
500-
virtual void setSkipFlatProf(bool Skip) {}
498+
/// Don't read profile without context if the flag is set.
499+
void setSkipFlatProf(bool Skip) { SkipFlatProf = Skip; }
500+
501501
/// Return whether any name in the profile contains ".__uniq." suffix.
502502
virtual bool hasUniqSuffix() { return false; }
503503

@@ -581,6 +581,10 @@ class SampleProfileReader {
581581
/// Whether the profile uses MD5 for Sample Contexts and function names. This
582582
/// can be one-way overriden by the user to force use MD5.
583583
bool ProfileIsMD5 = false;
584+
585+
/// If SkipFlatProf is true, skip functions marked with !Flat in text mode or
586+
/// sections with SecFlagFlat flag in ExtBinary mode.
587+
bool SkipFlatProf = false;
584588
};
585589

586590
class SampleProfileReaderText : public SampleProfileReader {
@@ -789,10 +793,6 @@ class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary {
789793
/// The set containing the functions to use when compiling a module.
790794
DenseSet<StringRef> FuncsToUse;
791795

792-
/// If SkipFlatProf is true, skip the sections with
793-
/// SecFlagFlat flag.
794-
bool SkipFlatProf = false;
795-
796796
public:
797797
SampleProfileReaderExtBinaryBase(std::unique_ptr<MemoryBuffer> B,
798798
LLVMContext &C, SampleProfileFormat Format)
@@ -815,8 +815,6 @@ class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary {
815815
return std::move(ProfSymList);
816816
};
817817

818-
void setSkipFlatProf(bool Skip) override { SkipFlatProf = Skip; }
819-
820818
private:
821819
/// Read the profiles on-demand for the given functions. This is used after
822820
/// stale call graph matching finds new functions whose profiles aren't loaded

llvm/include/llvm/ProfileData/SampleProfWriter.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ namespace sampleprof {
2828

2929
enum SectionLayout {
3030
DefaultLayout,
31-
// The layout splits profile with context information from profile without
32-
// context information. When Thinlto is enabled, ThinLTO postlink phase only
33-
// has to load profile with context information and can skip the other part.
31+
// The layout splits profile with inlined functions from profile without
32+
// inlined functions. When Thinlto is enabled, ThinLTO postlink phase only
33+
// has to load profile with inlined functions and can skip the other part.
3434
CtxSplitLayout,
3535
NumOfLayout,
3636
};
@@ -128,7 +128,7 @@ class SampleProfileWriter {
128128
virtual void setToCompressAllSections() {}
129129
virtual void setUseMD5() {}
130130
virtual void setPartialProfile() {}
131-
virtual void resetSecLayout(SectionLayout SL) {}
131+
virtual void setUseCtxSplitLayout() {}
132132

133133
protected:
134134
SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
@@ -176,12 +176,22 @@ class SampleProfileWriterText : public SampleProfileWriter {
176176
return sampleprof_error::success;
177177
}
178178

179+
void setUseCtxSplitLayout() override {
180+
MarkFlatProfiles = true;
181+
}
182+
179183
private:
180184
/// Indent level to use when writing.
181185
///
182186
/// This is used when printing inlined callees.
183187
unsigned Indent = 0;
184188

189+
/// If set, writes metadata "!Flat" to functions without inlined functions.
190+
/// This flag is for manual inspection only, it has no effect for the profile
191+
/// reader because a text sample profile is read sequentially and functions
192+
/// cannot be skipped.
193+
bool MarkFlatProfiles = false;
194+
185195
friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
186196
SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
187197
SampleProfileFormat Format);
@@ -242,11 +252,11 @@ const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
242252
// CtxSplitLayout
243253
SmallVector<SecHdrTableEntry, 8>({{SecProfSummary, 0, 0, 0, 0},
244254
{SecNameTable, 0, 0, 0, 0},
245-
// profile with context
255+
// profile with inlined functions
246256
// for next two sections
247257
{SecFuncOffsetTable, 0, 0, 0, 0},
248258
{SecLBRProfile, 0, 0, 0, 0},
249-
// profile without context
259+
// profile without inlined functions
250260
// for next two sections
251261
{SecFuncOffsetTable, 0, 0, 0, 0},
252262
{SecLBRProfile, 0, 0, 0, 0},
@@ -283,7 +293,11 @@ class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
283293
ProfSymList = PSL;
284294
};
285295

286-
void resetSecLayout(SectionLayout SL) override {
296+
void setUseCtxSplitLayout() override {
297+
resetSecLayout(SectionLayout::CtxSplitLayout);
298+
}
299+
300+
void resetSecLayout(SectionLayout SL) {
287301
verifySecLayout(SL);
288302
#ifndef NDEBUG
289303
// Make sure resetSecLayout is called before any flag setting.

llvm/lib/ProfileData/SampleProfReader.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,22 @@ static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth,
215215
uint64_t &NumSamples, uint32_t &LineOffset,
216216
uint32_t &Discriminator, StringRef &CalleeName,
217217
DenseMap<StringRef, uint64_t> &TargetCountMap,
218-
uint64_t &FunctionHash, uint32_t &Attributes) {
218+
uint64_t &FunctionHash, uint32_t &Attributes,
219+
bool &IsFlat) {
219220
for (Depth = 0; Input[Depth] == ' '; Depth++)
220221
;
221222
if (Depth == 0)
222223
return false;
223224

224225
if (Input[Depth] == '!') {
225226
LineTy = LineType::Metadata;
227+
// This metadata is only for manual inspection only. We already created a
228+
// FunctionSamples and put it in the profile map, so there is no point
229+
// to skip profiles even they have no use for ThinLTO.
230+
if (Input == StringRef(" !Flat")) {
231+
IsFlat = true;
232+
return true;
233+
}
226234
return parseMetadata(Input.substr(Depth), FunctionHash, Attributes);
227235
}
228236

@@ -325,6 +333,8 @@ std::error_code SampleProfileReaderText::readImpl() {
325333
// top-level or nested function profile.
326334
uint32_t DepthMetadata = 0;
327335

336+
std::vector<SampleContext *> FlatSamples;
337+
328338
ProfileIsFS = ProfileIsFSDisciminator;
329339
FunctionSamples::ProfileIsFS = ProfileIsFS;
330340
for (; !LineIt.is_at_eof(); ++LineIt) {
@@ -368,9 +378,10 @@ std::error_code SampleProfileReaderText::readImpl() {
368378
LineType LineTy;
369379
uint64_t FunctionHash = 0;
370380
uint32_t Attributes = 0;
381+
bool IsFlat = false;
371382
if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
372383
Discriminator, FName, TargetCountMap, FunctionHash,
373-
Attributes)) {
384+
Attributes, IsFlat)) {
374385
reportError(LineIt.line_number(),
375386
"Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
376387
*LineIt);
@@ -426,12 +437,26 @@ std::error_code SampleProfileReaderText::readImpl() {
426437
if (Attributes & (uint32_t)ContextShouldBeInlined)
427438
ProfileIsPreInlined = true;
428439
DepthMetadata = Depth;
440+
if (IsFlat) {
441+
if (Depth == 1)
442+
FlatSamples.push_back(&FProfile.getContext());
443+
else
444+
Ctx.diagnose(DiagnosticInfoSampleProfile(
445+
Buffer->getBufferIdentifier(), LineIt.line_number(),
446+
"!Flat may only be used at top level function.", DS_Warning));
447+
}
429448
break;
430449
}
431450
}
432451
}
433452
}
434453

454+
// Honor the option to skip flat functions. Since they are already added to
455+
// the profile map, remove them all here.
456+
if (SkipFlatProf)
457+
for (SampleContext *FlatSample : FlatSamples)
458+
Profiles.erase(*FlatSample);
459+
435460
assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
436461
"Cannot have both context-sensitive and regular profile");
437462
ProfileIsCS = (CSProfileCount > 0);
@@ -1026,7 +1051,7 @@ std::error_code SampleProfileReaderExtBinaryBase::readImpl() {
10261051
if (!Entry.Size)
10271052
continue;
10281053

1029-
// Skip sections without context when SkipFlatProf is true.
1054+
// Skip sections without inlined functions when SkipFlatProf is true.
10301055
if (SkipFlatProf && hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
10311056
continue;
10321057

llvm/lib/ProfileData/SampleProfWriter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,9 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
624624
LineCount++;
625625
}
626626

627+
if (Indent == 0 && MarkFlatProfiles && S.getCallsiteSamples().size() == 0)
628+
OS << " !Flat\n";
629+
627630
return sampleprof_error::success;
628631
}
629632

Binary file not shown.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
RUN: llvm-profdata merge --sample --extbinary --split-layout %p/Inputs/sample-profile.proftext -o %t-output
2+
RUN: diff %t-output %p/Inputs/split-layout.profdata
3+
4+
RUN: llvm-profdata merge --sample --text --split-layout %t-output | FileCheck %s
5+
CHECK: main:184019:0
6+
CHECK-NEXT: 4: 534
7+
CHECK-NEXT: 4.2: 534
8+
CHECK-NEXT: 5: 1075
9+
CHECK-NEXT: 5.1: 1075
10+
CHECK-NEXT: 6: 2080
11+
CHECK-NEXT: 7: 534
12+
CHECK-NEXT: 9: 2064 _Z3bari:1471 _Z3fooi:631
13+
CHECK-NEXT: 10: inline1:1000
14+
CHECK-NEXT: 1: 1000
15+
CHECK-NEXT: 10: inline2:2000
16+
CHECK-NEXT: 1: 2000
17+
CHECK-NEXT: _Z3bari:20301:1437
18+
CHECK-NEXT: 1: 1437
19+
CHECK-NEXT: !Flat
20+
CHECK-NEXT: _Z3fooi:7711:610
21+
CHECK-NEXT: 1: 610
22+
CHECK-NEXT: !Flat

llvm/tools/llvm-profdata/llvm-profdata.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ cl::opt<bool> GenPartialProfile(
207207
"gen-partial-profile", cl::init(false), cl::Hidden,
208208
cl::sub(MergeSubcommand),
209209
cl::desc("Generate a partial profile (only meaningful for -extbinary)"));
210+
cl::opt<bool> SplitLayout(
211+
"split-layout", cl::init(false), cl::Hidden,
212+
cl::sub(MergeSubcommand),
213+
cl::desc("Split the profile to two sections with one containing sample "
214+
"profiles with inlined functions and the other without (only "
215+
"meaningful for -extbinary)"));
210216
cl::opt<std::string> SupplInstrWithSample(
211217
"supplement-instr-with-sample", cl::init(""), cl::Hidden,
212218
cl::sub(MergeSubcommand),
@@ -1467,6 +1473,13 @@ static void handleExtBinaryWriter(sampleprof::SampleProfileWriter &Writer,
14671473
sampleprof::ProfileSymbolList &WriterList,
14681474
bool CompressAllSections, bool UseMD5,
14691475
bool GenPartialProfile) {
1476+
if (SplitLayout) {
1477+
if (OutputFormat == PF_Binary)
1478+
warn("-split-layout is ignored. Specify -extbinary to enable it");
1479+
else
1480+
Writer.setUseCtxSplitLayout();
1481+
}
1482+
14701483
populateProfileSymbolList(Buffer, WriterList);
14711484
if (WriterList.size() > 0 && OutputFormat != PF_Ext_Binary)
14721485
warn("Profile Symbol list is not empty but the output format is not "

0 commit comments

Comments
 (0)