add: get function score to find hot functions refine the dumped csv format

Summary: minor modification of the bolt stoke pass

(cherry picked from FBD5471011)
This commit is contained in:
Yue Zhao 2017-07-13 15:02:52 -07:00 committed by Maksim Panchenko
parent 6d845719ce
commit 70bad8d34d
2 changed files with 65 additions and 56 deletions

View File

@ -1,16 +1,18 @@
#include "StokeInfo.h"
#include "llvm/Support/Options.h"
#undef DEBUG_TYPE
#define DEBUG_TYPE "stoke"
using namespace llvm;
using namespace bolt;
namespace opts {
cl::OptionCategory StokeOptCategory("STOKE generic options");
cl::OptionCategory StokeOptCategory("STOKE pass options");
static cl::opt<std::string>
StokeOutputDataFilename("stoke-data",
cl::desc("<info data for stoke>"),
StokeOutputDataFilename("stoke-out",
cl::desc("output data for stoke's use"),
cl::Optional,
cl::cat(StokeOptCategory));
}
@ -18,25 +20,18 @@ StokeOutputDataFilename("stoke-data",
namespace llvm {
namespace bolt {
void dumpRegNameFromBitVec(const BitVector &RegV, const BinaryContext &BC) {
dbgs() << "\t ";
int RegIdx = RegV.find_first();
while (RegIdx != -1) {
dbgs() << RegIdx << ":" << BC.MRI->getName(RegIdx) << " ";
RegIdx = RegV.find_next(RegIdx);
}
dbgs() << "\n";
}
void getRegNameFromBitVec(const BitVector &RegV, std::set<std::string> &NameVec,
const BinaryContext &BC) {
void getRegNameFromBitVec(const BinaryContext &BC, const BitVector &RegV,
std::set<std::string> *NameVec = nullptr) {
int RegIdx = RegV.find_first();
while (RegIdx != -1) {
dbgs() << RegIdx << BC.MRI->getName(RegIdx) << "<>";
NameVec.insert(std::string(BC.MRI->getName(RegIdx)));
DEBUG(dbgs() << BC.MRI->getName(RegIdx) << " ");
if (NameVec) {
NameVec->insert(std::string(BC.MRI->getName(RegIdx)));
}
RegIdx = RegV.find_next(RegIdx);
}
dbgs() << "\n";
DEBUG(dbgs() << "\n");
}
void StokeInfo::checkInstr(const BinaryContext &BC, const BinaryFunction &BF,
@ -54,13 +49,9 @@ void StokeInfo::checkInstr(const BinaryContext &BC, const BinaryFunction &BF,
}
// skip function with exception handling yet
if (BC.MIA->isEHLabel(It) || BC.MIA->isInvoke(It) || BC.MIA->hasEHInfo(It)) {
outs() << "\t exception\n";
FuncInfo.Omitted = true;
return;
}
if (BC.MIA->hasRIPOperand(It)) {
outs() << "\t rip operand\n";
}
// check if this function contains call instruction
if (BC.MIA->isCall(It)) {
FuncInfo.HasCall = true;
@ -69,19 +60,21 @@ void StokeInfo::checkInstr(const BinaryContext &BC, const BinaryFunction &BF,
if (TargetSymbol == nullptr) {
FuncInfo.Omitted = true;
return;
} else {
outs() << "\t calling " << TargetSymbol->getName() << "\n";
}
}
// check if this function modify stack or heap
// TODO: more accurate analysis
auto IsPush = BC.MIA->isPush(It);
auto IsRipAddr = BC.MIA->hasRIPOperand(It);
if (IsPush) {
FuncInfo.StackOut = true;
}
if (BC.MIA->isStore(It) && !IsPush && !BC.MIA->hasRIPOperand(It)) {
if (BC.MIA->isStore(It) && !IsPush && !IsRipAddr) {
FuncInfo.HeapOut = true;
}
if (IsRipAddr) {
FuncInfo.HasRipAddr = true;
}
} // end of for (auto &It : ...)
} // end of for (auto *BB : ...)
@ -102,41 +95,42 @@ bool StokeInfo::analyze(const BinaryContext &BC, BinaryFunction &BF,
FuncInfo.Offset = BF.getFileOffset();
FuncInfo.Size = BF.getMaxSize();
FuncInfo.NumInstrs = BF.getNumNonPseudos();
FuncInfo.IsLoopFree = BF.isLoopFree();
FuncInfo.HotSize = BF.estimateHotSize();
FuncInfo.TotalSize = BF.estimateSize();
if (!FuncInfo.IsLoopFree) {
auto &BLI = BF.getLoopInfo();
FuncInfo.NumLoops = BLI.OuterLoops;
FuncInfo.MaxLoopDepth = BLI.MaximumDepth;
}
// early stop for large functions
if (FuncInfo.NumInstrs > 500) {
return false;
}
BinaryBasicBlock &EntryBB = BF.front();
assert(EntryBB.isEntryPoint() && "Weird, this block should be the entry block!");
FuncInfo.IsLoopFree = BF.isLoopFree();
if (!FuncInfo.IsLoopFree) {
auto &BLI = BF.getLoopInfo();
FuncInfo.NumLoops = BLI.OuterLoops;
FuncInfo.MaxLoopDepth = BLI.MaximumDepth;
}
FuncInfo.HotSize = BF.estimateHotSize();
FuncInfo.TotalSize = BF.estimateSize();
FuncInfo.Score = BF.getFunctionScore();
checkInstr(BC, BF, FuncInfo);
// register analysis
BinaryBasicBlock &EntryBB = BF.front();
assert(EntryBB.isEntryPoint() && "Weird, this should be the entry block!");
dbgs() << "\t EntryBB offset: " << EntryBB.getInputOffset() << "\n";
auto *FirstNonPseudo = EntryBB.getFirstNonPseudoInstr();
if (!FirstNonPseudo) {
return false;
}
dbgs() << "\t " << BC.InstPrinter->getOpcodeName(FirstNonPseudo->getOpcode()) << "\n";
dbgs() << "\t [DefIn at entry point]\n\t ";
DEBUG(dbgs() << "\t [DefIn]\n\t ");
auto LiveInBV = *(DInfo.getLivenessAnalysis().getStateAt(FirstNonPseudo));
LiveInBV &= DefaultDefInMask;
getRegNameFromBitVec(LiveInBV, FuncInfo.DefIn, BC);
getRegNameFromBitVec(BC, LiveInBV, &FuncInfo.DefIn);
outs() << "\t [LiveOut at return point]\n\t ";
DEBUG(dbgs() << "\t [LiveOut]\n\t ");
auto LiveOutBV = RA.getFunctionClobberList(&BF);
LiveOutBV &= DefaultLiveOutMask;
getRegNameFromBitVec(LiveOutBV, FuncInfo.LiveOut, BC);
checkInstr(BC, BF, FuncInfo);
getRegNameFromBitVec(BC, LiveOutBV, &FuncInfo.LiveOut);
outs() << " STOKE-INFO: end function \n";
return true;
@ -152,14 +146,14 @@ void StokeInfo::runOnFunctions(
if (!opts::StokeOutputDataFilename.empty()) {
Outfile.open(opts::StokeOutputDataFilename);
} else {
outs() << "STOKE-INFO: output file is required\n";
errs() << "STOKE-INFO: output file is required\n";
return;
}
// check some context meta data
outs() << "\tTarget: " << BC.TheTarget->getName() << "\n";
outs() << "\tTripleName " << BC.TripleName << "\n";
outs() << "\tgetNumRegs " << BC.MRI->getNumRegs() << "\n";
DEBUG(dbgs() << "\tTarget: " << BC.TheTarget->getName() << "\n");
DEBUG(dbgs() << "\tTripleName " << BC.TripleName << "\n");
DEBUG(dbgs() << "\tgetNumRegs " << BC.MRI->getNumRegs() << "\n");
auto CG = buildCallGraph(BC, BFs);
RegAnalysis RA(BC, BFs, CG);
@ -173,8 +167,8 @@ void StokeInfo::runOnFunctions(
BC.MIA->getDefaultDefIn(DefaultDefInMask, *BC.MRI);
BC.MIA->getDefaultLiveOut(DefaultLiveOutMask, *BC.MRI);
dumpRegNameFromBitVec(DefaultDefInMask, BC);
dumpRegNameFromBitVec(DefaultLiveOutMask, BC);
getRegNameFromBitVec(BC, DefaultDefInMask);
getRegNameFromBitVec(BC, DefaultLiveOutMask);
StokeFuncInfo FuncInfo;
// analyze all functions

View File

@ -44,11 +44,13 @@ struct StokeFuncInfo {
unsigned MaxLoopDepth;
uint64_t HotSize;
uint64_t TotalSize;
uint64_t Score;
bool HasCall;
std::set<std::string> DefIn;
std::set<std::string> LiveOut;
bool HeapOut;
bool StackOut;
bool HasRipAddr;
bool Omitted;
StokeFuncInfo() {
@ -60,7 +62,14 @@ struct StokeFuncInfo {
Offset = Size = NumInstrs = 0;
NumLoops = MaxLoopDepth = 0;
HotSize = TotalSize = 0;
IsLoopFree = HasCall = HeapOut = StackOut = Omitted = false;
Score = 0;
IsLoopFree
= HasCall
= HeapOut
= StackOut
= HasRipAddr
= Omitted
= false;
DefIn.clear();
LiveOut.clear();
}
@ -71,8 +80,11 @@ struct StokeFuncInfo {
<< "FuncName,Offset,Size,NumInstrs,"
<< "IsLoopFree,NumLoops,MaxLoopDepth,"
<< "HotSize,TotalSize,"
<< "Score,"
<< "HasCall,"
<< "DefIn,LiveOut,HeapOut,StackOut,Omitted\n";
<< "DefIn,LiveOut,HeapOut,StackOut,"
<< "HasRipAddr,"
<< "Omitted\n";
}
}
@ -82,15 +94,18 @@ struct StokeFuncInfo {
<< FuncName << "," << Offset << "," << Size << "," << NumInstrs << ","
<< IsLoopFree << "," << NumLoops << "," << MaxLoopDepth << ","
<< HotSize << "," << TotalSize << ","
<< HasCall << ",{ ";
<< Score << ","
<< HasCall << ",\"{ ";
for (auto s : DefIn) {
Outfile << s << " ";
Outfile << "%" << s << " ";
}
Outfile << "},{ ";
Outfile << "}\",\"{ ";
for (auto s : LiveOut) {
Outfile << s << " ";
}
Outfile << "}," << HeapOut << "," << StackOut << "," << Omitted << "\n";
Outfile << "}\"," << HeapOut << "," << StackOut << ","
<< HasRipAddr << ","
<< Omitted << "\n";
}
}
};