[PGO] Add PGO to LDC. Supported for LLVM >= 3.7

Add the commandline options -fprofile-instr-generate[=filename] and -profile-instr-use=filename
-fprofile-instr-generate
-- Add instrumentation on branches, switches, and function entry; uses LLVM's InstrProf pass.
-- Link to profile runtime that writes instrumentation counters to a file.
-fprofile-instr-use
-- Read profile data from a file and apply branch weights to branches and switches, and annotate functions with entrycount in LLVM IR.
-- Functions with low or high entrycount are marked with 'cold' or 'inlinehint'.

The only statement type without PGO yet is "try-finally".

A new pragma, `pragma(LDC_profile_instr, [ true | false ])`, is added to selectively disable/enable instrumentation of functions (granularity = whole functions).

The runtime library ldc-profile-rt is a copy of LLVM compiler-rt lib/profile. It has to be exactly in-sync with the LLVM version, and thus we need a copy for each PGO-supported LLVM (>=3.7).
import ldc.profile for a D interface to ldc-profile-rt (for example to reset execution counts after a program startup phase).

The instrumentation data is mainly passed on to LLVM: function-entry counts and branch counts/probabilities. LDC marks functions as hot when "execution count is 30% of the maximum function execution count", and marks functions as cold if their count is 1% of maximum function execution count.

The source of LLVM's llvm-profdata tool is hereby included in LDCs repository (different source for each LLVM version), and the binary is included in the install bin folder.
The executable is named "ldc-profdata" to avoid clashing with llvm-profdata on the same machine. This is needed because profdata executable has to be in-sync with the LLVM version used to build LDC.

Maintenance burden: for trunk LLVM, we have to keep ldc-profile-rt and llvm-profdata in sync. There is no diff with upstream; but because of active development there are the occasional API changes.
This commit is contained in:
Johan Engelen 2015-11-17 00:52:59 +01:00 committed by Johan Engelen
parent a81ac7d790
commit e0d9c58443
99 changed files with 11857 additions and 64 deletions

View file

@ -28,9 +28,10 @@ GotoJump::GotoJump(Loc loc, llvm::BasicBlock *sourceBlock,
tentativeTarget(tentativeTarget), targetLabel(targetLabel) {}
CatchScope::CatchScope(llvm::Constant *classInfoPtr,
llvm::BasicBlock *bodyBlock, CleanupCursor cleanupScope)
llvm::BasicBlock *bodyBlock, CleanupCursor cleanupScope,
llvm::MDNode *branchWeights)
: classInfoPtr(classInfoPtr), bodyBlock(bodyBlock),
cleanupScope(cleanupScope) {}
branchWeights(branchWeights), cleanupScope(cleanupScope) {}
bool useMSVCEH() {
#if LDC_LLVM_VER >= 308
@ -54,7 +55,7 @@ llvm::BasicBlock *executeCleanupCopying(IRState *irs, CleanupScope &scope,
llvm::BasicBlock *sourceBlock,
llvm::BasicBlock *continueWith,
llvm::BasicBlock *unwindTo,
llvm::Value* funclet) {
llvm::Value *funclet) {
if (isCatchSwitchBlock(scope.beginBlock))
return continueWith;
if (scope.cleanupBlocks.empty()) {
@ -253,7 +254,6 @@ llvm::BasicBlock *ScopeStack::runCleanupPad(CleanupCursor scope,
if (isCatchSwitchBlock(cleanupScopes[scope].beginBlock))
return cleanupScopes[scope].beginBlock;
// each cleanup block is bracketed by a pair of cleanuppad/cleanupret
// instructions, any unwinding should also just continue at the next
// cleanup block, e.g.:
@ -261,7 +261,7 @@ llvm::BasicBlock *ScopeStack::runCleanupPad(CleanupCursor scope,
// cleanuppad:
// %0 = cleanuppad within %funclet[]
// %frame = nullptr
// if (!_d_enter_cleanup(%frame)) br label %cleanupret
// if (!_d_enter_cleanup(%frame)) br label %cleanupret
// else br label %copy
//
// copy:
@ -279,7 +279,7 @@ llvm::BasicBlock *ScopeStack::runCleanupPad(CleanupCursor scope,
llvm::BasicBlock *cleanupret =
llvm::BasicBlock::Create(irs->context(), "cleanupret", irs->topfunc());
// preparation to allocate some space on the stack where _d_enter_cleanup
// preparation to allocate some space on the stack where _d_enter_cleanup
// can place an exception frame (but not done here)
auto frame = getNullPtr(getVoidPtrType());
@ -320,8 +320,8 @@ void ScopeStack::popCleanups(CleanupCursor targetScope) {
llvm::BasicBlock *tentative = gotoJump.tentativeTarget;
#if LDC_LLVM_VER >= 308
if (useMSVCEH()) {
llvm::BasicBlock *continueWith =
llvm::BasicBlock::Create(irs->context(), "jumpcleanup", irs->topfunc());
llvm::BasicBlock *continueWith = llvm::BasicBlock::Create(
irs->context(), "jumpcleanup", irs->topfunc());
auto startCleanup =
executeCleanupCopying(irs, cleanupScopes[i], gotoJump.sourceBlock,
continueWith, nullptr, nullptr);
@ -350,14 +350,16 @@ void ScopeStack::popCleanups(CleanupCursor targetScope) {
}
void ScopeStack::pushCatch(llvm::Constant *classInfoPtr,
llvm::BasicBlock *bodyBlock) {
llvm::BasicBlock *bodyBlock,
llvm::MDNode *matchWeights) {
if (useMSVCEH()) {
#if LDC_LLVM_VER >= 308
assert(isCatchSwitchBlock(bodyBlock));
pushCleanup(bodyBlock, bodyBlock);
#endif
} else {
catchScopes.emplace_back(classInfoPtr, bodyBlock, currentCleanupScope());
catchScopes.emplace_back(classInfoPtr, bodyBlock, currentCleanupScope(),
matchWeights);
currentLandingPads().push_back(nullptr);
}
}
@ -585,7 +587,7 @@ llvm::BasicBlock *ScopeStack::emitLandingPad() {
irs->ir->CreateCondBr(
irs->ir->CreateICmpEQ(irs->ir->CreateLoad(irs->func()->ehSelectorSlot),
ehTypeId),
it->bodyBlock, mismatchBB);
it->bodyBlock, mismatchBB, it->branchWeights);
irs->scope() = IRScope(mismatchBB);
}