Skip to content

Commit c9ee6ce

Browse files
committed
[PGO] Supporting code for always instrumenting loop entries
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 abac5be commit c9ee6ce

22 files changed

+253
-46
lines changed

compiler-rt/include/profile/InstrProfData.inc

Lines changed: 9 additions & 6 deletions
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
734-
* (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation
733+
* version for other variants of profile. We set the 9th most significant bit
734+
* (i.e. bit 55) to 1 to indicate if this is an IR-level instrumentation
735735
* generated profile, and 0 if this is a Clang FE generated profile.
736-
* 1 in bit 57 indicates there are context-sensitive records in the profile.
736+
* 1 in bit 56 indicates there are context-sensitive records in the profile.
737+
* The 57th bit indicates whether to always instrument function entry blocks.
738+
* The 58th bit indicates whether to always instrument loop 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,9 +744,10 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
742744
*/
743745
#define VARIANT_MASKS_ALL 0xffffffff00000000ULL
744746
#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
745-
#define VARIANT_MASK_IR_PROF (0x1ULL << 56)
746-
#define VARIANT_MASK_CSIR_PROF (0x1ULL << 57)
747-
#define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58)
747+
#define VARIANT_MASK_IR_PROF (0x1ULL << 55)
748+
#define VARIANT_MASK_CSIR_PROF (0x1ULL << 56)
749+
#define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 57)
750+
#define VARIANT_MASK_INSTR_LOOP_ENTRIES (0x1ULL << 58)
748751
#define VARIANT_MASK_DBG_CORRELATE (0x1ULL << 59)
749752
#define VARIANT_MASK_BYTE_COVERAGE (0x1ULL << 60)
750753
#define VARIANT_MASK_FUNCTION_ENTRY_ONLY (0x1ULL << 61)

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: 9 additions & 6 deletions
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
734-
* (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation
733+
* version for other variants of profile. We set the 9th most significant bit
734+
* (i.e. bit 55) to 1 to indicate if this is an IR-level instrumentation
735735
* generated profile, and 0 if this is a Clang FE generated profile.
736-
* 1 in bit 57 indicates there are context-sensitive records in the profile.
736+
* 1 in bit 56 indicates there are context-sensitive records in the profile.
737+
* The 57th bit indicates whether to always instrument function entry blocks.
738+
* The 58th bit indicates whether to always instrument loop 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,9 +744,10 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
742744
*/
743745
#define VARIANT_MASKS_ALL 0xffffffff00000000ULL
744746
#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
745-
#define VARIANT_MASK_IR_PROF (0x1ULL << 56)
746-
#define VARIANT_MASK_CSIR_PROF (0x1ULL << 57)
747-
#define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58)
747+
#define VARIANT_MASK_IR_PROF (0x1ULL << 55)
748+
#define VARIANT_MASK_CSIR_PROF (0x1ULL << 56)
749+
#define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 57)
750+
#define VARIANT_MASK_INSTR_LOOP_ENTRIES (0x1ULL << 58)
748751
#define VARIANT_MASK_DBG_CORRELATE (0x1ULL << 59)
749752
#define VARIANT_MASK_BYTE_COVERAGE (0x1ULL << 60)
750753
#define VARIANT_MASK_FUNCTION_ENTRY_ONLY (0x1ULL << 61)

llvm/include/llvm/ProfileData/InstrProfReader.h

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

124124
virtual bool instrEntryBBEnabled() const = 0;
125125

126+
virtual bool instrLoopEntriesEnabled() const = 0;
127+
126128
/// Return true if the profile has single byte counters representing coverage.
127129
virtual bool hasSingleByteCoverage() const = 0;
128130

@@ -274,6 +276,11 @@ class TextInstrProfReader : public InstrProfReader {
274276
InstrProfKind::FunctionEntryInstrumentation);
275277
}
276278

279+
bool instrLoopEntriesEnabled() const override {
280+
return static_cast<bool>(ProfileKind &
281+
InstrProfKind::LoopEntriesInstrumentation);
282+
}
283+
277284
bool hasSingleByteCoverage() const override {
278285
return static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage);
279286
}
@@ -398,6 +405,10 @@ class RawInstrProfReader : public InstrProfReader {
398405
return (Version & VARIANT_MASK_INSTR_ENTRY) != 0;
399406
}
400407

408+
bool instrLoopEntriesEnabled() const override {
409+
return (Version & VARIANT_MASK_INSTR_LOOP_ENTRIES) != 0;
410+
}
411+
401412
bool hasSingleByteCoverage() const override {
402413
return (Version & VARIANT_MASK_BYTE_COVERAGE) != 0;
403414
}
@@ -564,6 +575,7 @@ struct InstrProfReaderIndexBase {
564575
virtual bool isIRLevelProfile() const = 0;
565576
virtual bool hasCSIRLevelProfile() const = 0;
566577
virtual bool instrEntryBBEnabled() const = 0;
578+
virtual bool instrLoopEntriesEnabled() const = 0;
567579
virtual bool hasSingleByteCoverage() const = 0;
568580
virtual bool functionEntryOnly() const = 0;
569581
virtual bool hasMemoryProfile() const = 0;
@@ -628,6 +640,10 @@ class InstrProfReaderIndex : public InstrProfReaderIndexBase {
628640
return (FormatVersion & VARIANT_MASK_INSTR_ENTRY) != 0;
629641
}
630642

643+
bool instrLoopEntriesEnabled() const override {
644+
return (FormatVersion & VARIANT_MASK_INSTR_LOOP_ENTRIES) != 0;
645+
}
646+
631647
bool hasSingleByteCoverage() const override {
632648
return (FormatVersion & VARIANT_MASK_BYTE_COVERAGE) != 0;
633649
}
@@ -753,6 +769,10 @@ class IndexedInstrProfReader : public InstrProfReader {
753769
return Index->instrEntryBBEnabled();
754770
}
755771

772+
bool instrLoopEntriesEnabled() const override {
773+
return Index->instrLoopEntriesEnabled();
774+
}
775+
756776
bool hasSingleByteCoverage() const override {
757777
return Index->hasSingleByteCoverage();
758778
}

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: 17 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,11 @@ 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 TargetBB is a loop head (i.e.,
163+
// the current edge leads to a loop), set Weight to be minimal, so
164+
// that the edge won't be chosen for the MST and will be instrumented.
165+
if (InstrumentLoopEntries && LI->isLoopHeader(TargetBB))
166+
Weight = 0;
157167
if (Weight == 0)
158168
Weight++;
159169
auto *E = &addEdge(&BB, TargetBB, Weight);
@@ -291,10 +301,14 @@ template <class Edge, class BBInfo> class CFGMST {
291301
return *AllEdges.back();
292302
}
293303

294-
CFGMST(Function &Func, bool InstrumentFuncEntry,
304+
CFGMST(Function &Func, bool InstrumentFuncEntry, bool InstrumentLoopEntries,
295305
BranchProbabilityInfo *BPI = nullptr,
296-
BlockFrequencyInfo *BFI = nullptr)
297-
: F(Func), BPI(BPI), BFI(BFI), InstrumentFuncEntry(InstrumentFuncEntry) {
306+
BlockFrequencyInfo *BFI = nullptr, LoopInfo *LI = nullptr)
307+
: F(Func), BPI(BPI), BFI(BFI), LI(LI),
308+
InstrumentFuncEntry(InstrumentFuncEntry),
309+
InstrumentLoopEntries(InstrumentLoopEntries) {
310+
assert(!(InstrumentLoopEntries && !LI) &&
311+
"expected a LoopInfo to instrumenting loop entries");
298312
buildEdges();
299313
sortEdgesByWeight();
300314
computeMinimumSpanningTree();

llvm/lib/ProfileData/InstrProfReader.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
5353
if (Version & VARIANT_MASK_INSTR_ENTRY) {
5454
ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
5555
}
56+
if (Version & VARIANT_MASK_INSTR_LOOP_ENTRIES) {
57+
ProfileKind |= InstrProfKind::LoopEntriesInstrumentation;
58+
}
5659
if (Version & VARIANT_MASK_BYTE_COVERAGE) {
5760
ProfileKind |= InstrProfKind::SingleByteCoverage;
5861
}
@@ -263,6 +266,8 @@ Error TextInstrProfReader::readHeader() {
263266
ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
264267
else if (Str.equals_insensitive("not_entry_first"))
265268
ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
269+
else if (Str.equals_insensitive("instrument_loop_entries"))
270+
ProfileKind |= InstrProfKind::LoopEntriesInstrumentation;
266271
else if (Str.equals_insensitive("single_byte_coverage"))
267272
ProfileKind |= InstrProfKind::SingleByteCoverage;
268273
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
@@ -909,6 +909,9 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
909909
if (static_cast<bool>(ProfileKind &
910910
InstrProfKind::FunctionEntryInstrumentation))
911911
Header.Version |= VARIANT_MASK_INSTR_ENTRY;
912+
if (static_cast<bool>(ProfileKind &
913+
InstrProfKind::LoopEntriesInstrumentation))
914+
Header.Version |= VARIANT_MASK_INSTR_LOOP_ENTRIES;
912915
if (static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage))
913916
Header.Version |= VARIANT_MASK_BYTE_COVERAGE;
914917
if (static_cast<bool>(ProfileKind & InstrProfKind::FunctionEntryOnly))
@@ -1152,6 +1155,10 @@ Error InstrProfWriter::writeText(raw_fd_ostream &OS) {
11521155
if (static_cast<bool>(ProfileKind &
11531156
InstrProfKind::FunctionEntryInstrumentation))
11541157
OS << "# Always instrument the function entry block\n:entry_first\n";
1158+
if (static_cast<bool>(ProfileKind &
1159+
InstrProfKind::LoopEntriesInstrumentation))
1160+
OS << "# Always instrument the loop entry "
1161+
"blocks\n:instrument_loop_entries\n";
11551162
if (static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage))
11561163
OS << "# Instrument block coverage\n:single_byte_coverage\n";
11571164
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)