[BOLT] Expand BOLT report for basic block ordering

Summary:
Add a new positional option onto bolt: "-print-function-statistics=<uint64>"
which prints information about block ordering for requested number of functions.

(cherry picked from FBD5105323)
This commit is contained in:
Bohan Ren 2017-05-22 11:04:01 -07:00 committed by Maksim Panchenko
parent ea53066287
commit eb63a0b295
3 changed files with 114 additions and 9 deletions

View File

@ -53,6 +53,7 @@ extern cl::opt<bool> Relocs;
extern cl::opt<bool> UpdateDebugSections;
extern cl::opt<IndirectCallPromotionType> IndirectCallPromotion;
extern cl::opt<unsigned> Verbosity;
extern cl::opt<unsigned> PrintFuncStat;
static cl::opt<bool>
AggressiveSplitting("split-all-cold",
@ -2538,6 +2539,8 @@ void BinaryFunction::modifyLayout(LayoutType Type, bool MinBranchClusters,
}
Algo->reorderBasicBlocks(*this, NewLayout);
if (opts::PrintFuncStat > 0)
BasicBlocksPreviousLayout = BasicBlocksLayout;
BasicBlocksLayout.clear();
BasicBlocksLayout.swap(NewLayout);
@ -2545,6 +2548,49 @@ void BinaryFunction::modifyLayout(LayoutType Type, bool MinBranchClusters,
splitFunction();
}
uint64_t BinaryFunction::getInstructionCount() const {
uint64_t Count = 0;
for (auto &Block : BasicBlocksLayout) {
Count += Block->getNumNonPseudos();
}
return Count;
}
bool BinaryFunction::hasLayoutChanged() const {
assert(opts::PrintFuncStat > 0 && "PrintFuncStat flag is not on");
return BasicBlocksPreviousLayout != BasicBlocksLayout;
}
uint64_t BinaryFunction::getEditDistance() const {
assert(opts::PrintFuncStat > 0 && "PrintFuncStat flag is not on");
const auto LayoutSize = BasicBlocksPreviousLayout.size();
if (LayoutSize < 2) {
return 0;
}
std::vector<std::vector<uint64_t>> ChangeMatrix(
LayoutSize + 1, std::vector<uint64_t>(LayoutSize + 1));
for (uint64_t I = 0; I <= LayoutSize; ++I) {
ChangeMatrix[I][0] = I;
ChangeMatrix[0][I] = I;
}
for (uint64_t I = 1; I <= LayoutSize; ++I) {
for (uint64_t J = 1; J <= LayoutSize; ++J) {
if (BasicBlocksPreviousLayout[I] != BasicBlocksLayout[J]) {
ChangeMatrix[I][J] =
std::min(std::min(ChangeMatrix[I - 1][J], ChangeMatrix[I][J - 1]),
ChangeMatrix[I - 1][J - 1]) + 1;
} else {
ChangeMatrix[I][J] = ChangeMatrix[I - 1][J - 1];
}
}
}
return ChangeMatrix[LayoutSize][LayoutSize];
}
void BinaryFunction::emitBody(MCStreamer &Streamer, bool EmitColdPart) {
int64_t CurrentGnuArgsSize = 0;
for (auto BB : layout()) {

View File

@ -694,6 +694,8 @@ private:
BasicBlockListType BasicBlocks;
BasicBlockListType DeletedBasicBlocks;
BasicBlockOrderType BasicBlocksLayout;
/// Previous layout replaced by modifyLayout
BasicBlockOrderType BasicBlocksPreviousLayout;
/// BasicBlockOffsets are used during CFG construction to map from code
/// offsets to BinaryBasicBlocks. Any modifications made to the CFG
@ -1711,6 +1713,17 @@ public:
/// and size.
uint64_t getFunctionScore();
/// Return true if the layout has been changed by basic block reordering,
/// false otherwise.
bool hasLayoutChanged() const;
/// Get the edit distance of the new layout with respect to the previous
/// layout after basic block reordering.
uint64_t getEditDistance() const;
/// Get the number of instructions within this function.
uint64_t getInstructionCount() const;
const CFIInstrMapType &getFDEProgram() const {
return FrameInstructions;
}

View File

@ -97,6 +97,13 @@ PrintSortedBy("print-sorted-by",
cl::ZeroOrMore,
cl::cat(BoltOptCategory));
cl::opt<unsigned>
PrintFuncStat("print-function-statistics",
cl::desc("print statistics about basic block ordering"),
cl::init(0),
cl::ZeroOrMore,
cl::cat(BoltOptCategory));
static cl::opt<bolt::BinaryFunction::LayoutType>
ReorderBlocks("reorder-blocks",
cl::desc("change layout of basic blocks in a function"),
@ -293,25 +300,64 @@ bool ReorderBasicBlocks::shouldPrint(const BinaryFunction &BF) const {
}
void ReorderBasicBlocks::runOnFunctions(
BinaryContext &BC,
std::map<uint64_t, BinaryFunction> &BFs,
std::set<uint64_t> &LargeFunctions) {
BinaryContext &BC,
std::map<uint64_t, BinaryFunction> &BFs,
std::set<uint64_t> &LargeFunctions) {
if (opts::ReorderBlocks == BinaryFunction::LT_NONE)
return;
uint64_t ModifiedFuncCount = 0;
for (auto &It : BFs) {
auto &Function = It.second;
if (!shouldOptimize(Function))
continue;
if (!shouldOptimize(Function))
continue;
const bool ShouldSplit =
(opts::SplitFunctions == BinaryFunction::ST_ALL) ||
(opts::SplitFunctions == BinaryFunction::ST_EH &&
Function.hasEHRanges()) ||
(LargeFunctions.find(It.first) != LargeFunctions.end());
(opts::SplitFunctions == BinaryFunction::ST_ALL) ||
(opts::SplitFunctions == BinaryFunction::ST_EH &&
Function.hasEHRanges()) ||
(LargeFunctions.find(It.first) != LargeFunctions.end());
Function.modifyLayout(opts::ReorderBlocks, opts::MinBranchClusters,
ShouldSplit);
if (opts::PrintFuncStat > 0 && Function.hasLayoutChanged()) {
++ModifiedFuncCount;
}
}
if (opts::PrintFuncStat > 0) {
raw_ostream &OS = outs();
// Copy all the values into vector in order to sort them
std::map<uint64_t, BinaryFunction &> ScoreMap;
for (auto It = BFs.begin(); It != BFs.end(); ++It) {
ScoreMap.insert(std::pair<uint64_t, BinaryFunction &>(
It->second.getFunctionScore(), It->second));
}
OS << "\nBOLT-INFO: Printing Function Statistics:\n\n";
OS << " There are " << BFs.size() << " functions in total. \n";
OS << " Number of functions being modified: " << ModifiedFuncCount
<< "\n";
OS << " User asks for detailed information on top "
<< opts::PrintFuncStat << " functions. (Ranked by function score)"
<< "\n\n";
uint64_t I = 0;
for (std::map<uint64_t, BinaryFunction &>::reverse_iterator
Rit = ScoreMap.rbegin();
Rit != ScoreMap.rend() && I < opts::PrintFuncStat; ++Rit, ++I) {
auto &Function = Rit->second;
OS << " Information for function of top: " << (I + 1) << ": \n";
OS << " Function Score is: " << Function.getFunctionScore()
<< "\n";
OS << " There are " << Function.size()
<< " number of blocks in this function.\n";
OS << " There are " << Function.getInstructionCount()
<< " number of instructions in this function.\n";
OS << " The edit distance for this function is: "
<< Function.getEditDistance() << "\n\n";
}
}
}