[BOLT] Call Distance Metric
Summary: Designed a new metric, which shows 93.46% correltation with Cache Miss and 86% correlation with CPU Time. Definition: One can get all the traversal path for each function. And for each traversal, we will define a distance. The distance represents how far two connected basic blocks are. Therefore, for each traversal, I will go through the basic blocks one by one, until the end of the traversal and sum up the distance for the neighboring basic blocks. Distance between two connected basic blocks is the distance of the centers of two blocks in the binary file. (cherry picked from FBD5242526)
This commit is contained in:
parent
3469396269
commit
ec304396c3
|
@ -64,6 +64,7 @@ add_llvm_tool(llvm-bolt
|
|||
BinaryContext.cpp
|
||||
BinaryFunction.cpp
|
||||
BinaryPassManager.cpp
|
||||
CalcCacheMetrics.cpp
|
||||
DataReader.cpp
|
||||
DebugData.cpp
|
||||
DWARFRewriter.cpp
|
||||
|
|
166
bolt/CalcCacheMetrics.cpp
Normal file
166
bolt/CalcCacheMetrics.cpp
Normal file
|
@ -0,0 +1,166 @@
|
|||
//===------ CalcCacheMetrics.cpp - Calculate metrics of cache lines -------===//
|
||||
//
|
||||
// Functions to show metrics of cache lines
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "BinaryBasicBlock.h"
|
||||
#include "BinaryContext.h"
|
||||
#include "BinaryFunction.h"
|
||||
#include "BinaryPassManager.h"
|
||||
#include "CalcCacheMetrics.h"
|
||||
#include "Exceptions.h"
|
||||
#include "RewriteInstance.h"
|
||||
#include "llvm/MC/MCAsmLayout.h"
|
||||
#include "llvm/MC/MCObjectStreamer.h"
|
||||
#include "llvm/MC/MCSectionELF.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace object;
|
||||
using namespace bolt;
|
||||
using Traversal = std::vector<BinaryBasicBlock *>;
|
||||
|
||||
namespace opts {
|
||||
|
||||
extern cl::OptionCategory BoltOptCategory;
|
||||
|
||||
} // namespace opts
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/// Initialize and return a position map for binary basic blocks.
|
||||
std::unordered_map<BinaryBasicBlock *, double>
|
||||
getPositionMap(const BinaryFunction &Function) {
|
||||
std::unordered_map<BinaryBasicBlock *, double> DistMap;
|
||||
double CurrAddress = 0;
|
||||
for (auto *BB : Function.layout()) {
|
||||
uint64_t Size = BB->estimateSize();
|
||||
DistMap[BB] = CurrAddress + (double)Size / 2;
|
||||
CurrAddress += Size;
|
||||
}
|
||||
return DistMap;
|
||||
}
|
||||
|
||||
/// Initialize and return a vector of traversals for a given function and its
|
||||
/// entry point
|
||||
std::vector<Traversal> getTraversals(const BinaryFunction &Function,
|
||||
BinaryBasicBlock *BB) {
|
||||
std::vector<Traversal> AllTraversals;
|
||||
std::stack<std::pair<BinaryBasicBlock *, Traversal>> Stack;
|
||||
Stack.push(std::make_pair(BB, Traversal()));
|
||||
std::unordered_set<BinaryBasicBlock *> BBSet;
|
||||
|
||||
while (!Stack.empty()) {
|
||||
BinaryBasicBlock *CurrentBB = Stack.top().first;
|
||||
Traversal PrevTraversal(Stack.top().second);
|
||||
Stack.pop();
|
||||
|
||||
// Add current basic block into consideration
|
||||
BBSet.insert(CurrentBB);
|
||||
PrevTraversal.push_back(CurrentBB);
|
||||
|
||||
if (CurrentBB->succ_empty()) {
|
||||
AllTraversals.push_back(PrevTraversal);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t SuccTotalCount = 0;
|
||||
// Calculate total edges count of successors
|
||||
for (auto BI = CurrentBB->branch_info_begin();
|
||||
BI != CurrentBB->branch_info_end(); ++BI) {
|
||||
if (BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE) {
|
||||
SuccTotalCount += BI->Count;
|
||||
}
|
||||
}
|
||||
if (SuccTotalCount == 0) {
|
||||
AllTraversals.push_back(PrevTraversal);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto BI = CurrentBB->branch_info_begin();
|
||||
for (auto *SuccBB : CurrentBB->successors()) {
|
||||
if (BBSet.find(SuccBB) == BBSet.end() && BI->Count != 0 &&
|
||||
BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE) {
|
||||
Stack.push(std::make_pair(SuccBB, PrevTraversal));
|
||||
}
|
||||
++BI;
|
||||
}
|
||||
}
|
||||
|
||||
return AllTraversals;
|
||||
}
|
||||
|
||||
/// Given a traversal, return the sum of block distances along this traversal.
|
||||
double
|
||||
getTraversalLength(std::unordered_map<BinaryBasicBlock *, double> &DistMap,
|
||||
Traversal const &Path) {
|
||||
if (Path.size() <= 1) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double Length = 0.0;
|
||||
BinaryBasicBlock *PrevBB = Path.front();
|
||||
for (auto BBI = std::next(Path.begin()); BBI != Path.end(); ++BBI) {
|
||||
Length += std::abs(DistMap[*BBI] - DistMap[PrevBB]);
|
||||
PrevBB = *BBI;
|
||||
}
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
/// Helper function of calcGraphDistance to go through the call traversals of
|
||||
/// certain function and to calculate and record the length of each
|
||||
/// traversal.
|
||||
void graphDistHelper(std::vector<Traversal> &AllTraversals,
|
||||
const BinaryFunction &Function,
|
||||
std::unordered_map<uint64_t, double> &TraversalMap,
|
||||
uint64_t &TraversalCount) {
|
||||
auto DistMap = getPositionMap(Function);
|
||||
|
||||
for (auto const &Path : AllTraversals) {
|
||||
TraversalMap[++TraversalCount] = getTraversalLength(DistMap, Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalcCacheMetrics::calcGraphDistance(
|
||||
const std::map<uint64_t, BinaryFunction> &BinaryFunctions) {
|
||||
|
||||
double TotalFuncValue = 0;
|
||||
uint64_t FuncCount = 0;
|
||||
for (auto &BFI : BinaryFunctions) {
|
||||
auto &Function = BFI.second;
|
||||
|
||||
std::unordered_map<uint64_t, double> TraversalMap;
|
||||
uint64_t TraversalCount = 0;
|
||||
for (auto *BB : Function.layout()) {
|
||||
if (BB->isEntryPoint()) {
|
||||
auto AllTraversals = getTraversals(Function, BB);
|
||||
graphDistHelper(AllTraversals, Function, TraversalMap, TraversalCount);
|
||||
}
|
||||
}
|
||||
|
||||
double TotalValue = 0;
|
||||
for (auto const &Entry : TraversalMap) {
|
||||
TotalValue += Entry.second;
|
||||
}
|
||||
|
||||
double AverageValue =
|
||||
TraversalMap.empty() ? 0 : (TotalValue * 1.0 / TraversalMap.size());
|
||||
TotalFuncValue += AverageValue;
|
||||
++FuncCount;
|
||||
}
|
||||
|
||||
outs() << format(" Sum of averages of traversal distance for all "
|
||||
"functions is: %.2f\n",
|
||||
TotalFuncValue)
|
||||
<< format(" There are %u functions in total\n", FuncCount)
|
||||
<< format(" On average, every traversal is %.2f long\n\n",
|
||||
TotalFuncValue / FuncCount);
|
||||
}
|
27
bolt/CalcCacheMetrics.h
Normal file
27
bolt/CalcCacheMetrics.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
//===- CalcCacheMetrics.h - Interface for metrics printing of cache lines --===//
|
||||
//
|
||||
// Functions to show metrics of cache lines
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CALCCACHEMETRICS_H
|
||||
#define LLVM_CALCCACHEMETRICS_H
|
||||
|
||||
#include "BinaryFunction.h"
|
||||
#include <map>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace object;
|
||||
using namespace bolt;
|
||||
|
||||
namespace CalcCacheMetrics {
|
||||
/// Calculate average number of call distance for every graph traversal.
|
||||
void calcGraphDistance(
|
||||
const std::map<uint64_t, BinaryFunction> &BinaryFunctions);
|
||||
}
|
||||
|
||||
#endif //LLVM_CALCCACHEMETRICS_H
|
|
@ -14,6 +14,7 @@
|
|||
#include "BinaryContext.h"
|
||||
#include "BinaryFunction.h"
|
||||
#include "BinaryPassManager.h"
|
||||
#include "CalcCacheMetrics.h"
|
||||
#include "DataReader.h"
|
||||
#include "Exceptions.h"
|
||||
#include "RewriteInstance.h"
|
||||
|
@ -73,6 +74,13 @@ extern cl::OptionCategory BoltOptCategory;
|
|||
extern cl::opt<JumpTableSupportLevel> JumpTables;
|
||||
extern cl::opt<BinaryFunction::ReorderType> ReorderFunctions;
|
||||
|
||||
static cl::opt<bool>
|
||||
CalcCacheMetrics("calc-cache-metrics",
|
||||
cl::desc("calculate metrics of cache lines"),
|
||||
cl::init(false),
|
||||
cl::ZeroOrMore,
|
||||
cl::cat(BoltOptCategory));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o",
|
||||
cl::desc("<output file>"),
|
||||
|
@ -811,6 +819,12 @@ void RewriteInstance::run() {
|
|||
emitFunctions();
|
||||
}
|
||||
|
||||
if (opts::CalcCacheMetrics) {
|
||||
outs() << "\nBOLT-INFO: After Optimization Call Graph Statistics: Call "
|
||||
"Distance \n\n";
|
||||
CalcCacheMetrics::calcGraphDistance(BinaryFunctions);
|
||||
}
|
||||
|
||||
if (opts::UpdateDebugSections)
|
||||
updateDebugInfo();
|
||||
|
||||
|
@ -1858,6 +1872,12 @@ void RewriteInstance::disassembleFunctions() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::CalcCacheMetrics) {
|
||||
outs() << "\nBOLT-INFO: Before Optimization Call Graph Statistics: Call "
|
||||
"Distance \n\n";
|
||||
CalcCacheMetrics::calcGraphDistance(BinaryFunctions);
|
||||
}
|
||||
}
|
||||
|
||||
void RewriteInstance::runOptimizationPasses() {
|
||||
|
|
Loading…
Reference in a new issue