//===- PathProfileInfo.cpp ------------------------------------*- C++ -*---===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the interface used by optimizers to load path profiles, // and provides a loader pass which reads a path profile file. // //===----------------------------------------------------------------------===// #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; // command line option for loading path profiles 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(); // this pass doesn't change anything (only loads information) virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); } // the full name of the loader pass virtual const char* getPassName() const { return "Path Profiling Information Loader"; } // required since this pass implements multiple inheritance virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { if (PI == &PathProfileInfo::ID) return (PathProfileInfo*)this; return this; } // entry point to run the pass bool runOnModule(Module &M); // pass identification static char ID; private: // make a reference table to refer to function by number void buildFunctionRefs(Module &M); // process argument info of a program from the input file void handleArgumentInfo(); // process path number information from the input file void handlePathInfo(); // array of references to the functions in the module std::vector<Function*> _functions; // path profile file handle FILE* _file; // path profile file name std::string _filename; }; } // register PathLoader 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; // link PathLoader as a pass, and make it available as an optimisation ModulePass *llvm::createPathProfileLoaderPass() { return new PathProfileLoaderPass; } // ---------------------------------------------------------------------------- // PathEdge implementation // ProfilePathEdge::ProfilePathEdge (BasicBlock* source, BasicBlock* target, unsigned duplicateNumber) : _source(source), _target(target), _duplicateNumber(duplicateNumber) {} // ---------------------------------------------------------------------------- // Path implementation // 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 && // no backedges (*next)->getType() != BallLarusEdge::SPLITEDGE && // no split edges (*next)->getWeight() <= pathNumber && // weight must be <= pathNumber (!best || (best->getWeight() < (*next)->getWeight())) ) // best one? 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())); // set the new node 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(); // add block to the block list if it is a real edge if( next->getType() == BallLarusEdge::NORMAL) pbv->push_back (currentNode->getBlock()); // make the back edge the last edge since we are at the end else if( next->getTarget() == _ppi->_currentDag->getExit() ) { pbv->push_back (currentNode->getBlock()); pbv->push_back (next->getRealEdge()->getTarget()->getBlock()); } // set the new node 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(); } // ---------------------------------------------------------------------------- // PathProfileInfo implementation // // Pass identification char llvm::PathProfileInfo::ID = 0; PathProfileInfo::PathProfileInfo () : _currentDag(0) , _currentFunction(0) { } PathProfileInfo::~PathProfileInfo() { if (_currentDag) delete _currentDag; } // set the function for which paths are currently begin processed void PathProfileInfo::setCurrentFunction(Function* F) { // Make sure it exists if (!F) return; if (_currentDag) delete _currentDag; _currentFunction = F; _currentDag = new BallLarusDag(*F); _currentDag->init(); _currentDag->calculatePathNumbers(); } // get the function for which paths are currently being processed Function* PathProfileInfo::getCurrentFunction() const { return _currentFunction; } // get the entry block of the function BasicBlock* PathProfileInfo::getCurrentFunctionEntry() { return _currentDag->getRoot()->getBlock(); } // return the path based on its number ProfilePath* PathProfileInfo::getPath(unsigned int number) { return _functionPaths[_currentFunction][number]; } // return the number of paths which a function may potentially execute unsigned int PathProfileInfo::getPotentialPathCount() { return _currentDag ? _currentDag->getNumberOfPaths() : 0; } // return an iterator for the beginning of a functions executed paths ProfilePathIterator PathProfileInfo::pathBegin() { return _functionPaths[_currentFunction].begin(); } // return an iterator for the end of a functions executed paths ProfilePathIterator PathProfileInfo::pathEnd() { return _functionPaths[_currentFunction].end(); } // returns the total number of paths run in the function unsigned int PathProfileInfo::pathsRun() { return _currentFunction ? _functionPaths[_currentFunction].size() : 0; } // ---------------------------------------------------------------------------- // PathLoader implementation // // remove all generated paths 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; } // entry point of the pass; this loads and parses a file bool PathProfileLoaderPass::runOnModule(Module &M) { // get the filename and setup the module's function references _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; } // create a reference table for functions defined in the path profile file void PathProfileLoaderPass::buildFunctionRefs (Module &M) { _functions.push_back(0); // make the 0 index a null pointer for (Module::iterator F = M.begin(), E = M.end(); F != E; F++) { if (F->isDeclaration()) continue; _functions.push_back(F); } } // handle command like argument infor in the output file void PathProfileLoaderPass::handleArgumentInfo() { // get the argument list's length unsigned savedArgsLength; if( fread(&savedArgsLength, sizeof(unsigned), 1, _file) != 1 ) { errs() << "warning: argument info header/data mismatch\n"; return; } // allocate a buffer, and get the arguments 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; // cleanup dynamic string // byte alignment if (savedArgsLength & 3) fseek(_file, 4-(savedArgsLength&3), SEEK_CUR); } // Handle path profile information in the output file void PathProfileLoaderPass::handlePathInfo () { // get the number of functions in this profile unsigned functionCount; if( fread(&functionCount, sizeof(functionCount), 1, _file) != 1 ) { errs() << "warning: path info header/data mismatch\n"; return; } // gather path information for each function 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]; // dynamically allocate a table to store path numbers 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; } // Build a new path for the current function 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; } } //===----------------------------------------------------------------------===// // NoProfile PathProfileInfo implementation // namespace { struct NoPathProfileInfo : public ImmutablePass, public PathProfileInfo { static char ID; // Class identification, replacement for typeinfo NoPathProfileInfo() : ImmutablePass(ID) { initializeNoPathProfileInfoPass(*PassRegistry::getPassRegistry()); } /// getAdjustedAnalysisPointer - This method is used when a pass implements /// an analysis interface through multiple inheritance. If needed, it /// should override this to adjust the this pointer as needed for the /// specified pass info. virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { if (PI == &PathProfileInfo::ID) return (PathProfileInfo*)this; return this; } virtual const char *getPassName() const { return "NoPathProfileInfo"; } }; } // End of anonymous namespace char NoPathProfileInfo::ID = 0; // Register this pass... INITIALIZE_AG_PASS(NoPathProfileInfo, PathProfileInfo, "no-path-profile", "No Path Profile Information", false, true, true) ImmutablePass *llvm::createNoPathProfileInfoPass() { return new NoPathProfileInfo(); }