PathProfileInfo.cpp [plain text]
#define DEBUG_TYPE "path-profile-info"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/ProfileInfoTypes.h"
#include "llvm/Analysis/PathProfileInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace llvm;
static cl::opt<std::string>
PathProfileInfoFilename("path-profile-loader-file", cl::init("llvmprof.out"),
cl::value_desc("filename"),
cl::desc("Path profile file loaded by -path-profile-loader"), cl::Hidden);
namespace {
class PathProfileLoaderPass : public ModulePass, public PathProfileInfo {
public:
PathProfileLoaderPass() : ModulePass(ID) { }
~PathProfileLoaderPass();
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
}
virtual const char* getPassName() const {
return "Path Profiling Information Loader";
}
virtual void *getAdjustedAnalysisPointer(AnalysisID PI) {
if (PI == &PathProfileInfo::ID)
return (PathProfileInfo*)this;
return this;
}
bool runOnModule(Module &M);
static char ID;
private:
void buildFunctionRefs(Module &M);
void handleArgumentInfo();
void handlePathInfo();
std::vector<Function*> _functions;
FILE* _file;
std::string _filename;
};
}
char PathProfileLoaderPass::ID = 0;
INITIALIZE_ANALYSIS_GROUP(PathProfileInfo, "Path Profile Information",
NoPathProfileInfo)
INITIALIZE_AG_PASS(PathProfileLoaderPass, PathProfileInfo,
"path-profile-loader",
"Load path profile information from file",
false, true, false)
char &llvm::PathProfileLoaderPassID = PathProfileLoaderPass::ID;
ModulePass *llvm::createPathProfileLoaderPass() {
return new PathProfileLoaderPass;
}
ProfilePathEdge::ProfilePathEdge (BasicBlock* source, BasicBlock* target,
unsigned duplicateNumber)
: _source(source), _target(target), _duplicateNumber(duplicateNumber) {}
ProfilePath::ProfilePath (unsigned int number, unsigned int count,
double countStdDev, PathProfileInfo* ppi)
: _number(number) , _count(count), _countStdDev(countStdDev), _ppi(ppi) {}
double ProfilePath::getFrequency() const {
return 100 * double(_count) /
double(_ppi->_functionPathCounts[_ppi->_currentFunction]);
}
static BallLarusEdge* getNextEdge (BallLarusNode* node,
unsigned int pathNumber) {
BallLarusEdge* best = 0;
for( BLEdgeIterator next = node->succBegin(),
end = node->succEnd(); next != end; next++ ) {
if( (*next)->getType() != BallLarusEdge::BACKEDGE && (*next)->getType() != BallLarusEdge::SPLITEDGE && (*next)->getWeight() <= pathNumber && (!best || (best->getWeight() < (*next)->getWeight())) ) best = *next;
}
return best;
}
ProfilePathEdgeVector* ProfilePath::getPathEdges() const {
BallLarusNode* currentNode = _ppi->_currentDag->getRoot ();
unsigned int increment = _number;
ProfilePathEdgeVector* pev = new ProfilePathEdgeVector;
while (currentNode != _ppi->_currentDag->getExit()) {
BallLarusEdge* next = getNextEdge(currentNode, increment);
increment -= next->getWeight();
if( next->getType() != BallLarusEdge::BACKEDGE_PHONY &&
next->getType() != BallLarusEdge::SPLITEDGE_PHONY &&
next->getTarget() != _ppi->_currentDag->getExit() )
pev->push_back(ProfilePathEdge(
next->getSource()->getBlock(),
next->getTarget()->getBlock(),
next->getDuplicateNumber()));
if( next->getType() == BallLarusEdge::BACKEDGE_PHONY &&
next->getTarget() == _ppi->_currentDag->getExit() )
pev->push_back(ProfilePathEdge(
next->getRealEdge()->getSource()->getBlock(),
next->getRealEdge()->getTarget()->getBlock(),
next->getDuplicateNumber()));
if( next->getType() == BallLarusEdge::SPLITEDGE_PHONY &&
next->getSource() == _ppi->_currentDag->getRoot() )
pev->push_back(ProfilePathEdge(
next->getRealEdge()->getSource()->getBlock(),
next->getRealEdge()->getTarget()->getBlock(),
next->getDuplicateNumber()));
currentNode = next->getTarget();
}
return pev;
}
ProfilePathBlockVector* ProfilePath::getPathBlocks() const {
BallLarusNode* currentNode = _ppi->_currentDag->getRoot ();
unsigned int increment = _number;
ProfilePathBlockVector* pbv = new ProfilePathBlockVector;
while (currentNode != _ppi->_currentDag->getExit()) {
BallLarusEdge* next = getNextEdge(currentNode, increment);
increment -= next->getWeight();
if( next->getType() == BallLarusEdge::NORMAL)
pbv->push_back (currentNode->getBlock());
else if( next->getTarget() == _ppi->_currentDag->getExit() ) {
pbv->push_back (currentNode->getBlock());
pbv->push_back (next->getRealEdge()->getTarget()->getBlock());
}
currentNode = next->getTarget();
}
return pbv;
}
BasicBlock* ProfilePath::getFirstBlockInPath() const {
BallLarusNode* root = _ppi->_currentDag->getRoot();
BallLarusEdge* edge = getNextEdge(root, _number);
if( edge && (edge->getType() == BallLarusEdge::BACKEDGE_PHONY ||
edge->getType() == BallLarusEdge::SPLITEDGE_PHONY) )
return edge->getTarget()->getBlock();
return root->getBlock();
}
char llvm::PathProfileInfo::ID = 0;
PathProfileInfo::PathProfileInfo () : _currentDag(0) , _currentFunction(0) {
}
PathProfileInfo::~PathProfileInfo() {
if (_currentDag)
delete _currentDag;
}
void PathProfileInfo::setCurrentFunction(Function* F) {
if (!F) return;
if (_currentDag)
delete _currentDag;
_currentFunction = F;
_currentDag = new BallLarusDag(*F);
_currentDag->init();
_currentDag->calculatePathNumbers();
}
Function* PathProfileInfo::getCurrentFunction() const {
return _currentFunction;
}
BasicBlock* PathProfileInfo::getCurrentFunctionEntry() {
return _currentDag->getRoot()->getBlock();
}
ProfilePath* PathProfileInfo::getPath(unsigned int number) {
return _functionPaths[_currentFunction][number];
}
unsigned int PathProfileInfo::getPotentialPathCount() {
return _currentDag ? _currentDag->getNumberOfPaths() : 0;
}
ProfilePathIterator PathProfileInfo::pathBegin() {
return _functionPaths[_currentFunction].begin();
}
ProfilePathIterator PathProfileInfo::pathEnd() {
return _functionPaths[_currentFunction].end();
}
unsigned int PathProfileInfo::pathsRun() {
return _currentFunction ? _functionPaths[_currentFunction].size() : 0;
}
PathProfileLoaderPass::~PathProfileLoaderPass() {
for( FunctionPathIterator funcNext = _functionPaths.begin(),
funcEnd = _functionPaths.end(); funcNext != funcEnd; funcNext++)
for( ProfilePathIterator pathNext = funcNext->second.begin(),
pathEnd = funcNext->second.end(); pathNext != pathEnd; pathNext++)
delete pathNext->second;
}
bool PathProfileLoaderPass::runOnModule(Module &M) {
_filename = PathProfileInfoFilename;
buildFunctionRefs (M);
if (!(_file = fopen(_filename.c_str(), "rb"))) {
errs () << "error: input '" << _filename << "' file does not exist.\n";
return false;
}
ProfilingType profType;
while( fread(&profType, sizeof(ProfilingType), 1, _file) ) {
switch (profType) {
case ArgumentInfo:
handleArgumentInfo ();
break;
case PathInfo:
handlePathInfo ();
break;
default:
errs () << "error: bad path profiling file syntax, " << profType << "\n";
fclose (_file);
return false;
}
}
fclose (_file);
return true;
}
void PathProfileLoaderPass::buildFunctionRefs (Module &M) {
_functions.push_back(0);
for (Module::iterator F = M.begin(), E = M.end(); F != E; F++) {
if (F->isDeclaration())
continue;
_functions.push_back(F);
}
}
void PathProfileLoaderPass::handleArgumentInfo() {
unsigned savedArgsLength;
if( fread(&savedArgsLength, sizeof(unsigned), 1, _file) != 1 ) {
errs() << "warning: argument info header/data mismatch\n";
return;
}
char* args = new char[savedArgsLength+1];
if( fread(args, 1, savedArgsLength, _file) != savedArgsLength )
errs() << "warning: argument info header/data mismatch\n";
args[savedArgsLength] = '\0';
argList = std::string(args);
delete [] args;
if (savedArgsLength & 3)
fseek(_file, 4-(savedArgsLength&3), SEEK_CUR);
}
void PathProfileLoaderPass::handlePathInfo () {
unsigned functionCount;
if( fread(&functionCount, sizeof(functionCount), 1, _file) != 1 ) {
errs() << "warning: path info header/data mismatch\n";
return;
}
for (unsigned i = 0; i < functionCount; i++) {
PathProfileHeader pathHeader;
if( fread(&pathHeader, sizeof(pathHeader), 1, _file) != 1 ) {
errs() << "warning: bad header for path function info\n";
break;
}
Function* f = _functions[pathHeader.fnNumber];
PathProfileTableEntry* pathTable =
new PathProfileTableEntry[pathHeader.numEntries];
if( fread(pathTable, sizeof(PathProfileTableEntry),
pathHeader.numEntries, _file) != pathHeader.numEntries) {
delete [] pathTable;
errs() << "warning: path function info header/data mismatch\n";
return;
}
unsigned int totalPaths = 0;
for (unsigned int j = 0; j < pathHeader.numEntries; j++) {
totalPaths += pathTable[j].pathCounter;
_functionPaths[f][pathTable[j].pathNumber]
= new ProfilePath(pathTable[j].pathNumber, pathTable[j].pathCounter,
0, this);
}
_functionPathCounts[f] = totalPaths;
delete [] pathTable;
}
}
namespace {
struct NoPathProfileInfo : public ImmutablePass, public PathProfileInfo {
static char ID; NoPathProfileInfo() : ImmutablePass(ID) {
initializeNoPathProfileInfoPass(*PassRegistry::getPassRegistry());
}
virtual void *getAdjustedAnalysisPointer(AnalysisID PI) {
if (PI == &PathProfileInfo::ID)
return (PathProfileInfo*)this;
return this;
}
virtual const char *getPassName() const {
return "NoPathProfileInfo";
}
};
}
char NoPathProfileInfo::ID = 0;
INITIALIZE_AG_PASS(NoPathProfileInfo, PathProfileInfo, "no-path-profile",
"No Path Profile Information", false, true, true)
ImmutablePass *llvm::createNoPathProfileInfoPass() { return new NoPathProfileInfo(); }