[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:
Bohan Ren 2017-06-13 16:29:39 -07:00 committed by Maksim Panchenko
parent 3469396269
commit ec304396c3
4 changed files with 214 additions and 0 deletions

View file

@ -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
View 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
View 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

View file

@ -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() {