diff --git a/bolt/BinaryFunction.cpp b/bolt/BinaryFunction.cpp index fe397319a92e..7de9ada88771 100644 --- a/bolt/BinaryFunction.cpp +++ b/bolt/BinaryFunction.cpp @@ -53,6 +53,7 @@ extern cl::opt Relocs; extern cl::opt UpdateDebugSections; extern cl::opt IndirectCallPromotion; extern cl::opt Verbosity; +extern cl::opt PrintFuncStat; static cl::opt 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> ChangeMatrix( + LayoutSize + 1, std::vector(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()) { diff --git a/bolt/BinaryFunction.h b/bolt/BinaryFunction.h index affbd39ade44..531f1e3107d0 100644 --- a/bolt/BinaryFunction.h +++ b/bolt/BinaryFunction.h @@ -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; } diff --git a/bolt/Passes/BinaryPasses.cpp b/bolt/Passes/BinaryPasses.cpp index 5ff491935d2a..95fcef30fc31 100644 --- a/bolt/Passes/BinaryPasses.cpp +++ b/bolt/Passes/BinaryPasses.cpp @@ -97,6 +97,13 @@ PrintSortedBy("print-sorted-by", cl::ZeroOrMore, cl::cat(BoltOptCategory)); +cl::opt +PrintFuncStat("print-function-statistics", + cl::desc("print statistics about basic block ordering"), + cl::init(0), + cl::ZeroOrMore, + cl::cat(BoltOptCategory)); + static cl::opt 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 &BFs, - std::set &LargeFunctions) { + BinaryContext &BC, + std::map &BFs, + std::set &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 ScoreMap; + for (auto It = BFs.begin(); It != BFs.end(); ++It) { + ScoreMap.insert(std::pair( + 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::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"; + } } }