Skip to content

Commit

Permalink
[PGO] Resubmit "MST based PGO instrumentation infrastructure" (r254021)
Browse files Browse the repository at this point in the history
This new patch fixes a few bugs that exposed in last submit. It also improves
the test cases.
--Original Commit Message--
This patch implements a minimum spanning tree (MST) based instrumentation for
PGO. The use of MST guarantees minimum number of CFG edges getting
instrumented. An addition optimization is to instrument the less executed
edges to further reduce the instrumentation overhead. The patch contains both the
instrumentation and the use of the profile to set the branch weights.

Differential Revision: http://reviews.llvm.org/D12781

llvm-svn: 255132
  • Loading branch information
xur-llvm committed Dec 9, 2015
1 parent f0cccb3 commit f430ae4
Show file tree
Hide file tree
Showing 29 changed files with 1,570 additions and 1 deletion.
26 changes: 26 additions & 0 deletions llvm/include/llvm/IR/DiagnosticInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ enum DiagnosticKind {
DK_OptimizationRemarkAnalysisAliasing,
DK_OptimizationFailure,
DK_MIRParser,
DK_PGOProfile,
DK_FirstPluginKind
};

Expand Down Expand Up @@ -250,6 +251,31 @@ class DiagnosticInfoSampleProfile : public DiagnosticInfo {
const Twine &Msg;
};

/// Diagnostic information for the PGO profiler.
class DiagnosticInfoPGOProfile : public DiagnosticInfo {
public:
DiagnosticInfoPGOProfile(const char *FileName, const Twine &Msg,
DiagnosticSeverity Severity = DS_Error)
: DiagnosticInfo(DK_PGOProfile, Severity), FileName(FileName), Msg(Msg) {}

/// \see DiagnosticInfo::print.
void print(DiagnosticPrinter &DP) const override;

static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_PGOProfile;
}

const char *getFileName() const { return FileName; }
const Twine &getMsg() const { return Msg; }

private:
/// Name of the input file associated with this diagnostic.
const char *FileName;

/// Message to report.
const Twine &Msg;
};

/// Common features for diagnostics dealing with optimization remarks.
class DiagnosticInfoOptimizationBase : public DiagnosticInfo {
public:
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ void initializeEdgeBundlesPass(PassRegistry&);
void initializeExpandPostRAPass(PassRegistry&);
void initializeAAResultsWrapperPassPass(PassRegistry &);
void initializeGCOVProfilerPass(PassRegistry&);
void initializePGOInstrumentationGenPass(PassRegistry&);
void initializePGOInstrumentationUsePass(PassRegistry&);
void initializeInstrProfilingPass(PassRegistry&);
void initializeAddressSanitizerPass(PassRegistry&);
void initializeAddressSanitizerModulePass(PassRegistry&);
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/LinkAllPasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ namespace {
(void) llvm::createDomOnlyViewerPass();
(void) llvm::createDomViewerPass();
(void) llvm::createGCOVProfilerPass();
(void) llvm::createPGOInstrumentationGenPass();
(void) llvm::createPGOInstrumentationUsePass();
(void) llvm::createInstrProfilingPass();
(void) llvm::createFunctionImportPass();
(void) llvm::createFunctionInliningPass();
Expand Down
23 changes: 23 additions & 0 deletions llvm/include/llvm/Transforms/Instrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ struct GCOVOptions {
ModulePass *createGCOVProfilerPass(const GCOVOptions &Options =
GCOVOptions::getDefault());

// PGO Instrumention
ModulePass *createPGOInstrumentationGenPass();
ModulePass *
createPGOInstrumentationUsePass(StringRef Filename = StringRef(""));

/// Options for the frontend instrumentation based profiling pass.
struct InstrProfOptions {
InstrProfOptions() : NoRedZone(false) {}
Expand Down Expand Up @@ -149,6 +154,24 @@ FunctionPass *createBoundsCheckingPass();
/// protect against stack-based overflow vulnerabilities.
FunctionPass *createSafeStackPass(const TargetMachine *TM = nullptr);

/// \brief Calculate what to divide by to scale counts.
///
/// Given the maximum count, calculate a divisor that will scale all the
/// weights to strictly less than UINT32_MAX.
static inline uint64_t calculateCountScale(uint64_t MaxCount) {
return MaxCount < UINT32_MAX ? 1 : MaxCount / UINT32_MAX + 1;
}

/// \brief Scale an individual branch count.
///
/// Scale a 64-bit weight down to 32-bits using \c Scale.
///
static inline uint32_t scaleBranchCount(uint64_t Count, uint64_t Scale) {
uint64_t Scaled = Count / Scale;
assert(Scaled <= UINT32_MAX && "overflow 32-bits");
return Scaled;
}

} // End llvm namespace

#endif
6 changes: 6 additions & 0 deletions llvm/lib/IR/DiagnosticInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const {
DP << getMsg();
}

void DiagnosticInfoPGOProfile::print(DiagnosticPrinter &DP) const {
if (getFileName())
DP << getFileName() << ": ";
DP << getMsg();
}

bool DiagnosticInfoOptimizationBase::isLocationAvailable() const {
return getDebugLoc();
}
Expand Down
217 changes: 217 additions & 0 deletions llvm/lib/Transforms/Instrumentation/CFGMST.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
//===-- CFGMST.h - Minimum Spanning Tree for CFG ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a Union-find algorithm to compute Minimum Spanning Tree
// for a given CFG.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <string>
#include <utility>
#include <vector>

namespace llvm {

#define DEBUG_TYPE "cfgmst"

/// \brief An union-find based Minimum Spanning Tree for CFG
///
/// Implements a Union-find algorithm to compute Minimum Spanning Tree
/// for a given CFG.
template <class Edge, class BBInfo> class CFGMST {
public:
Function &F;

// Store all the edges in CFG. It may contain some stale edges
// when Removed is set.
std::vector<std::unique_ptr<Edge>> AllEdges;

// This map records the auxiliary information for each BB.
DenseMap<const BasicBlock *, std::unique_ptr<BBInfo>> BBInfos;

// Find the root group of the G and compress the path from G to the root.
BBInfo *findAndCompressGroup(BBInfo *G) {
if (G->Group != G)
G->Group = findAndCompressGroup(static_cast<BBInfo *>(G->Group));
return static_cast<BBInfo *>(G->Group);
}

// Union BB1 and BB2 into the same group and return true.
// Returns false if BB1 and BB2 are already in the same group.
bool unionGroups(const BasicBlock *BB1, const BasicBlock *BB2) {
BBInfo *BB1G = findAndCompressGroup(&getBBInfo(BB1));
BBInfo *BB2G = findAndCompressGroup(&getBBInfo(BB2));

if (BB1G == BB2G)
return false;

// Make the smaller rank tree a direct child or the root of high rank tree.
if (BB1G->Rank < BB2G->Rank)
BB1G->Group = BB2G;
else {
BB2G->Group = BB1G;
// If the ranks are the same, increment root of one tree by one.
if (BB1G->Rank == BB2G->Rank)
BB1G->Rank++;
}
return true;
}

// Give BB, return the auxiliary information.
BBInfo &getBBInfo(const BasicBlock *BB) const {
auto It = BBInfos.find(BB);
assert(It->second.get() != nullptr);
return *It->second.get();
}

// Traverse the CFG using a stack. Find all the edges and assign the weight.
// Edges with large weight will be put into MST first so they are less likely
// to be instrumented.
void buildEdges() {
DEBUG(dbgs() << "Build Edge on " << F.getName() << "\n");

const BasicBlock *BB = &(F.getEntryBlock());
uint64_t EntryWeight = (BFI != nullptr ? BFI->getEntryFreq() : 2);
// Add a fake edge to the entry.
addEdge(nullptr, BB, EntryWeight);

// Special handling for single BB functions.
if (succ_empty(BB)) {
addEdge(BB, nullptr, EntryWeight);
return;
}

static const uint32_t CriticalEdgeMultiplier = 1000;

for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
TerminatorInst *TI = BB->getTerminator();
uint64_t BBWeight =
(BFI != nullptr ? BFI->getBlockFreq(&*BB).getFrequency() : 2);
uint64_t Weight = 2;
if (int successors = TI->getNumSuccessors()) {
for (int i = 0; i != successors; ++i) {
BasicBlock *TargetBB = TI->getSuccessor(i);
bool Critical = isCriticalEdge(TI, i);
uint64_t scaleFactor = BBWeight;
if (Critical) {
if (scaleFactor < UINT64_MAX / CriticalEdgeMultiplier)
scaleFactor *= CriticalEdgeMultiplier;
else
scaleFactor = UINT64_MAX;
}
if (BPI != nullptr)
Weight = BPI->getEdgeProbability(&*BB, TargetBB).scale(scaleFactor);
addEdge(&*BB, TargetBB, Weight).IsCritical = Critical;
DEBUG(dbgs() << " Edge: from " << BB->getName() << " to "
<< TargetBB->getName() << " w=" << Weight << "\n");
}
} else {
addEdge(&*BB, nullptr, BBWeight);
DEBUG(dbgs() << " Edge: from " << BB->getName() << " to exit"
<< " w = " << BBWeight << "\n");
}
}
}

// Sort CFG edges based on its weight.
void sortEdgesByWeight() {
std::stable_sort(AllEdges.begin(), AllEdges.end(),
[](const std::unique_ptr<Edge> &Edge1,
const std::unique_ptr<Edge> &Edge2) {
return Edge1->Weight > Edge2->Weight;
});
}

// Traverse all the edges and compute the Minimum Weight Spanning Tree
// using union-find algorithm.
void computeMinimumSpanningTree() {
// First, put all the critical edge with landing-pad as the Dest to MST.
// This works around the insufficient support of critical edges split
// when destination BB is a landing pad.
for (auto &Ei : AllEdges) {
if (Ei->Removed)
continue;
if (Ei->IsCritical) {
if (Ei->DestBB && Ei->DestBB->isLandingPad()) {
if (unionGroups(Ei->SrcBB, Ei->DestBB))
Ei->InMST = true;
}
}
}

for (auto &Ei : AllEdges) {
if (Ei->Removed)
continue;
if (unionGroups(Ei->SrcBB, Ei->DestBB))
Ei->InMST = true;
}
}

// Dump the Debug information about the instrumentation.
void dumpEdges(raw_ostream &OS, const Twine &Message) const {
if (!Message.str().empty())
OS << Message << "\n";
OS << " Number of Basic Blocks: " << BBInfos.size() << "\n";
for (auto &BI : BBInfos) {
const BasicBlock *BB = BI.first;
OS << " BB: " << (BB == nullptr ? "FakeNode" : BB->getName()) << " "
<< BI.second->infoString() << "\n";
}

OS << " Number of Edges: " << AllEdges.size()
<< " (*: Instrument, C: CriticalEdge, -: Removed)\n";
uint32_t Count = 0;
for (auto &EI : AllEdges)
OS << " Edge " << Count++ << ": " << getBBInfo(EI->SrcBB).Index << "-->"
<< getBBInfo(EI->DestBB).Index << EI->infoString() << "\n";
}

// Add an edge to AllEdges with weight W.
Edge &addEdge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W) {
uint32_t Index = BBInfos.size();
auto Iter = BBInfos.end();
bool Inserted;
std::tie(Iter, Inserted) = BBInfos.insert(std::make_pair(Src, nullptr));
if (Inserted) {
// Newly inserted, update the real info.
Iter->second = std::move(llvm::make_unique<BBInfo>(Index));
Index++;
}
std::tie(Iter, Inserted) = BBInfos.insert(std::make_pair(Dest, nullptr));
if (Inserted)
// Newly inserted, update the real info.
Iter->second = std::move(llvm::make_unique<BBInfo>(Index));
AllEdges.emplace_back(new Edge(Src, Dest, W));
return *AllEdges.back();
}

BranchProbabilityInfo *BPI;
BlockFrequencyInfo *BFI;

public:
CFGMST(Function &Func, BranchProbabilityInfo *BPI_ = nullptr,
BlockFrequencyInfo *BFI_ = nullptr)
: F(Func), BPI(BPI_), BFI(BFI_) {
buildEdges();
sortEdgesByWeight();
computeMinimumSpanningTree();
}
};

#undef DEBUG_TYPE // "cfgmst"
} // end namespace llvm
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Instrumentation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_llvm_library(LLVMInstrumentation
MemorySanitizer.cpp
Instrumentation.cpp
InstrProfiling.cpp
PGOInstrumentation.cpp
SafeStack.cpp
SanitizerCoverage.cpp
ThreadSanitizer.cpp
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/Instrumentation/Instrumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) {
initializeAddressSanitizerModulePass(Registry);
initializeBoundsCheckingPass(Registry);
initializeGCOVProfilerPass(Registry);
initializePGOInstrumentationGenPass(Registry);
initializePGOInstrumentationUsePass(Registry);
initializeInstrProfilingPass(Registry);
initializeMemorySanitizerPass(Registry);
initializeThreadSanitizerPass(Registry);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Instrumentation/LLVMBuild.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@
type = Library
name = Instrumentation
parent = Transforms
required_libraries = Analysis Core MC Support TransformUtils
required_libraries = Analysis Core MC Support TransformUtils ProfileData
Loading

0 comments on commit f430ae4

Please sign in to comment.