Skip to content

Commit ff281f7

Browse files
authored
[PGO] Add option to always instrumenting loop entries (#116789)
This patch extends the PGO infrastructure with an option to prefer the instrumentation of loop entry blocks. This option is a generalization of 19fb5b4, and helps to cover cases where the loop exit is never executed. An example where this can occur are event handling loops. Note that change does NOT change the default behavior.
1 parent 92ed7e2 commit ff281f7

File tree

13 files changed

+305
-30
lines changed

13 files changed

+305
-30
lines changed

compiler-rt/include/profile/InstrProfData.inc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,10 +730,12 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
730730
#define INSTR_PROF_COVMAP_VERSION 6
731731

732732
/* Profile version is always of type uint64_t. Reserve the upper 32 bits in the
733-
* version for other variants of profile. We set the 8th most significant bit
733+
* version for other variants of profile. We set the 8th most significant bit
734734
* (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation
735735
* generated profile, and 0 if this is a Clang FE generated profile.
736736
* 1 in bit 57 indicates there are context-sensitive records in the profile.
737+
* The 54th bit indicates whether to always instrument loop entry blocks.
738+
* The 58th bit indicates whether to always instrument function entry blocks.
737739
* The 59th bit indicates whether to use debug info to correlate profiles.
738740
* The 60th bit indicates single byte coverage instrumentation.
739741
* The 61st bit indicates function entry instrumentation only.
@@ -742,6 +744,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
742744
*/
743745
#define VARIANT_MASKS_ALL 0xffffffff00000000ULL
744746
#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
747+
#define VARIANT_MASK_INSTR_LOOP_ENTRIES (0x1ULL << 55)
745748
#define VARIANT_MASK_IR_PROF (0x1ULL << 56)
746749
#define VARIANT_MASK_CSIR_PROF (0x1ULL << 57)
747750
#define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58)

llvm/include/llvm/ProfileData/InstrProf.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,9 @@ enum class InstrProfKind {
344344
MemProf = 0x40,
345345
// A temporal profile.
346346
TemporalProfile = 0x80,
347-
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/TemporalProfile)
347+
// A profile with loop entry basic blocks instrumentation.
348+
LoopEntriesInstrumentation = 0x100,
349+
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/LoopEntriesInstrumentation)
348350
};
349351

350352
const std::error_category &instrprof_category();

llvm/include/llvm/ProfileData/InstrProfData.inc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,10 +730,12 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
730730
#define INSTR_PROF_COVMAP_VERSION 6
731731

732732
/* Profile version is always of type uint64_t. Reserve the upper 32 bits in the
733-
* version for other variants of profile. We set the 8th most significant bit
733+
* version for other variants of profile. We set the 8th most significant bit
734734
* (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation
735735
* generated profile, and 0 if this is a Clang FE generated profile.
736736
* 1 in bit 57 indicates there are context-sensitive records in the profile.
737+
* The 54th bit indicates whether to always instrument loop entry blocks.
738+
* The 58th bit indicates whether to always instrument function entry blocks.
737739
* The 59th bit indicates whether to use debug info to correlate profiles.
738740
* The 60th bit indicates single byte coverage instrumentation.
739741
* The 61st bit indicates function entry instrumentation only.
@@ -742,6 +744,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
742744
*/
743745
#define VARIANT_MASKS_ALL 0xffffffff00000000ULL
744746
#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
747+
#define VARIANT_MASK_INSTR_LOOP_ENTRIES (0x1ULL << 55)
745748
#define VARIANT_MASK_IR_PROF (0x1ULL << 56)
746749
#define VARIANT_MASK_CSIR_PROF (0x1ULL << 57)
747750
#define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58)

llvm/include/llvm/ProfileData/InstrProfReader.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ class InstrProfReader {
123123

124124
virtual bool instrEntryBBEnabled() const = 0;
125125

126+
/// Return true if the profile instruments all loop entries.
127+
virtual bool instrLoopEntriesEnabled() const = 0;
128+
126129
/// Return true if the profile has single byte counters representing coverage.
127130
virtual bool hasSingleByteCoverage() const = 0;
128131

@@ -274,6 +277,11 @@ class TextInstrProfReader : public InstrProfReader {
274277
InstrProfKind::FunctionEntryInstrumentation);
275278
}
276279

280+
bool instrLoopEntriesEnabled() const override {
281+
return static_cast<bool>(ProfileKind &
282+
InstrProfKind::LoopEntriesInstrumentation);
283+
}
284+
277285
bool hasSingleByteCoverage() const override {
278286
return static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage);
279287
}
@@ -398,6 +406,10 @@ class RawInstrProfReader : public InstrProfReader {
398406
return (Version & VARIANT_MASK_INSTR_ENTRY) != 0;
399407
}
400408

409+
bool instrLoopEntriesEnabled() const override {
410+
return (Version & VARIANT_MASK_INSTR_LOOP_ENTRIES) != 0;
411+
}
412+
401413
bool hasSingleByteCoverage() const override {
402414
return (Version & VARIANT_MASK_BYTE_COVERAGE) != 0;
403415
}
@@ -564,6 +576,7 @@ struct InstrProfReaderIndexBase {
564576
virtual bool isIRLevelProfile() const = 0;
565577
virtual bool hasCSIRLevelProfile() const = 0;
566578
virtual bool instrEntryBBEnabled() const = 0;
579+
virtual bool instrLoopEntriesEnabled() const = 0;
567580
virtual bool hasSingleByteCoverage() const = 0;
568581
virtual bool functionEntryOnly() const = 0;
569582
virtual bool hasMemoryProfile() const = 0;
@@ -628,6 +641,10 @@ class InstrProfReaderIndex : public InstrProfReaderIndexBase {
628641
return (FormatVersion & VARIANT_MASK_INSTR_ENTRY) != 0;
629642
}
630643

644+
bool instrLoopEntriesEnabled() const override {
645+
return (FormatVersion & VARIANT_MASK_INSTR_LOOP_ENTRIES) != 0;
646+
}
647+
631648
bool hasSingleByteCoverage() const override {
632649
return (FormatVersion & VARIANT_MASK_BYTE_COVERAGE) != 0;
633650
}
@@ -753,6 +770,10 @@ class IndexedInstrProfReader : public InstrProfReader {
753770
return Index->instrEntryBBEnabled();
754771
}
755772

773+
bool instrLoopEntriesEnabled() const override {
774+
return Index->instrLoopEntriesEnabled();
775+
}
776+
756777
bool hasSingleByteCoverage() const override {
757778
return Index->hasSingleByteCoverage();
758779
}

llvm/include/llvm/ProfileData/InstrProfWriter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,9 @@ class InstrProfWriter {
190190
return make_error<InstrProfError>(instrprof_error::unsupported_version);
191191
}
192192
if (testIncompatible(InstrProfKind::FunctionEntryOnly,
193-
InstrProfKind::FunctionEntryInstrumentation)) {
193+
InstrProfKind::FunctionEntryInstrumentation) ||
194+
testIncompatible(InstrProfKind::FunctionEntryOnly,
195+
InstrProfKind::LoopEntriesInstrumentation)) {
194196
return make_error<InstrProfError>(
195197
instrprof_error::unsupported_version,
196198
"cannot merge FunctionEntryOnly profiles and BB profiles together");

llvm/include/llvm/Transforms/Instrumentation/CFGMST.h

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/Analysis/BlockFrequencyInfo.h"
2020
#include "llvm/Analysis/BranchProbabilityInfo.h"
2121
#include "llvm/Analysis/CFG.h"
22+
#include "llvm/Analysis/LoopInfo.h"
2223
#include "llvm/IR/Instructions.h"
2324
#include "llvm/IR/IntrinsicInst.h"
2425
#include "llvm/Support/BranchProbability.h"
@@ -52,10 +53,14 @@ template <class Edge, class BBInfo> class CFGMST {
5253

5354
BranchProbabilityInfo *const BPI;
5455
BlockFrequencyInfo *const BFI;
56+
LoopInfo *const LI;
5557

5658
// If function entry will be always instrumented.
5759
const bool InstrumentFuncEntry;
5860

61+
// If true loop entries will be always instrumented.
62+
const bool InstrumentLoopEntries;
63+
5964
// Find the root group of the G and compress the path from G to the root.
6065
BBInfo *findAndCompressGroup(BBInfo *G) {
6166
if (G->Group != G)
@@ -154,6 +159,16 @@ template <class Edge, class BBInfo> class CFGMST {
154159
}
155160
if (BPI != nullptr)
156161
Weight = BPI->getEdgeProbability(&BB, TargetBB).scale(scaleFactor);
162+
// If InstrumentLoopEntries is on and the current edge leads to a loop
163+
// (i.e., TargetBB is a loop head and BB is outside its loop), set
164+
// Weight to be minimal, so that the edge won't be chosen for the MST
165+
// and will be instrumented.
166+
if (InstrumentLoopEntries && LI->isLoopHeader(TargetBB)) {
167+
Loop *TargetLoop = LI->getLoopFor(TargetBB);
168+
assert(TargetLoop);
169+
if (!TargetLoop->contains(&BB))
170+
Weight = 0;
171+
}
157172
if (Weight == 0)
158173
Weight++;
159174
auto *E = &addEdge(&BB, TargetBB, Weight);
@@ -252,6 +267,19 @@ template <class Edge, class BBInfo> class CFGMST {
252267
}
253268
}
254269

270+
[[maybe_unused]] bool validateLoopEntryInstrumentation() {
271+
if (!InstrumentLoopEntries)
272+
return true;
273+
for (auto &Ei : AllEdges) {
274+
if (Ei->Removed)
275+
continue;
276+
if (Ei->DestBB && LI->isLoopHeader(Ei->DestBB) &&
277+
!LI->getLoopFor(Ei->DestBB)->contains(Ei->SrcBB) && Ei->InMST)
278+
return false;
279+
}
280+
return true;
281+
}
282+
255283
public:
256284
// Dump the Debug information about the instrumentation.
257285
void dumpEdges(raw_ostream &OS, const Twine &Message) const {
@@ -291,13 +319,20 @@ template <class Edge, class BBInfo> class CFGMST {
291319
return *AllEdges.back();
292320
}
293321

294-
CFGMST(Function &Func, bool InstrumentFuncEntry,
322+
CFGMST(Function &Func, bool InstrumentFuncEntry, bool InstrumentLoopEntries,
295323
BranchProbabilityInfo *BPI = nullptr,
296-
BlockFrequencyInfo *BFI = nullptr)
297-
: F(Func), BPI(BPI), BFI(BFI), InstrumentFuncEntry(InstrumentFuncEntry) {
324+
BlockFrequencyInfo *BFI = nullptr, LoopInfo *LI = nullptr)
325+
: F(Func), BPI(BPI), BFI(BFI), LI(LI),
326+
InstrumentFuncEntry(InstrumentFuncEntry),
327+
InstrumentLoopEntries(InstrumentLoopEntries) {
328+
assert(!(InstrumentLoopEntries && !LI) &&
329+
"expected a LoopInfo to instrumenting loop entries");
298330
buildEdges();
299331
sortEdgesByWeight();
300332
computeMinimumSpanningTree();
333+
assert(validateLoopEntryInstrumentation() &&
334+
"Loop entries should not be in MST when "
335+
"InstrumentLoopEntries is on");
301336
if (AllEdges.size() > 1 && InstrumentFuncEntry)
302337
std::iter_swap(std::move(AllEdges.begin()),
303338
std::move(AllEdges.begin() + AllEdges.size() - 1));

llvm/lib/ProfileData/InstrProfReader.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
5252
if (Version & VARIANT_MASK_INSTR_ENTRY) {
5353
ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
5454
}
55+
if (Version & VARIANT_MASK_INSTR_LOOP_ENTRIES) {
56+
ProfileKind |= InstrProfKind::LoopEntriesInstrumentation;
57+
}
5558
if (Version & VARIANT_MASK_BYTE_COVERAGE) {
5659
ProfileKind |= InstrProfKind::SingleByteCoverage;
5760
}
@@ -262,6 +265,8 @@ Error TextInstrProfReader::readHeader() {
262265
ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
263266
else if (Str.equals_insensitive("not_entry_first"))
264267
ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
268+
else if (Str.equals_insensitive("instrument_loop_entries"))
269+
ProfileKind |= InstrProfKind::LoopEntriesInstrumentation;
265270
else if (Str.equals_insensitive("single_byte_coverage"))
266271
ProfileKind |= InstrProfKind::SingleByteCoverage;
267272
else if (Str.equals_insensitive("temporal_prof_traces")) {

llvm/lib/ProfileData/InstrProfWriter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,9 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
877877
if (static_cast<bool>(ProfileKind &
878878
InstrProfKind::FunctionEntryInstrumentation))
879879
Header.Version |= VARIANT_MASK_INSTR_ENTRY;
880+
if (static_cast<bool>(ProfileKind &
881+
InstrProfKind::LoopEntriesInstrumentation))
882+
Header.Version |= VARIANT_MASK_INSTR_LOOP_ENTRIES;
880883
if (static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage))
881884
Header.Version |= VARIANT_MASK_BYTE_COVERAGE;
882885
if (static_cast<bool>(ProfileKind & InstrProfKind::FunctionEntryOnly))
@@ -1120,6 +1123,10 @@ Error InstrProfWriter::writeText(raw_fd_ostream &OS) {
11201123
if (static_cast<bool>(ProfileKind &
11211124
InstrProfKind::FunctionEntryInstrumentation))
11221125
OS << "# Always instrument the function entry block\n:entry_first\n";
1126+
if (static_cast<bool>(ProfileKind &
1127+
InstrProfKind::LoopEntriesInstrumentation))
1128+
OS << "# Always instrument the loop entry "
1129+
"blocks\n:instrument_loop_entries\n";
11231130
if (static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage))
11241131
OS << "# Instrument block coverage\n:single_byte_coverage\n";
11251132
InstrProfSymtab Symtab;

llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,8 @@ bool GCOVProfiler::emitProfileNotes(
820820
SplitIndirectBrCriticalEdges(F, /*IgnoreBlocksWithoutPHI=*/false, BPI,
821821
BFI);
822822

823-
CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI);
823+
CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry=*/false,
824+
/*InstrumentLoopEntries=*/false, BPI, BFI);
824825

825826
// getInstrBB can split basic blocks and push elements to AllEdges.
826827
for (size_t I : llvm::seq<size_t>(0, MST.numEdges())) {

0 commit comments

Comments
 (0)